ULOG
- 标准输出
- 过滤功能
- 异步输出
- 颜色功能
- 后端支持
标准输出
初始化
1 2 3 4 5 6 7 8 9 10 11 12 13
| intulog_init(void)
{
rt_mutex_init(&ulog.output_locker, "ulog", RT_IPC_FLAG_PRIO);
ulog.output_lock_enabled = RT_TRUE;
return0;
}
|
ulog_output
- 根据当前是否在中断中,判断使用的缓冲区
- 上锁(线程环境互斥量,中断环境关闭中断,未初始化互斥量时使用
ulog_voutput_recursion
)
3.ulog_voutput_recursion
递归输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
if ((ulog_voutput_recursion == RT_TRUE) && (hex_buf == RT_NULL))
{
rt_kprintf(format, args);
if (newline == RT_TRUE)
{
rt_kprintf(ULOG_NEWLINE_SIGN);
}
output_unlock();
return;
}
|
- ulog_formater 执行格式化
- do_output 输出
1.ulog_head_formater
格式化插入头部信息
2.ulog_tail_formater
格式化插入尾部信息
do_output
- 线程环境,使用后端输出方式
- 中断环境,仅使用控制台输出方式
我们不能确保所有后端都支持 ISR 上下文输出。因此仅当上下文为 ISR 时才使用 rt_kprintf
后端支持
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| struct ulog_backend
{
charname[RT_NAME_MAX];
rt_bool_t support_color;
rt_uint32_t out_level;
void (*init) (struct ulog_backend *backend);
void (*output)(struct ulog_backend *backend, rt_uint32_t level, constchar *tag, rt_bool_t is_raw, constchar *log, rt_size_t len);
void (*flush) (struct ulog_backend *backend);
void (*deinit)(struct ulog_backend *backend);
rt_bool_t (*filter)(struct ulog_backend *backend, rt_uint32_t level, constchar *tag, rt_bool_t is_raw, constchar *log, rt_size_t len);
rt_slist_t list;
};
|
- 初始化后端链表
1 2 3
| rt_slist_init(&ulog.backend_list);
|
2 注册后端,将注册后端节点插入到ULOG链表中
1 2 3
| rt_slist_append(&ulog.backend_list, &backend->list);
|
- 卸载后端,将注册后端节点从ULOG链表中移除
- ulog_output_to_all_backend
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| staticvoidulog_output_to_all_backend(rt_uint32_tlevel, constchar *tag, rt_bool_tis_raw, constchar *log, rt_size_tlen)
{
if (!rt_slist_first(&ulog.backend_list))
{
rt_kputs(log);
return;
}
for (node = rt_slist_first(&ulog.backend_list); node; node = rt_slist_next(node))
{
backend = rt_slist_entry(node, struct ulog_backend, list);
if (backend->out_level < level)
{
continue;
}
if (backend->filter && backend->filter(backend, level, tag, is_raw, log, len) == RT_FALSE)
{
continue;
}
if (backend->support_color || is_raw)
{
backend->output(backend, level, tag, is_raw, log, len);
}
else
{
rt_size_t color_info_len = 0, output_len = len;
constchar *output_log = log;
if (color_output_info[level] != RT_NULL)
color_info_len = rt_strlen(color_output_info[level]);
if (color_info_len)
{
rt_size_t color_hdr_len = rt_strlen(CSI_START) + color_info_len;
output_log += color_hdr_len;
output_len -= (color_hdr_len + (sizeof(CSI_END) - 1));
}
backend->output(backend, level, tag, is_raw, output_log, output_len);
}
}
}
|
过滤功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| struct
{
rt_slist_t tag_lvl_list;
rt_uint32_t level;
chartag[ULOG_FILTER_TAG_MAX_LEN + 1];
charkeyword[ULOG_FILTER_KW_MAX_LEN + 1];
} filter;
|
- 初始化链表
- ulog_tag_lvl_filter_set
异步输出
1 2 3 4 5 6 7 8 9 10 11 12 13
| rt_bool_t async_enabled;
rt_rbb_t async_rbb;
struct rt_ringbuffer *async_rb;
rt_thread_t async_th;
struct rt_semaphore async_notice;
|
- 初始化
1 2 3 4 5 6 7
|
ulog.async_rbb = rt_rbb_create(RT_ALIGN(ULOG_ASYNC_OUTPUT_BUF_SIZE, RT_ALIGN_SIZE), ULOG_ASYNC_OUTPUT_STORE_LINES);
rt_sem_init(&ulog.async_notice, "ulog", 0, RT_IPC_FLAG_FIFO);
|
- 日志输入
1 2 3 4 5 6 7 8 9
|
rt_ringbuffer_put(ulog.async_rb, (constrt_uint8_t *)log_buf, (rt_uint16_t)log_buf_size - 1);
rt_sem_release(&ulog.async_notice);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| struct ulog_frame
{
rt_uint32_t magic:8;
rt_uint32_t is_raw:1;
rt_uint32_t log_len:23;
rt_uint32_t level;
constchar *log;
constchar *tag;
};
log_blk = rt_rbb_blk_alloc(ulog.async_rbb, RT_ALIGN(sizeof(struct ulog_frame) + log_buf_size, RT_ALIGN_SIZE));
if (log_blk)
{
log_frame = (ulog_frame_t) log_blk->buf;
log_frame->magic = ULOG_FRAME_MAGIC;
log_frame->is_raw = is_raw;
log_frame->level = level;
log_frame->log_len = log_len;
log_frame->tag = tag;
log_frame->log = (constchar *)log_blk->buf + sizeof(struct ulog_frame);
rt_strncpy((char *)(log_blk->buf + sizeof(struct ulog_frame)), log_buf, log_buf_size);
rt_rbb_blk_put(log_blk);
rt_sem_release(&ulog.async_notice);
}
|
- 异步输出线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
| rt_err_tulog_async_waiting_log(rt_int32_ttime)
{
rt_sem_control(&ulog.async_notice, RT_IPC_CMD_RESET, RT_NULL);
returnrt_sem_take(&ulog.async_notice, time);
}
voidulog_async_output(void)
{
rt_rbb_blk_t log_blk;
ulog_frame_t log_frame;
while ((log_blk = rt_rbb_blk_get(ulog.async_rbb)) != RT_NULL)
{
log_frame = (ulog_frame_t) log_blk->buf;
if (log_frame->magic == ULOG_FRAME_MAGIC)
{
ulog_output_to_all_backend(log_frame->level, log_frame->tag, log_frame->is_raw, log_frame->log,
log_frame->log_len);
}
rt_rbb_blk_free(ulog.async_rbb, log_blk);
}
if (ulog.async_rb)
{
rt_size_t log_len = rt_ringbuffer_data_len(ulog.async_rb);
char *log = rt_malloc(log_len + 1);
if (log)
{
rt_size_t len = rt_ringbuffer_get(ulog.async_rb, (rt_uint8_t *)log, (rt_uint16_t)log_len);
log[log_len] = '\0';
ulog_output_to_all_backend(LOG_LVL_DBG, "", RT_TRUE, log, len);
rt_free(log);
}
}
}
staticvoidasync_output_thread_entry(void *param)
{
ulog_async_output();
while (1)
{
ulog_async_waiting_log(RT_WAITING_FOREVER);
while (1)
{
ulog_async_output();
if (ulog_async_waiting_log(RT_TICK_PER_SECOND * 2) == RT_EOK)
{
continue;
}
else
{
ulog_flush();
break;
}
}
}
}
|
文件后端
- ulog_file_backend_output_with_buf
- 拷贝到缓冲区中,缓冲区未满保留;
- 直到缓冲区满了执行flush操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| while (len)
{
free_len = buf_ptr_end - be->buf_ptr_now;
if (len > free_len)
{
copy_len = free_len;
}
else
{
copy_len = len;
}
rt_memcpy(be->buf_ptr_now, log, copy_len);
be->buf_ptr_now += copy_len;
len -= copy_len;
log += copy_len;
RT_ASSERT(be->buf_ptr_now <= buf_ptr_end);
if (buf_ptr_end == be->buf_ptr_now)
{
ulog_file_backend_flush_with_buf(backend);
if (buf_ptr_end == be->buf_ptr_now)
{
break;
}
}
}
|
- ulog_file_backend_flush_with_buf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| staticvoidulog_file_backend_flush_with_buf(struct ulog_backend *backend)
{
struct ulog_file_be *be = (struct ulog_file_be *) backend;
rt_size_t file_size = 0, write_size = 0;
if (be->enable == RT_FALSE || be->buf_ptr_now == be->file_buf)
{
return;
}
if (be->cur_log_file_fd < 0)
{
if (access(be->cur_log_dir_path, F_OK) < 0)
{
mkdir(be->cur_log_dir_path, 0);
}
rt_snprintf(be->cur_log_file_path, ULOG_FILE_PATH_LEN, "%s/%s.log", be->cur_log_dir_path, be->parent.name);
be->cur_log_file_fd = open(be->cur_log_file_path, O_CREAT | O_RDWR | O_APPEND);
if (be->cur_log_file_fd < 0)
{
rt_kprintf("ulog file(%s) open failed.", be->cur_log_file_path);
return;
}
}
file_size = lseek(be->cur_log_file_fd, 0, SEEK_END);
if (file_size >= (be->file_max_size - be->buf_size * 2))
{
if (!ulog_file_rotate(be))
{
return;
}
}
write_size = (rt_size_t)(be->buf_ptr_now - be->file_buf);
if (write(be->cur_log_file_fd, be->file_buf, write_size) != write_size)
{
return;
}
fsync(be->cur_log_file_fd);
be->buf_ptr_now = be->file_buf;
}
|
- ulog_file_rotate