首页 >> 大全

调试利器!一款轻量级日志库 log.c

2023-11-13 大全 32 作者:考证青年

这两天发现一个还不错的开源项目,记录一下学习心得。

对于嵌入式底层应用开发,基本离不开日志功能,这种轮子有很多,log.c 最简单,达到了开箱即用的级别。

log.c 是什么?

https://github.com/rxi/log.c

简单地说,log.c 就是一个 C 语言的日志功能模块。

点击查看大图

log.c 的几个特点:

代码简洁,就一个 .c 和 .h 文件,一共 200 行。

设计优雅,打印日志的 API 只有 1 个。

提供了将 log 输入到不同目标的接口,例如输入到文件。

提供了实现线程安全的接口。

log.c 怎么用?

打印日志的 API:

log_trace(const char *fmt, ...);
log_debug(const char *fmt, ...);
log_info(const char *fmt, ...);
log_warn(const char *fmt, ...);
log_error(const char *fmt, ...);
log_fatal(const char *fmt, ...);

它们都是对 () 的简单封装,用法和 () 一样。

示例:

下面的例子会将日志同时输出到标准输出和文件中。

#include "log.h"int main(int argc, char *argv[])
{log_set_level(0);log_set_quiet(0);FILE *fp1, *fp2;fp1 = fopen("./log_info.txt", "ab");if(fp1 == NULL)return -1;fp2 = fopen("./log_debug.txt", "ab");if(fp2 == NULL)return -1;log_add_fp(fp1, LOG_INFO);log_add_fp(fp2, LOG_DEBUG);log_debug("debug");log_info("info");log_warn("warn");fclose(fp2);fclose(fp1);return 0;
}

本地日志调试_日志管理器_

运行:

$ ./example1 
23:31:05 DEBUG example1.c:20: debug
23:31:05 INFO  example1.c:21: info
23:31:05 WARN  example1.c:22: warn$ cat log_debug.txt 
2022-05-08 23:31:05 DEBUG example1.c:20: debug
2022-05-08 23:31:05 INFO  example1.c:21: info
2022-05-08 23:31:05 WARN  example1.c:22: warn$ cat log_info.txt 
2022-05-08 23:31:05 INFO  example1.c:21: info
2022-05-08 23:31:05 WARN  example1.c:22: warn

关于线程安全:

log.c 代码虽然少,但是仍然考虑了线程安全,下面是用法示例。

#include "log.h"pthread_mutex_t MUTEX_LOG;
void log_lock(bool lock, void *udata);int main()
{log_set_level(0);log_set_quiet(0);pthread_mutex_init(&MUTEX_LOG, NULL);log_set_lock(log_lock, &MUTEX_LOG);/* Insert threaded application code here... */log_info("I'm threadsafe");pthread_mutex_destroy(&MUTEX_LOG);return 0;
}void log_lock(bool lock, void* udata)
{pthread_mutex_t *LOCK = (pthread_mutex_t*)(udata);if (lock)pthread_mutex_lock(LOCK);elsepthread_mutex_unlock(LOCK);
}

log.c 的内部实现?

私有数据结构:

点击查看大图

全局变量 L 维护了 log.c 所需要的所有信息。

void *udata 用于保存用户数据,用户可以将其用作任意用途。

lock 是一个函数指针:。

typedef void (*log_LockFn)(bool lock, void *udata);

用户可以用它来指定自己想用的锁机制,例如 的互斥量。

int level 用于保存当前的 log 等级,等级大于 level 的 log 才会被输出到标准输出。

bool quiet 用于打开、关闭 log 输出。

数组 用于保存多种输出方式,目前仅支持输出到标准输出和文件,有需要的话我们还可以将其扩展成输出到 、网络等,每增加一种输出方式就是构造一个 ,成员回调函数 负责真正地 log 输出功能:

typedef void (*log_LogFn)(log_Event *ev);

公共数据结构:

本地日志调试__日志管理器

点击查看大图

一条 log 信息对应一个 。暴露这个数据结构是为了用户可以编写自己的 log 打印函数 以输出 log。

公共的 API:

整个 log.c 其实只提供了一个打印相关的 API:()。() 等宏只是对 () 的简单封装,这种简洁地设计无论是对库的用户还是对库的开发者而言,都是最幸福的事情。

剩下的几个 API 用于控制和功能扩展。

() 的实现思路:

1> 根据用于提供的 log 信息构造 1个 。

2> 将 log 信息输出到标准输出。

3> 遍历所有 log ,逐一调用它们的打印函数 。

总结

log.c 代码优雅、设计简洁、功能实用,这对库的用户和库的开发者而言,都是一种幸福。

如果你的项目需要一个简单好用的日志功能,可以考虑集成开箱即用的 log.c

往期推荐

三本毕业,三年嵌入式软件的心路历程

神奇的双摆系统

开发项目事半功倍,一款开源的stm32驱动库大集合

傅里叶变换,为何如此优美?

一句话总结工程师的辛酸,你躺枪了吗?

高效,可靠,安全的串口通讯开源方案

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了