XFusion API v1.3.0
载入中...
搜索中...
未找到
xf_log.c
浏览该文件的文档.
1
12/* ==================== [Includes] ========================================== */
13
14#include "xf_log.h"
15#include <stdarg.h>
16
17/* ==================== [Defines] =========================================== */
18
19#define PL_CSI_START "\033["
20#define PL_CSI_END "\033[0m"
21
22#if XF_LOG_CTYPE_IS_ENABLE
23#include <ctype.h>
24#else
25#define isdigit(c) ((c) >= '0' && (c) <= '9')
26#endif
27
28#if XF_LOG_STRLEN_IS_ENABLE
29#include <string.h>
30#define xf_log_strlen(s) strlen(s)
31#endif
32
33#if XF_LOG_VSNPRINTF_IS_ENABLE
34#include <stdio.h>
35#define xf_log_vsprintf(buffer, maxlen, fmt, args) vsnprintf(buffer, maxlen, fmt, args)
36#endif
37
38/* ==================== [Typedefs] ========================================== */
39
53
54#if XF_LOG_FILTER_IS_ENABLE
55
56typedef struct _xf_log_filter_t {
57 uint8_t enable;
58 uint8_t b_or_w; // 黑白名单,0表示黑名单表示加入后不会被输出,1表示白名单表示加入后会被输出
59 uint8_t level;
60 uint8_t is_colorful;
61 const char *tag;
62 const char *file;
64
65#endif
66
67typedef struct _xf_log_obj_t {
68 uint8_t info_level;
70 void *user_args;
71
72#if XF_LOG_FILTER_IS_ENABLE
73
75
76#endif
77
79
80/* ==================== [Static Prototypes] ================================= */
81
82static size_t xf_log_vprintf(xf_log_out_t log_out, void *arg, const char *format, va_list va);
83static size_t xf_log_color_format(int log_obj_id, uint8_t level, const char *tag, const char *file, uint32_t line,
84 const char *func, const char *fmt, va_list va);
85
86/* ==================== [Static Variables] ================================== */
87
88static const char s_lvl_to_prompt[] = {
89 '\0',
90 'U',
91 'E',
92 'W',
93 'I',
94 'D',
95 'V',
96};
97
98#if XF_LOG_COLORS_IS_ENABLE
108#endif
109
111
113
114/* ==================== [Macros] ============================================ */
115
116/* ==================== [Global Functions] ================================== */
117
118int xf_log_register_obj(xf_log_out_t out_func, void *user_args)
119{
120 for (size_t i = 0; i < XF_LOG_OBJ_NUM; i++) {
121 if (s_log_obj[i].out_func != NULL) {
122 continue;
123 }
124 s_log_obj[i].out_func = out_func;
125 s_log_obj[i].user_args = user_args;
126 s_log_obj[i].info_level = XF_LOG_LVL_ERROR; // 当log等级大于等于XF_LOG_LVL_ERROR时才会输出相关信息
127
128#if XF_LOG_FILTER_IS_ENABLE
129
130 s_log_obj[i].filter.enable = 0; // 不开启过滤器
131 s_log_obj[i].filter.b_or_w = 0; // 默认黑名单
132 s_log_obj[i].filter.level = XF_LOG_LVL_VERBOSE; // 不对等级做任何屏蔽
133 s_log_obj[i].filter.is_colorful = 1; // 不对颜色做任何屏蔽
134 s_log_obj[i].filter.tag = NULL; // 不对 tag 进行任何屏蔽
135 s_log_obj[i].filter.file = NULL; // 不对 file 进行任何屏蔽
136
137#endif
138 return i;
139 }
140
141 return -1;
142}
143
144#if XF_LOG_FILTER_IS_ENABLE
145
146void xf_log_set_filter_enable(int log_obj_id)
147{
148 s_log_obj[log_obj_id].filter.enable = 1;
149}
150
151void xf_log_set_filter_disable(int log_obj_id)
152{
153 s_log_obj[log_obj_id].filter.enable = 0;
154}
155
157{
158 s_log_obj[log_obj_id].filter.is_colorful = 1;
159}
160
162{
163 s_log_obj[log_obj_id].filter.is_colorful = 0;
164}
165
167{
168 s_log_obj[log_obj_id].filter.b_or_w = 0;
169}
170
172{
173 s_log_obj[log_obj_id].filter.b_or_w = 1;
174}
175
176void xf_log_set_filter_tag(int log_obj_id, const char *tag)
177{
178 s_log_obj[log_obj_id].filter.tag = tag;
179}
180
181void xf_log_set_filter_level(int log_obj_id, uint8_t level)
182{
183 s_log_obj[log_obj_id].filter.level = level;
184}
185
186void xf_log_set_filter_file(int log_obj_id, const char *file)
187{
188 s_log_obj[log_obj_id].filter.file = file;
189}
190
191#endif
192
193void xf_log_set_info_level(int log_obj_id, uint8_t level)
194{
195 s_log_obj[log_obj_id].info_level = level;
196}
197
199{
200 s_log_time_func = log_time_func;
201}
202
203size_t xf_log(uint8_t level, const char *tag, const char *file, uint32_t line, const char *func, const char *fmt, ...)
204{
205 size_t len = 0;
206 // 根据不同的订阅进行不同的输出
207 va_list args;
208 va_start(args, fmt);
209 for (size_t i = 0; i < XF_LOG_OBJ_NUM; i++) {
210 if (s_log_obj[i].out_func == NULL) {
211 continue;
212 }
213#if XF_LOG_FILTER_IS_ENABLE
214 // 根据屏蔽等级判断后续是否执行
215 xf_log_filter_t filter = s_log_obj[i].filter;
216 if (filter.enable) {
217 if (filter.b_or_w == 0) {
218 if (filter.level < level) {
219 continue;
220 } else if (filter.tag != NULL && filter.tag == tag) {
221 continue;
222 } else if (filter.file != NULL && filter.file == file) {
223 continue;
224 }
225
226 } else if (filter.b_or_w == 1) {
227 if (filter.level < level) {
228 continue;
229 } else if (filter.tag != NULL && filter.tag != tag) {
230 continue;
231 } else if (filter.file != NULL && filter.file != file) {
232 continue;
233 }
234 }
235 }
236#endif
237 len = xf_log_color_format(i, level, tag, file, line, func, fmt, args);
238 }
239 va_end(args);
240
241 return len;
242}
243
244size_t xf_log_printf(const char *format, ...)
245{
246 size_t len = 0;
247 va_list args;
248 va_start(args, format);
249 for (size_t i = 0; i < XF_LOG_OBJ_NUM; i++) {
250 if (s_log_obj[i].out_func == NULL) {
251 continue;
252 }
253 len = xf_log_vprintf(s_log_obj[i].out_func, s_log_obj[i].user_args, format, args);
254 }
255 va_end(args);
256
257 return len;
258}
259
260/* ==================== [Static Functions] ================================== */
261
262static void find_args_from_index(va_list *va, size_t index)
263{
264 for (int i = 0; i < index; i++) {
265 va_arg(*va, void *);
266 }
267}
268
269static size_t xf_log_vprintf(xf_log_out_t log_out, void *arg, const char *format, va_list va)
270{
271 const char *p = format;
272 char format_flag[XF_FORMAT_FLAG_SIZE]; // 用于格式化部分的缓冲区
273 char format_buffer[XF_FORMAT_BUFFER_SIZE]; // 用于格式化结果的缓冲区
274 size_t total_length = 0;
275 size_t index = 0, used_index = 0;
276 va_list args_copy;
277
278 while (*p != '\0') {
279 // 普通字符处理,直接输出到串口
280 if (*p != '%') {
281 const char *start = p;
282 while (*p != '%' && *p != '\0') {
283 p++; // 找到下一个 '%' 或者字符串末尾
284 }
285 total_length += p - start;
286 log_out(start, p - start, arg); // 输出普通文本部分
287 } else {
288 p++; // 移动到 % 后面的字符
289 char *format_start = format_flag; // 记录 % 开始的地方
290 *format_start = '%';
291 format_start++;
292 used_index = 0;
293
294 // 优化一些特殊情况
295 if (*p == '%') {
296 p++;
297 total_length++;
298 log_out("%", 1, arg);
299 continue;
300 } else if (*p == 's') {
301 p++;
302 va_copy(args_copy, va);
303 find_args_from_index(&args_copy, index);
304 const char *start = va_arg(args_copy, const char *);
305 index++;
306 va_end(args_copy);
307 total_length += xf_log_strlen(start);
308 log_out(start, xf_log_strlen(start), arg);
309 continue;
310 }
311
312 // 收录格式控制符
313 switch (*p) {
314 case '-':
315 case '+':
316 case ' ':
317 case '#':
318 case '0':
319 if ((format_start - format_flag) < XF_FORMAT_FLAG_SIZE - 1) {
320 *format_start++ = *p++;
321 }
322 break;
323
324 default:
325 break;
326 }
327 // 收录宽度信息
328 if (*p == '*') {
329 used_index++;
330 if ((format_start - format_flag) < XF_FORMAT_FLAG_SIZE - 1) {
331 *format_start++ = *p++;
332 }
333 } else {
334 while (isdigit((int)(*p))) {
335 if ((format_start - format_flag) < XF_FORMAT_FLAG_SIZE - 1) {
336 *format_start++ = *p++;
337 }
338 }
339 }
340
341 // 收录位置信息
342 if (*p == '.') {
343 if ((format_start - format_flag) < XF_FORMAT_FLAG_SIZE - 1) {
344 *format_start++ = *p++;
345 }
346 if (*p == '*') {
347 used_index++;
348 if ((format_start - format_flag) < XF_FORMAT_FLAG_SIZE - 1) {
349 *format_start++ = *p++;
350 }
351 } else {
352 while (isdigit((int)(*p))) {
353 if ((format_start - format_flag) < XF_FORMAT_FLAG_SIZE - 1) {
354 *format_start++ = *p++;
355 }
356 }
357 }
358 }
359 // 收录长度
360 switch (*p) {
361 case 'h':
362 case 'l':
363 case 'j':
364 case 'z':
365 case 't': {
366 if ((format_start - format_flag) < XF_FORMAT_FLAG_SIZE - 1) {
367 *format_start++ = *p++;
368 }
369 switch (*p) {
370 case 'h':
371 case 'l':
372 if ((format_start - format_flag) < XF_FORMAT_FLAG_SIZE - 1) {
373 *format_start++ = *p++;
374 }
375 break;
376
377 default:
378 break;
379 }
380 }
381 break;
382
383 default:
384 break;
385 }
386 // 收录类型转换符
387 switch (*p) {
388 case 'E':
389 case 'F':
390 case 'G':
391 case 'X':
392 case 'b':
393 case 'c':
394 case 'd':
395 case 'e':
396 case 'f':
397 case 'g':
398 case 'i':
399 case 'o':
400 case 'p':
401 case 's':
402 case 't':
403 case 'u':
404 case 'x':
405 used_index++;
406 if ((format_start - format_flag) < XF_FORMAT_FLAG_SIZE - 1) {
407 *format_start++ = *p++;
408 }
409 break;
410
411 default:
412 break;
413 }
414
415 *format_start = '\0'; // 结束符
416 // 格式化字符串并输出;
417 va_copy(args_copy, va);
418 find_args_from_index(&args_copy, index);
419 // 获取完整格式化的长度
420 int formatted_len = xf_log_vsprintf(format_buffer, XF_FORMAT_BUFFER_SIZE, format_flag, args_copy);
421 va_end(args_copy);
422 if (formatted_len < XF_FORMAT_BUFFER_SIZE) {
423 log_out(format_buffer, formatted_len, arg);
424 total_length += formatted_len;
425 } else {
426 int total_written = 0;
427 while (total_written < formatted_len) {
428 int remaining = formatted_len - total_written;
429 int chunk_size = remaining < XF_FORMAT_BUFFER_SIZE ? remaining : XF_FORMAT_BUFFER_SIZE - 1;
430 va_copy(args_copy, va);
431 find_args_from_index(&args_copy, index);
432 xf_log_vsprintf(format_buffer, chunk_size + 1, format_flag, args_copy); // 输出分块格式化内容
433 va_end(args_copy);
434 log_out(format_buffer, chunk_size, arg);
435 total_written += chunk_size;
436 }
437 total_length += total_written;
438 }
439 index += used_index;
440 }
441 }
442
443 return total_length;
444}
445
446static size_t xf_log_printf_out(xf_log_out_t log_out, void *arg, const char *format, ...)
447{
448 va_list va;
449 va_start(va, format);
450 size_t len = xf_log_vprintf(log_out, arg, format, va);
451 va_end(va);
452
453 return len;
454}
455
456static size_t xf_log_color_format(int log_obj_id, uint8_t level, const char *tag, const char *file, uint32_t line,
457 const char *func, const char *fmt, va_list va)
458{
459 size_t len = 0;
460 xf_log_out_t out_func = s_log_obj[log_obj_id].out_func;
461 void *user_args = s_log_obj[log_obj_id].user_args;
462
463#if XF_LOG_COLORS_IS_ENABLE
464#if XF_LOG_FILTER_IS_ENABLE
465 if (!s_log_obj[log_obj_id].filter.enable || (s_log_obj[log_obj_id].filter.enable
466 && s_log_obj[log_obj_id].filter.is_colorful)) {
467#endif
468 if (s_lvl_to_color[level] != XF_LOG_COLOR_NULL) {
469 /* \033[0;3%cm: 重置样式并设置前景色 */
470 len += xf_log_printf_out(out_func, user_args, PL_CSI_START "0;3" "%cm", s_lvl_to_color[level]);
471 }
472#if XF_LOG_FILTER_IS_ENABLE
473 }
474#endif
475#endif
476
477 // 添加时间戳打印
478 if (s_log_time_func) {
479 len += xf_log_printf_out(out_func, user_args, "%c (%lu)-%s", s_lvl_to_prompt[level], s_log_time_func(), tag);
480 } else {
481 len += xf_log_printf_out(out_func, user_args, "%c %s", s_lvl_to_prompt[level], tag);
482 }
483
484 // 打印信息
485 if (level <= s_log_obj[log_obj_id].info_level) {
486 len += xf_log_printf_out(out_func, user_args, "[%s:%lu(%s)]", file, line, func);
487 }
488
489 // 用户日志打印
490 len += xf_log_printf_out(out_func, user_args, ": ");
491 len += xf_log_vprintf(out_func, user_args, fmt, va);
492
493#if XF_LOG_COLORS_IS_ENABLE
494#if XF_LOG_FILTER_IS_ENABLE
495 if (!s_log_obj[log_obj_id].filter.enable || (s_log_obj[log_obj_id].filter.enable
496 && s_log_obj[log_obj_id].filter.is_colorful)) {
497#endif
498 /* 清除 CSI 格式 */
499 if (s_lvl_to_color[level] != XF_LOG_COLOR_NULL) {
500 len += xf_log_printf_out(out_func, user_args, PL_CSI_END);
501 }
502#if XF_LOG_FILTER_IS_ENABLE
503 }
504#endif
505#endif
506 return len;
507}
void xf_log_set_filter_enable(int log_obj_id)
启用过滤器
Definition xf_log.c:146
void xf_log_set_time_func(xf_log_time_func_t log_time_func)
设置log的时间戳打印函数
Definition xf_log.c:198
void xf_log_set_filter_disable(int log_obj_id)
禁用过滤器
Definition xf_log.c:151
size_t xf_log(uint8_t level, const char *tag, const char *file, uint32_t line, const char *func, const char *fmt,...)
log打印函数
Definition xf_log.c:203
void xf_log_set_filter_file(int log_obj_id, const char *file)
设置过滤器的文件过滤
Definition xf_log.c:186
void xf_log_set_info_level(int log_obj_id, uint8_t level)
显示文件函数等信息的最小等级
Definition xf_log.c:193
void xf_log_set_filter_is_whitelist(int log_obj_id)
设置过滤器为白名单(仅其内容将被暴露)
Definition xf_log.c:171
void xf_log_set_filter_level(int log_obj_id, uint8_t level)
设置过滤器的等级过滤
Definition xf_log.c:181
void xf_log_set_filter_colorful_disable(int log_obj_id)
关闭彩色显示
Definition xf_log.c:161
void xf_log_set_filter_tag(int log_obj_id, const char *tag)
设置过滤器的标签过滤
Definition xf_log.c:176
void xf_log_set_filter_colorful_enable(int log_obj_id)
开启彩色显示
Definition xf_log.c:156
void xf_log_set_filter_is_blacklist(int log_obj_id)
设置过滤器为黑名单(其内容将被过滤)
Definition xf_log.c:166
#define XF_LOG_LVL_VERBOSE
Definition xf_log.h:69
#define XF_LOG_LVL_ERROR
Definition xf_log.h:65
uint8_t enable
Definition xf_log.c:57
uint8_t b_or_w
Definition xf_log.c:58
const char * tag
Definition xf_log.c:61
uint8_t level
Definition xf_log.c:59
uint8_t is_colorful
Definition xf_log.c:60
const char * file
Definition xf_log.c:62
xf_log_out_t out_func
Definition xf_log.c:69
uint8_t info_level
Definition xf_log.c:68
xf_log_filter_t filter
Definition xf_log.c:74
void * user_args
Definition xf_log.c:70
static block_link_t start
闲内存块链表的起点和终点。 用户在注册的时候末尾 next_free_block 为 (void*) 0,block_size 为 0
Definition xf_alloc.c:54
#define XF_LOG_OBJ_NUM
xf_log 系统日志。
void(* xf_log_out_t)(const char *str, size_t len, void *arg)
log 输出后端原型。
Definition xf_log.h:92
uint32_t(* xf_log_time_func_t)(void)
log 时间戳原型。
Definition xf_log.h:99
enum _xf_log_color_t xf_log_color_t
static const char s_lvl_to_prompt[]
Definition xf_log.c:88
#define PL_CSI_END
Definition xf_log.c:20
#define xf_log_strlen(s)
Definition xf_log.c:30
static size_t xf_log_vprintf(xf_log_out_t log_out, void *arg, const char *format, va_list va)
Definition xf_log.c:269
_xf_log_color_t
Definition xf_log.c:40
@ XF_LOG_COLOR_MAGENTA
Definition xf_log.c:47
@ XF_LOG_COLOR_BLACK
Definition xf_log.c:42
@ XF_LOG_COLOR_WHITE
Definition xf_log.c:49
@ XF_LOG_COLOR_MAX
Definition xf_log.c:51
@ XF_LOG_COLOR_BLUE
Definition xf_log.c:46
@ XF_LOG_COLOR_NULL
Definition xf_log.c:41
@ XF_LOG_COLOR_RED
Definition xf_log.c:43
@ XF_LOG_COLOR_GREEN
Definition xf_log.c:44
@ XF_LOG_COLOR_YELLOW
Definition xf_log.c:45
@ XF_LOG_COLOR_CYAN
Definition xf_log.c:48
#define xf_log_vsprintf(buffer, maxlen, fmt, args)
Definition xf_log.c:35
int xf_log_register_obj(xf_log_out_t out_func, void *user_args)
注册log后端是输出到哪里,其最大值受到 XF_LOG_OBJ_MAX 的限制
Definition xf_log.c:118
struct _xf_log_obj_t xf_log_obj_t
static void find_args_from_index(va_list *va, size_t index)
Definition xf_log.c:262
static size_t xf_log_printf_out(xf_log_out_t log_out, void *arg, const char *format,...)
Definition xf_log.c:446
static xf_log_obj_t s_log_obj[XF_LOG_OBJ_NUM]
Definition xf_log.c:110
static const uint8_t s_lvl_to_color[]
Definition xf_log.c:99
static size_t xf_log_color_format(int log_obj_id, uint8_t level, const char *tag, const char *file, uint32_t line, const char *func, const char *fmt, va_list va)
Definition xf_log.c:456
static xf_log_time_func_t s_log_time_func
Definition xf_log.c:112
#define PL_CSI_START
Definition xf_log.c:19
struct _xf_log_filter_t xf_log_filter_t
#define XF_FORMAT_BUFFER_SIZE
#define XF_FORMAT_FLAG_SIZE
#define xf_log_printf(format,...)