a. 全局log等级自定义
b. 支持模块独立log等级自定义
通过链表结构,来维护不同模块的 tag名称和log等级
主要 arch_log.h, arch_log.c,list.h,有依赖编译不过,参考设计思路
arch_log.h
#ifndef _ARCH_LOG_H_
#define _ARCH_LOG_H_
#include "arch_os.h"
#include "list.h"
#define LOG_DEBUG 0
#define LOG_INFO 1
#define LOG_WARN 2
#define LOG_ERROR 3
#define LOG_LEVEL LOG_INFO
typedef struct {
list_head_t iter; /* list header */
char tag_name[30]; /* log tag name */
int tag_level; /* log tag level */
} log_list_t;
/**
* @func: LOG模块-初始化
* @return {*}
*/
void arch_log_init();
/**
* @func: 已二进制形式输出
* @parm: tag:模块标识,level:打印等级, header:打印头, data:打印数据, len:打印数据长度
* @return {*}
*/
void arch_log_print_hex(const char *tag, int level, const char *header, void *data, int len);
/**
* @func: LOG模块-设置优先级
* @parm: tag:模块标识, level:模块优先级
* @return {*}
*/
int arch_log_level_set(const char *tag, int level);
/**
* @func: LOG模块-输出
* @parm: tag:模块标识, tag_is_need:是否打印模块标识, level:模块优先级, str:打印内容
* @return {*}
*/
int arch_log_printf(const char *tag, int tag_is_need, int level, const char *str, ...);
#define ESP_LOGD(tag, str, ...) arch_log_printf(tag, 1, LOG_DEBUG, str"\n", ##__VA_ARGS__)
#define ESP_LOGI(tag, str, ...) arch_log_printf(tag, 1, LOG_INFO, str"\n", ##__VA_ARGS__)
#define ESP_LOGW(tag, str, ...) arch_log_printf(tag, 1, LOG_WARN, str"\n", ##__VA_ARGS__)
#define ESP_LOGE(tag, str, ...) arch_log_printf(tag, 1, LOG_ERROR, str"\n", ##__VA_ARGS__)
#define ESP_LOGD1(tag, str, ...) arch_log_printf(tag, 0, LOG_DEBUG, str, ##__VA_ARGS__)
#define ESP_LOGI1(tag, str, ...) arch_log_printf(tag, 0, LOG_INFO, str, ##__VA_ARGS__)
#define ESP_LOGW1(tag, str, ...) arch_log_printf(tag, 0, LOG_WARN, str, ##__VA_ARGS__)
#define ESP_LOGE1(tag, str, ...) arch_log_printf(tag, 0, LOG_ERROR, str, ##__VA_ARGS__)
#define ESP_LOGD_HEX(tag, header, str, ...) arch_log_print_hex(tag, LOG_DEBUG, header, str, ##__VA_ARGS__);
#define ESP_LOGI_HEX(tag, header, str, ...) arch_log_print_hex(tag, LOG_INFO, header, str, ##__VA_ARGS__);
#define ESP_LOGW_HEX(tag, header, str, ...) arch_log_print_hex(tag, LOG_WARN, header, str, ##__VA_ARGS__);
#define ESP_LOGE_HEX(tag, header, str, ...) arch_log_print_hex(tag, LOG_ERROR, header, str, ##__VA_ARGS__);
#endif //_ARCH_LOG_H_
arch_log.c
#include "arch_log.h"
#include "list.h"
static int log_level = 0;
static list_head_t list_tag = {0};
void arch_log_print_hex(const char* tag, int level, const char *header, void *data, int len)
{
switch(level) {
case LOG_DEBUG: {
if(header != NULL) {
ESP_LOGD1(tag, "%s\n", header);
}
for (int i = 0; i < len; i++) {
ESP_LOGD1(tag, "0x%02x, ", *(unsigned char *)(data + i));
}
ESP_LOGD1(tag, "\n");
break;
}
case LOG_INFO: {
if(header != NULL) {
ESP_LOGI1(tag, "%s\n", header);
}
for (int i = 0; i < len; i++) {
ESP_LOGI1(tag, "0x%02x, ", *(unsigned char *)(data + i));
}
ESP_LOGI1(tag, "\n");
break;
}
case LOG_WARN: {
if(header != NULL) {
ESP_LOGW1(tag, "%s\n", header);
}
for (int i = 0; i < len; i++) {
ESP_LOGW1(tag, "0x%02x, ", *(unsigned char *)(data + i));
}
ESP_LOGW1(tag, "\n");
break;
}
case LOG_ERROR: {
if(header != NULL) {
ESP_LOGE1(tag, "%s\n", header);
}
for (int i = 0; i < len; i++) {
ESP_LOGE1(tag, "0x%02x, ", *(unsigned char *)(data + i));
}
ESP_LOGE1(tag, "\n");
break;
}
default:
break;
}
}
void arch_log_init()
{
printf("lyh add -> enter control init\n");
INIT_LIST_HEAD(&list_tag);
arch_log_level_set("all", LOG_LEVEL);
}
int arch_log_level_set(const char *tag, int level)
{
log_list_t *node = NULL;
/* set all the log tag level */
if(strncmp("all", tag, strlen(tag)) == 0) {
log_level = level;
/* reset all the log list */
list_for_each_entry(node, &list_tag, iter, log_list_t) {
node->tag_level = level;
}
return 0;
}
/* set log tag in tag list */
list_for_each_entry(node, &list_tag, iter, log_list_t)
{
// printf("lyh add -> tag_name = %s\n", node->tag_name);
if (strncmp(node->tag_name, tag, strlen(tag)) == 0) {
printf("lyh add -> tag is already save, rewrite level = %d\n", level);
node->tag_level = level;
return 0;
}
}
printf("lyh add -> tag is not save, create new node!\n");
/* create the new tag to tag list */
log_list_t *log_tag = calloc(1, sizeof(log_list_t));
if(log_tag == NULL) {
printf("lyh add -> log_tag calloc failed\n");
return -1;
}
log_tag->tag_level = level;
memcpy(log_tag->tag_name, tag, strlen(tag));
list_add_tail(&log_tag->iter, &list_tag);
return 0;
}
int arch_log_printf(const char *tag, int tag_is_need, int level, const char *str, ...)
{
int tag_is_print = 0;
int tag_is_save = 0;
log_list_t *node = NULL;
/* judging the printing level from the tag list */
list_for_each_entry(node, &list_tag, iter, log_list_t)
{
if (strncmp(node->tag_name, tag, strlen(tag)) == 0) {
if (level >= node->tag_level) {
tag_is_print = 1;
}
tag_is_save = 1;
break;
}
}
/* judging the printing level */
if (level >= log_level && tag_is_save == 0) {
tag_is_print = 1;
}
/* print log */
if(tag_is_print) {
char customer_buf[512] = {0};
va_list ap;
uint32_t tag_len = 0;
if (tag_is_need) {
tag_len = strlen(tag) + strlen(": ");
if ((tag_len > 0) && (tag_len < 64)) {
snprintf(customer_buf, sizeof(customer_buf), "%s%s", tag, ": ");
}
}
va_start(ap, str);
int len = vsnprintf(customer_buf + tag_len, sizeof(customer_buf) - tag_len, str, ap);
va_end(ap);
hal_trace_output((unsigned char *)customer_buf, len + tag_len + 1);
}
return 0;
}
list.h
#ifndef __LIST_H__
#define __LIST_H__
#if defined ( __CC_ARM )
#ifndef inline
#define inline __inline
#endif
#endif
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
typedef struct list_head {
struct list_head *next, *prev;
}list_head_t;
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add(struct list_head *nw,
struct list_head *prev,
struct list_head *next)
{
next->prev = nw;
nw->next = next;
nw->prev = prev;
prev->next = nw;
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void list_add(struct list_head *nw, struct list_head *head)
{
__list_add(nw, head, head->next);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *nw, struct list_head *head)
{
__list_add(nw, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is in an undefined state.
*/
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = (void *) 0;
entry->prev = (void *) 0;
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
/**
* list_move - delete from one list and add as another's head
* @list: the entry to move
* @head: the head that will precede our entry
*/
static inline void list_move(struct list_head *list, struct list_head *head)
{
__list_del(list->prev, list->next);
list_add(list, head);
}
/**
* list_move_tail - delete from one list and add as another's tail
* @list: the entry to move
* @head: the head that will follow our entry
*/
static inline void list_move_tail(struct list_head *list,
struct list_head *head)
{
__list_del(list->prev, list->next);
list_add_tail(list, head);
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static inline int list_empty(struct list_head *head)
{
return head->next == head;
}
static inline void __list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
/**
* list_splice - join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static inline void list_splice(struct list_head *list, struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head);
}
/**
* list_splice_init - join two lists and reinitialise the emptied list.
* @list: the new list to add.
* @head: the place to add it in the first list.
*
* The list at @list is reinitialised
*/
static inline void list_splice_init(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list)) {
__list_splice(list, head);
INIT_LIST_HEAD(list);
}
}
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/**
* list_first_entry - get the first element from a list
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*
* Note, that list is expected to be not empty.
*/
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
#define list_last_entry(ptr, type, field) \
list_entry((ptr)->prev, type, field)
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); \
pos = pos->next)
/**
* list_for_each_prev - iterate over a list backwards
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each_prev(pos, head) \
for (pos = (head)->prev; pos != (head); \
pos = pos->prev)
/**
* list_for_each_safe - iterate over a list safe against removal of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member, type) \
for (pos = list_entry((head)->next, type, member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, type, member))
/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop counter.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member, type) \
for (pos = list_entry((head)->next, type, member), \
n = list_entry(pos->member.next, type, member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, type, member))
#endif