自己写了个 header-only 轻量级 C 语言日志库 lw-clogger, 适用于嵌入式环境, 分享给需要的朋友.

2014-09-02 00:52:41 +08:00
 Akagi201
类似的轮子挺多的, 看了一下感觉没必要太复杂, thread-safe还是依赖于线程库, 或者保险情况下自己控制一下最好了, 就算用printf在pthread下也是线程不安全的.

学习了一下别的开源代码, 还有结合了一些自己使用宏的经验, 分享给有需要的朋友.

## 项目地址
* <https://github.com/Akagi201/lw-clogger>
3406 次点击
所在节点    分享创造
13 条回复
dbbbit
2014-09-02 07:09:51 +08:00
吐槽下这个函数的命名

clog_debug(l, LOG_INFO, "LOG_INFO");
clog_debug(l, LOG_NOTICE, "LOG_NOTICE");
clog_debug(l, LOG_DEBUG, "LOG_DEBUG");
auser
2014-09-02 07:20:43 +08:00
时间颗粒度不够,推荐gettimeofday
每次都调用write,系统调用开销影响多大?
另外,为什么printf在多线程下不是安全的?

我只接触服务端,如果嵌入式环境下较为特殊,当我没说。
soli
2014-09-02 10:30:13 +08:00
clog_file 和 _clog_debug 并不是太复杂,可以合并到一个函数里,减少一次函数调用。

接口可以定义成:

```
void clog_write(clogger *l, int level, const char *fmt, ...);
```

然后,用宏定义把 file、func、line 加进去。这样就可以在 debug 以上级别的日志里省掉这些内容。

比如:

```
#define CLOG_ERRO(log, fmt, args...) clog_write(log, CLOG_LEVEL_ERRO, fmt, ##args)
#define CLOG_WARN(log, fmt, args...) clog_write(log, CLOG_LEVEL_WARN, fmt, ##args)
#define CLOG_INFO(log, fmt, args...) clog_write(log, CLOG_LEVEL_INFO, fmt, ##args)
#define CLOG_DEBUG(log, fmt, args...) clog_write(log, CLOG_LEVEL_DEBUG, __FILE__":"__FUNCTION__"():"__LINE__" "fmt, ##args)
```

仅供参考。
soli
2014-09-02 10:32:45 +08:00
呃,说好的 Markdown 呢。。。
soli
2014-09-02 10:40:47 +08:00
另外,建议把日志级别、PID 等写成相同的长度,这样打印出来的日志漂亮一些。


比如(我喜欢把时间放到最前面):

```
2014-09-02 00:28:10,INFO,[00658] test.c:main():19: LOG_INFO
2014-09-02 00:28:10,NOTE,[13658] test.c:main():20: LOG_NOTICE
2014-09-02 00:28:10,WARN,[13650] test.c:main():24: Foo[Information
2014-09-02 00:28:10,ERRO,[03658] test.c:main():24: Foo[Information
```
semicircle21
2014-09-02 11:36:24 +08:00
每次都 write, 这样恐怕不行, 至少不是常规手段.
并不是性能问题, 也不是线程安全, 而是:
可靠的 Log() 是不会阻塞的, 现在直接 write 操作, 谁知道底层驱动会干啥, 用个1s 去整理下 Flash 碎片啥的, 谁都说不清.

当然, 如果就是要用来 Debug,有特殊需求, 那在 write 后面加个 flush 也不为过.
Akagi201
2014-09-02 14:40:45 +08:00
@semicircle21 我用write而不用C库是为了避免使用带缓存的函数, 在嵌入式里应该更需要, 当然是个人看法.
Akagi201
2014-09-02 14:41:53 +08:00
@auser 感谢你的建议, 我后面会考虑改良. 关于线程安全要看具体的C库和线程库实现, 我觉得要是想确定还是要自己控制比较保险. 一个参考链接 http://stackoverflow.com/questions/467938/stdout-thread-safe-in-c-on-linux
Akagi201
2014-09-02 14:43:02 +08:00
@dbbbit 接口我的考虑是只用一个函数, 不行用clog_err, clog_warn....这样, 容易忘, 而是用跟syslog一样的log等级, 当然是个人想法而已
Akagi201
2014-09-02 14:44:49 +08:00
@soli 好吧, 这点dirty代码被你发现了, 我写着写着也觉得合并会比较好, 我有空更新下. 排版我后面考虑下加点对齐代码, 谢谢, 很好的建议
semicircle21
2014-09-02 16:21:24 +08:00
@Akagi201 "C库"和"带缓存的函数"是指 printf 吗? 可能我描述的不太清楚,
重新描述一下: 用 write 没问题. 问题在于直接调用了:
_clog_debug -> clog_file -> write
这样, 调用 _clog_debug 时可能由于 write 而阻塞, 这样会影响调用了_clog_debug的thread的行为, 不时的阻塞一下, 之类.
Akagi201
2014-09-02 17:21:48 +08:00
@semicircle21 理解你的意思了, 默认的write是不是阻塞不确定, 可以用fcntl设置为非阻塞, 就可以了.
semicircle21
2014-09-03 06:31:35 +08:00
@Akagi201 默认的是阻塞的, 如果用了 NON_BLOCK, 那write 的行为是会彻底变掉的, 也需要做相应的处理, 比如建个 buffer把一次没写完的部分先缓存住等等. 另外, 对于嵌入式, 还需要确认驱动是不是靠谱, 是不是真的按 NON_BLOCK执行了...
我又想了下, 如果不是对可靠性和实时性要求特别高的话, 这样估计也没什么问题. 不用在意这些细节..

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/131202

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX