电子产业一站式赋能平台

PCB联盟网

搜索
查看: 358|回复: 0
收起左侧

如何设计嵌入式 C 语言日志分级?

[复制链接]

576

主题

576

帖子

4487

积分

四级会员

Rank: 4

积分
4487
发表于 2023-4-3 17:50:00 | 显示全部楼层 |阅读模式
我是老温,一名热爱学习的嵌入式工程师
关注我,一起变得更加优秀!给大家分享一下嵌入式 C 语言日志分级
日志分级概念所谓日志分级,就是将日志按照不同的层次,有选择的输出。
参考一些高级语言的分级日志设计,我们根据对程序运行信息的类型把控,可以把日志分为5个级别DEBUG、INFO、WARN、ERROR、FATAL。
DEBUG:主要用于程序开发测试阶段的打印输出,用于验证程序的设计逻辑是否满足上层应用的设计需求,在经过测试检验后的发布程序可以把它关掉。INFO:这个级别的打印输出是用来告诉测试人员或者开发人员一些提示的信息WRAN:这是一种警告的打印输出,它一般是用来输出诸如用户输入错误的数据之类的警告打印,这个级别的打印输出在程序发布后也建议保留,以方面后期程序的维护追踪。ERROR:运行出错的打印,这个级别的打印在发布的软件不可关闭,否则无法从发布软件中获取一些反馈信息来指导我们新的程序优化设计。FATAL :程序运行遇到这种级别的问题,很难修复,一般伴随着程序的闪退或重启,此时FATAL ERROR的打印则非常关键了,可以帮助我们定位到程序跑飞的原因,FATAL ERROR级别的打印在任何时刻都不可以关闭。
为什么要有日志分级?一个好的日志分级设计,有助于我们快速定位问题,主要是方便后续开发和维护。在设计软件的时候,可以根据问题出现的轻重缓急,有决策的去添加分层信息,在必要的时候有针对性的打开和关闭一些日志。
如何设计?目前有两种粗浅的设计策略,一种是或的关系,即各个日志等级彼此独立,可以单独打开关闭;一种是顺序打印,根据设置打印等级,低于或者高于这个等级的才打印。
两种没有孰好孰坏,根据需要选择合适策略即可。本文将以后者介绍。
设置打印级别
/* module_debug.h */
/*1. 设置打印级别 */
enum {
        LOG_LEVEL_NONE,
        LOG_LEVEL_DEBUG,
        LOG_LEVEL_INFO,
        LOG_LEVEL_WARN,
        LOG_LEVEL_ERROR,
        LOG_LEVEL_FATAL,
};
/* 2. log 打印 重写 */
void log_fun(int level, const char *opt, const char* tag, int line, const char *func, const char *fmt, ...);
/* 3. 各打印级别宏 */
/*
*@LOG_DBG
*/
#define LOG_DBG(tag, fmt, ...) \
  log_fun(LOG_LEVEL_DEBUG, "D", tag , __LINE__, __func__, fmt, ##__VA_ARGS__)
/*
*@LOG_INFO
*/
#define LOG_INFO(tag, fmt, ...)  \
  log_fun(LOG_LEVEL_INFO, "I", tag , __LINE__, __func__, fmt, ##__VA_ARGS__)
/*
*@LOG_WARN
*/
#define LOG_WARN(tag, fmt, ...)  \
  log_fun(LOG_LEVEL_WARN, "W", tag , __LINE__, __func__, fmt, ##__VA_ARGS__)
/*
*@LOG_ERR
*/
#define LOG_ERR(tag, fmt, ...)  \
  log_fun(LOG_LEVEL_ERROR, "E", tag , __LINE__, __func__, fmt, ##__VA_ARGS__)
/*
*@LOG_FATAL
*/
#define LOG_FATAL(tag, fmt, ...)  \
  log_fun(LOG_LEVEL_FATAL, "F", tag , __LINE__, __func__, fmt, ##__VA_ARGS__)
注释:... 和 __VA_ARGS__.省略点表示可变参数,__VA_ARGS__表示可变参数的宏,是C99规范中新增的,用来替换宏定义中的可变参数(...); ##运算符将两个宏参数连接在一起。##__VA_ARGS__ 这里主要是为了解决当__VA_ARGS__为空时编译问题,使用##防止编译出错。
根据打印级别控制输出范围
/* module_debug.c */
#include
#include
#include
#include
#include
#include
#include
int g_current_dbg_level = LOG_LEVEL_DEBUG;
void log_fun(int level, const char *opt, const char* tag, int line, const char *func, const char *fmt, ...)
{
    if (level > g_current_dbg_level) {
            char msg_buf[20*1024];
            va_list ap;
            va_start(ap,fmt);                                                                       
            sprintf(msg_buf,"%s/%s (%d): %s() ",opt, tag, line, func);
            vsprintf(msg_buf+strlen(msg_buf),fmt,ap);
            fprintf(stderr,"%s
",msg_buf); /* 输出到标准输出 */
            va_end(ap);
    }
}
/* 设置 打印级别 */
void ModuleDebugInit(int level)
{
    g_current_dbg_level = level;
}
测试
/* main.c */
#include
#define TAG    "test"
int main (int argc , char *argv[])
{
    LOG_DBG(TAG, "log_debug %d
", LOG_LEVEL_DEBUG);
    LOG_INFO(TAG, "log_info %d
", LOG_LEVEL_INFO);
    LOG_WARN(TAG, "log_warn
");
    LOG_ERR(TAG, "log_err
");
    return 0;
}
输出打印信息:
I/test (61): main() log_info 2
W/test (62): main() log_warn
E/test (63): main() log_err
其中I表示INFO、W表示WARN、E表示ERROR;紧接着跟着模块(test),也可以是文件名;然后是行号、函数名,最后是打印信息。
当然具体打印信息和风格用户可以根据需要,自行设计。
来自公众号:漫谈嵌入式
作者:Vinson

-END-
往期推荐:点击图片即可跳转阅读
                                                                               

wgnkrqllfy06405533842.jpg

wgnkrqllfy06405533842.jpg

                                                                                这款 99 元嵌入式工业核心板,有点相见恨晚的感觉!
                                                                               
                                                                               

hes0kuighqr6405533942.jpg

hes0kuighqr6405533942.jpg

                                                                                如何建立嵌入式软件基础设施?
                                                                               
                                                                               

ajey1d25fjl6405534042.jpg

ajey1d25fjl6405534042.jpg

                                                                                基于 ChatGPT 的代码阅读工具
                                                                               
我是老温,一名热爱学习的嵌入式工程师
关注我,一起变得更加优秀!
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


联系客服 关注微信 下载APP 返回顶部 返回列表