一个用纯 C99 写的小型高效日志库,只有两个文件,不需要任何第三方依赖

 

说实话,写了这么多年 C 语言,有个事儿我一直挺纠结的。就是打日志。

你看啊,刚学编程那会儿,谁不是满屏的 printf?调试全靠打印,那是真·原始人生活。后来项目大了,你发现 printf 不行了,没时间戳、没文件行号、没颜色区分,关键是一旦上线,你还没法关掉它,控制台直接被刷爆,那叫一个灾难。

于是你开始找库。好家伙,一搜日志库,要么是那种巨无霸,光配置就得写半天,编译还得依赖一堆乱七八糟的东西;要么就是太简陋,跟自己写的宏也没啥区别。

直到我碰到了 log.c。

真的,这玩意儿给我的感觉就是——刚刚好。就像你饿的时候,刚好有一碗热腾腾的葱油拌面,不花哨,但就是顶饱、好吃。

今天我就跟大伙儿唠唠这个库,顺便聊聊咱们写 C 代码时,日志到底该怎么管。

极简主义的胜利

咱们先看个大概。log.c 这项目,简单到令人发指。就两个文件:log.c 和 log.h。

你没听错,就俩文件。

我想起前几年带个项目,有个实习生非要引个什么“企业级”日志框架,光是把环境配通就花了一下午。我就跟他说,兄弟,咱们是写嵌入式逻辑的,不是搞大数据的,别整那些虚头巴脑的。

log.c 的用法,简直就是为了懒人设计的。你把这俩文件往项目里一扔,一起编译,完事。

用起来啥样?

log_info("这就完事了? %s", "是的");

没了。就这么简单。

它给了你 6 个宏,基本上覆盖了咱们日常 99% 的需求:

  • • log_trace:追踪流程,平时不开,查死锁或者逻辑漏洞时开。

  • • log_debug:调试用的,开发阶段最常用。

  • • log_info:记录关键节点,比如“系统启动了”、“用户登录了”。

  • • log_warn:警告,比如“内存有点紧张但还能跑”。

  • • log_error:出错了,但系统还没挂。

  • • log_fatal:完犊子了,准备重启吧。

输出的结果也是那种看着特舒服的格式,带时间、带颜色、带文件名和行号。比如:
20:18:26 TRACE src/main.c:11: Hello world

这种清晰度,比你自己手搓的 printf("===DEBUG===") 强了一万倍吧?

看着简单,其实内功深厚

这时候肯定有人要说了:“哎呀院士,这不就是封装了几个 fprintf 嘛,我也能写。”

嘿,你还真别小看它。这库虽然代码少,但设计思路非常老辣。

第一点,它懂“安静”。
有个函数叫 log_set_quiet(bool enable)。这功能太重要了。有时候咱们跑自动化测试,或者作为库被别人调用的时候,你不想让控制台噼里啪啦乱吐字。一键静音,世界清静,但它还能继续往文件里写日志。这就是分寸感。

第二点,它懂“分级”。
log_set_level(int level)。这可是生产环境的救命稻草。开发的时候我开 LOG_TRACE,恨不得把变量每一位都打印出来;上线了,我把级别调到 LOG_ERROR,只有出大事才吱声。这能极大地节省磁盘空间和 I/O 性能。很多新手写代码不注意这个,上线几天把服务器磁盘写满了,被运维追着骂,别问我怎么知道的。

第三点,也是最骚的,回调函数(Callback)。
这个 log_add_callback 设计得非常有灵性。它允许你把日志数据“钩”出来。
你想把日志存数据库?想发到远程服务器?想推送到 Slack 或者钉钉群里报警?
不用改库的源码,注册个回调函数,拿到结构体数据,随你怎么折腾。这就是架构设计里的“开闭原则”啊朋友们,对扩展开放,对修改关闭。

关于多线程的那点事儿

做 C 语言开发的,听到“全局变量”或者“静态库”,第一反应肯定是:线程安全吗?

log.c 考虑到了。它有个 log_set_lock 函数。

虽然它默认没有绑定具体的锁实现(为了保持库的纯粹性,不依赖 pthread 或者 Windows API),但它把接口留给你了。你如果是在多线程环境下跑,自己写个简单的互斥锁包装一下传进去,它在写日志的时候就会自动上锁、解锁。

这就很聪明。它不强塞给你一个你可能不用的锁库,而是把选择权交给你。这种设计哲学,我是非常推崇的。

既然要用,怎么用得漂亮?

最后,结合这个库,给大伙儿几个实操建议:

  1. 1. 别乱用级别。我看过太多代码,全篇都是 log_info。出了 Bug,想通过日志过滤一下都不行。要严格遵守 Trace < Debug < Info < Warn < Error 的层级。

  2. 2. 文件输出要分离。利用它的 log_add_fp 功能,可以把 Error 级别的日志单独写一个文件。查问题的时候,先看 Error.log,通常能秒杀 80% 的故障。

  3. 3. 记得加颜色。编译的时候加上 -DLOG_USE_COLOR。别觉得这是花哨,当你对着几千行黑白日志眼花缭乱的时候,那一行红色的 Error 能救你的命。

总结

总的来说,log.c 是我见过的 C99 标准下,性价比最高的日志库之一。它没有复杂的依赖,代码量极小,但功能却覆盖了从控制台输出、文件记录到自定义回调的全套流程。

在这个动不动就搞几百兆框架的年代,这种几百行代码解决核心问题的“小而美”,简直就是一股清流。

如果你还在手写 printf,或者在这一堆臃肿的库里挣扎,不妨试试它。

有时候,简单的,才是最强大的。

项目地址:https://github.com/rxi/log.c

 

发表评论