uLog 是一个专为资源受限的嵌入式设备设计的超轻量级结构化日志库。它借鉴了 Log4c、Log4j 的思路,但把负担甩得干干净净:一个 .h、一个 .c,只要有 stdio.h、string.h、stdarg.h,就能跑起来。最妙的是,完全可控、不用时啥都不占地方——编译时如果没定义 ULOG_ENABLED,根本就不生成任何日志代码,真·零开销。
适用场景与痛点
你是不是也遇到过这样的烦恼?
-
• 嵌入式项目没法用那些大而全的日志库,烧录空间和 RAM 动辄吃不消;
-
• 想分级输出(ERROR、INFO、DEBUG)却又不想把 printf 全局打开;
-
• 想把日志丢到串口、丢到 SD 卡、丢到内存环形缓冲,一套又一套,折磨人……
uLog 就是来救场的。它让你:“唰”一下搞定各种输出源,随时调节每个输出的阈值级别,开发/发布一键切换,省心又省资源。
主要特性
-
• 纯 C 实现,一个头文件+一个源文件,没人依赖;
-
• 支持 CRITICAL、ERROR、WARNING、INFO、DEBUG、TRACE 六档级别;
-
• 多路输出(console、文件、内存 buffer……)各自独立阈值;
-
• 编译期开关:
ULOG_ENABLED未定义时,无日志代码; -
• 自带测试用例,质量在线,放心用。
|
特性 |
说明 |
|
一键开关 |
编译时 undef |
|
多订阅机制 |
ULOG_SUBSCRIBE
增加输出函数, |
|
级别可调 |
不同输出可设不同阈值,灵活控制信息量 |
|
零依赖 |
只要标准库,无额外包,适合各种裸机或 RTOS 环境 |
Python 示例
虽说 uLog 本身是 C 库,但很多时候你会把日志刷到文件或串口,然后用 Python 快速搞定后续处理。下面这段小脚本,示范了怎么把日志文件里所有 ERROR、CRITICAL 级别的行过滤出来:
import re
LOG_PATTERN = re.compile(r'(.+?) \[(.+?)\]: (.+)')
def parse_log_line(line):
m = LOG_PATTERN.match(line)
if not m:
return None
timestamp, level, msg = m.groups()
return {'time': timestamp,'level': level,'msg': msg}
def filter_errors(logfile):
with open(logfile,'r')as f:
for line in f:
entry = parse_log_line(line)
if entry and entry['level']in('ERROR','CRITICAL'):
print(f"{entry['time']} - {entry['level']} - {entry['msg']}")
if __name__ =='__main__':
filter_errors('device.log')
这段代码很简单:正则切分三段,把高危级别的直接打印出来,拿去做报警或统计都行。
优缺点一览
|
优点 |
缺点 |
|
极低的资源占用(代码+数据) |
不支持异步输出(不过可以自己封装环形缓冲) |
|
灵活的多路订阅/阈值控制 |
没有原生网络传输,需要自己实现 send/recv |
|
编译期开关无痕息化 |
纯 C 实现,对 C++ 用户需要加 |
|
测试覆盖,社区维护 |
不带 GUI,不带高级插件,定位更偏底层 |
总结
总的来说,uLog 干净、轻量、高度可定制,特别适合那些对资源敏感又想要分级日志和多路输出的嵌入式项目。要用就用最简单的那一套,不要再把一大堆 logging 框架搬到 MC 平台上折腾了,轻装上阵,效率翻倍!
项目地址:https/github.com/rdpoor/ulog