通过ANSI
转义序列,C语言工程中导入一个头文件和一个源文件就可以实现终端彩色打印,并且可以自定义需要显示的打印等级。同时能够以16进制格式化打印数组内容。该彩色打印完全兼容printf
函数。
1.要求
要求终端支持ANSI
转义序列的显示,否则无法显示正确的颜色且会打印多余的字符。 最新工程可以关闭颜色输出,设置宏COLOR_ENABLE
为0
以关闭颜色输出,在一些不支持ANSI显示的终端可以设置。另外,如果需要支持中文显示,则终端需要支持UTF-8
。比如VSCode内置的终端、WSL2的终端、Git Bash等均支持ANSI
转义序列和UTF-8
2.入门使用
2.1 导入库
可以通过以下提供的头文件和源文件复制粘贴到指定的工程目录,也可以通过github下载。debug_log.c
提供了一个示例函数debug_log_demo
,直接调用观察输出效果。
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 131 132 133 134 135
| #ifndef DEBUG_LOG_H_ #define DEBUG_LOG_H_ #include <stdint.h> #include <string.h>
#define DBG_ENABLE 1
#define COLOR_ENABLE 1
#define DBG_LOG_LEVEL DBG_LOG_DEBUG
#define DBG_LOG_ERROR 1
#define DBG_LOG_WARNING 2
#define DBG_LOG_INFO 3
#define DBG_LOG_DEBUG 4
#define ANSI_COLOR_RED "\x1b[31m" #define ANSI_COLOR_GREEN "\x1b[32m" #define ANSI_COLOR_YELLOW "\x1b[33m" #define ANSI_COLOR_BLUE "\x1b[34m" #define ANSI_COLOR_MAGENTA "\x1b[35m" #define ANSI_COLOR_CYAN "\x1b[36m" #define ANSI_COLOR_RESET "\x1b[0m"
#if COLOR_ENABLE #define PRINT_ANSI_COLOR(...) printf(__VA_ARGS__) #else #define PRINT_ANSI_COLOR(...) #endif
#if DBG_ENABLE
#define DBG_LOG(color, ...) \ PRINT_ANSI_COLOR(color); \ printf("[%s]: ", __func__); \ printf(__VA_ARGS__); \ PRINT_ANSI_COLOR(ANSI_COLOR_RESET); \ printf("\n");
#if DBG_LOG_LEVEL >= DBG_LOG_DEBUG #define DBG_LOGD(...) DBG_LOG(ANSI_COLOR_BLUE, __VA_ARGS__); #else #define DBG_LOGD(...) #endif
#if DBG_LOG_LEVEL >= DBG_LOG_INFO #define DBG_LOGI(...) DBG_LOG(ANSI_COLOR_GREEN, __VA_ARGS__); #else #define DBG_LOGI(...) #endif
#if DBG_LOG_LEVEL >= DBG_LOG_WARNING #define DBG_LOGW(...) DBG_LOG(ANSI_COLOR_YELLOW, __VA_ARGS__); #else #define DBG_LOGW(...) #endif
#if DBG_LOG_LEVEL >= DBG_LOG_ERROR #define DBG_LOGE(...) DBG_LOG(ANSI_COLOR_RED, __VA_ARGS__); #else #define DBG_LOGE(...) #endif #else #define DBG_LOGD(...) #define DBG_LOGI(...) #define DBG_LOGW(...) #define DBG_LOGE(...) #endif
#define ADVANCED_LOG(color, ...) \ PRINT_ANSI_COLOR(color); \ printf(__VA_ARGS__); \ PRINT_ANSI_COLOR(ANSI_COLOR_RESET); \ printf("\n");
void print_hex_table(uint8_t *data, uint16_t len);
void debug_log_demo(void);
#endif
|
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
| #include <stdio.h> #include "debug_log.h"
const char *log_level_string[] = { [DBG_LOG_ERROR] = "Error", [DBG_LOG_WARNING] = "Warning", [DBG_LOG_INFO] = "Info", [DBG_LOG_DEBUG] = "Debug", };
void print_hex_table(uint8_t *data, uint16_t len) { #if DBG_ENABLE PRINT_ANSI_COLOR(ANSI_COLOR_CYAN); printf(" "); for (size_t i = 0; i < 0x10; i++) { printf("%02X ", (unsigned int)i); } PRINT_ANSI_COLOR(ANSI_COLOR_RESET); printf("\n"); size_t rows = (len + 15) / 16; for (size_t i = 0; i < rows; i++) { PRINT_ANSI_COLOR(ANSI_COLOR_CYAN); printf("%04X ", (unsigned int)i * 16); PRINT_ANSI_COLOR(ANSI_COLOR_MAGENTA); size_t j; for (j = 0; j < 16 && i * 16 + j < len; j++) { printf("%02X ", data[i * 16 + j]); } for (; j < 16; j++) { printf(" "); } printf("\n"); PRINT_ANSI_COLOR(ANSI_COLOR_RESET); } #endif }
void debug_log_demo(void) { #if DBG_ENABLE == 0 printf("## Debug Print Disable, NO log print\n"); #else printf("Current log level is [%s]\n", log_level_string[DBG_LOG_LEVEL]); #endif #define PROJECT_NAME_ART " ____ ____ ____ ____ ____ ____ ____ ____ \n||L |||O |||G |||- |||D |||E |||M |||O ||\n||__|||__|||__|||__|||__|||__|||__|||__||\n|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|\n" ADVANCED_LOG(ANSI_COLOR_YELLOW, PROJECT_NAME_ART); DBG_LOGI("中文测试输出, 需要确保终端支持UTF-8的显示, 否则显示乱码\n"); DBG_LOGD("The Log Level is %s", log_level_string[DBG_LOG_DEBUG]); DBG_LOGI("The Log Level is %s", log_level_string[DBG_LOG_INFO]); DBG_LOGW("The Log Level is %s", log_level_string[DBG_LOG_WARNING]); DBG_LOGE("The Log Level is %s", log_level_string[DBG_LOG_ERROR]); uint8_t array[100] = {0}; for (size_t i = 0; i < sizeof(array); i++) { array[i] = i; } print_hex_table(array, sizeof(array)); }
|
2.2 使用示例
3.进阶使用
3.1 关闭所有打印
通过debug_log.h
中的宏DGB_ENABLE
启用或禁用全局打印
3.2 按照等级打印
通过debug_log.h
中的宏DBG_LOG_LEVEL
控制打印等级。打印的等级从高到低的排序: 错误 > 警告 > 普通 > 调试。假设指定打印等级为DGB_LOG_WARNING
,即当前工程只会输出警告以及错误的信息,在工程产生大量的日志的时候十分有用。
3.3 行首说明
- 如果输出的等级是调试或普通,则行首的方括号表示的是函数名称
如果输出的等级是警告或错误,则行首的方括号表示的是文件名(已经去除了文件路径)+代码行数+函数名称,Update: 为了效果统一,所有打印等级的格式均一致,只有颜色区分,且行首的函数名称已经足够定位调试
行首是可以自定义的,比如在FreeRTOS中可以加入系统当前的滴答数以粗略估计该打印的时间。其余同理。
参考