【开源解读】一款轻量级C日志库-EasyLogger
1、聊一聊
今天为大家推荐一首迈克的<Dangerous>,这是一首舞蹈歌曲,所以词的部分相对比较少,不过副歌绝对经典,也推荐大家去看原版舞蹈视频。
好了,作者在之前的文章中对于C语言语法细节和技巧讲解得相对比较多,所以现在考虑拿一些优秀的开源代码来进行分析分析,一方面可以看看这些开源项目怎么组织和设计代码,同时也能获得一些比较实用技巧。
2、用开源项目来得到提升
在嵌入式领域耳熟能详的开源项目-Linux操作系统算是最为闪耀了,可以说现在Linux横扫嵌入式领域与其开源精神和每个提交贡献的开发爱好者是分不开的。
在这些开发者中大部分都是在行业内有着丰富的软件编程和设计经验的工程师,他们的一些思想和设计理念都会在代码中得到体现,经常有句话说"见代码如见本人",所以拿这些代码来进行学习再好不过了。
同样代码的质量在一定程度上就体现了编写者的个人水平,所以当你移交相应的项目给同事来进行维护的时候,老是听到同事的吐槽,这个时候可能需要考虑一下是不是自己的代码质量还有待提高。
好了,下面正式进入EasyLogger的代码解读。
3、介绍一下EasyLogger
EasyLogger是github上ArmLink开源的一个轻量级日志库。下面是对应的链接地址:
GitHub:
https://github.com/armink/EasyLogger
其功能与大家平时printf把日志数据打印在终端上面是类似的,不过它有如下的几个特点,作者会根据这几个特点在后面一一为大家解读:
几个特点如下:
支持用户自定义输出方式(例如:终端、文件、数据库、串口、485、Flash...);(PS : 简单一点说就是接口留给用户,具体把日志数据发送到哪里由用户实现并决定)
日志内容可包含级别、时间戳、线程信息、进程信息等;(PS : 每条日志信息比较丰富,有日志的紧急等级,日志记录的时间等等信息)
日志输出被设计为线程安全的方式,并支持 异步输出 及 缓冲输出模式;(能够在多线程中使用,不用担心数据上的共享和互斥问题)
日志支持可以正常打印,也可以支持类似于hexdump功能;(PS : 类似于我们平时以16进制的形式查看数据)
支持按标签 、 级别 、 关键词进行动态过滤;(PS : 比较便于日志调试信息筛选和目标调试信息的定位)
各级别日志支持不同颜色显示;(PS : 这个需要终端支持,也是便于用户查看和分析 )
4、EasyLogger实现思路
上一节我们大体了解了一下EasyLogger的特点,其功能还是非常丰富的,该日志库的实现相对比较简单,大体思路我画了张图,大家带着这个思路去理解后面的代码会更加简单一点,不过个人觉得还是有些地方可以更好的优化,后面作者会提出一些个人的改善意见。
5、Easylogger代码解读
下面我们就来看看该开源代码具体怎么实现一个功能丰富的日志库的:
1、应用范例解读
下面作者列了一下使用该日志库的一个使用过程:
了解一下重点代码:(来自EasyLogger开源代码实例)
1int main(void){
2
3 /* initialize Hardwave */
4 BSP_Init();
5
6 /* initialize EasyLogger */
7 elog_init();
8 /* set EasyLogger log format */
9 elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL);
10 elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
11 elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
12 elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
13 elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_ALL & ~(ELOG_FMT_FUNC | ELOG_FMT_T_INFO | ELOG_FMT_P_INFO));
14 elog_set_fmt(ELOG_LVL_VERBOSE, ELOG_FMT_ALL & ~(ELOG_FMT_FUNC | ELOG_FMT_T_INFO | ELOG_FMT_P_INFO));
15
16 elog_set_text_color_enabled(true);
17 /* start EasyLogger */
18 elog_start();
19
20 /* dynamic set enable or disable for output logs (true or false) */
21 // elog_set_output_enabled(false);
22 /* dynamic set output logs's level (from ELOG_LVL_ASSERT to ELOG_LVL_VERBOSE) */
23 //elog_set_filter_lvl(ELOG_LVL_WARN);
24 /* dynamic set output logs's filter for tag */
25 //elog_set_filter_tag("main");
26 /* dynamic set output logs's filter for keyword */
27 //elog_set_filter_kw("Hello");
28 /* dynamic set output logs's tag filter */
29 //elog_set_filter_tag_lvl("main", ELOG_LVL_WARN);
30
31 while(1) {
32 /* test logger output */
33 log_a("the last bug!");
34 log_e("the last bug!");
35 log_w("the last bug!");
36 log_i("Debug Var1 = %d",5);
37 log_d("Debug Var2 = %.4f",3.1415);
38 log_v("name = %s","the last bug!");
39 LED_RUN_ON;
40 delay(10000000);
41 LED_RUN_OFF;
42 delay(10000000);
43 }
44 return 0;
45}
实验效果:
2、实现代码解读
1)该日志的配置及参数打包成了一个结构体,通过相应的函数接口即可对其进行修改,比如00157行的过滤信息、接下来的格式信息、是否初始化OK、是否使能输出等等,这些参数都有对应的set和get函数接口。
2)通过宏定义可知其支持6种日志等级,分别是断言(ASSERT)、错误(ERROR)、告警(WARN)等,大家可以在自己的工程项目中根据不同的故障方便的打印不同日志信息或者调试信息,同时也方便扩展其他的日志等级。
3)通过结构体成员enabled_fmt_set变量的每个位来确定每个等级日志的格式配置,这样也是节省其占用内存小的一个办法,同时对每个位的设置和取消也是采用了与或的办法,也是值得大家采纳的。
4)基本上其他的配置信息的处理都大同小异,比如说配置过滤信息的话,大体实现办法就是设定一定的条件(如字符串、日志等级等),然后在组拼数据buff的过程中进行判断(如:是否包含指定字符串、当前日志等级是否与过滤信息相等)并禁止打印即可,这里作者就不再分析太多,下图作者截取了一个字符串过滤的部分给大家看看。
5)下面我们再看看用户使用的日志接口,首先作者画个简图描述一下各函数的调用关系。
大家通过上面的调用关系看出来了,函数形式采用了大量的可变参数和一些预定义标识符,可能部分小伙伴对该部分接触的不多,可以先阅读作者往期对于这两块C语言知识点的讲解,基本上理解这块代码就也问题不大了。
推荐预先阅读
6)对于最终的elog_output函数,其实主要是根据用户的输入和预先进行的配置信息进行Buff的组拼和过滤,然后通过统一的接口把Buff发送出去,最后打印到终端等设备上,下面作者也是截取了组拼数据的代码实现和最后调用统一发送的接口部分代码给大家理解一下:
7)最后一点小知识,上面作者的实验动图中显示的日志有颜色,该功能也就是代码中的颜色使能功能,一般需要对应的日志显示终端能够支持ANSI转义序列,说得简单一点就是日志中填充了一些规定的特殊字符,显示的终端检测到这些字符就会实现格式控制、颜色显示等等,其代码中也进行了对应说明,如下图所示,大家有兴趣可以搜索相关资料了解一下。
8)代码到这里基本上就算结束了,至于最后所组拼的数据buff到底采用什么方式发送,是同步还是异步,发送到哪里,都有用户自己决定,最常用的就是串口了。
3、作者的一些个人想法
该日志库从代码结构来说对于同一套代码中实现两个日志管理会相对比较麻烦,其对于EasyLogger的操作方法都是已经被封装得比较单一化。如果我们要再创建第二个日志对象的话,需要把下面所有的方法都重新写一遍,这样有点麻烦。
之前作者跟大家介绍了很多C编程的思想,大家如果有认真阅读应该基本上知道该如何解决该问题了吧,所以大家感兴趣可以对其进行修改一下可以方便扩展多个Logger对象。
6、最后小结
EasyLogger这个开源项目作者就跟大家分享到这里,主要讲解了一下实现的思路,大家有时间可以阅读一下具体的代码,代码量不是很大,不过里面还有很多细节值得大家学习和参考,不要形成"下载代码-->烧录成功-->已学完"的体验式学习!
好了,这里是公众号:“最后一个bug”,一个为大家打造的技术知识提升基地。同时非常感谢各位小伙伴的支持,我们下期精彩见!
推荐好文 点击蓝色字体即可跳转