Linux C可复用日志函数需兼顾灵活性、线程安全、可配置性和易用性,通过宏控制级别、自动注入文件行号等上下文、pthread_mutex_t保护输出、支持滚动截断及errno/调用栈附加。

在 Linux C 程序中编写可复用的日志函数,核心是兼顾灵活性、线程安全、可配置性和易用性。不依赖第三方库(如 glog、spdlog),纯 POSIX + 标准 C 就能实现一个轻量但实用的日志封装。
支持日志级别与运行时开关
通过宏或整型变量控制日志级别(DEBUG/INFO/WARN/ERROR),避免无用字符串拼接和系统调用开销:
- 定义日志级别宏,如 #define LOG_LEVEL 3(0=OFF, 1=ERROR, 2=WARN, 3=INFO, 4=DEBUG)
- 用 #ifdef DEBUG 或运行时检查 if (log_level >= LOG_DEBUG) 控制是否执行实际输出
- 关键:DEBUG 级别日志在发布版中应完全被预处理器剔除(用宏包裹),而非只跳过 printf
自动注入上下文信息
避免每次调用都手动写文件名、行号、时间——用可变宏 + 内置宏自动捕获:
Linux 性能分析与调优专家,覆盖 CPU、内存、磁盘 I/O、网络、内核参数、编译优化、容器/K8s。适用场景:系统卡顿/高负载、内存不足/OOM/Swap 高、CPU 异常/iowait 高。
- 使用 __FILE__、__LINE__、__func__ 补充定位信息
- 用 __attribute__((format(printf, N, N+1))) 声明宏,让编译器检查格式串安全性
- 示例宏定义节选:
do { \
if (log_level >= level) \
log_print(level, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__); \
} while(0)
线程安全与输出目标可选
多线程环境必须防止日志交错;同时支持输出到 stderr、文件或 syslog:
- 用 pthread_mutex_t 保护共享输出(如 fputs + fflush);若用 syslog() 则本身线程安全
- 初始化时调用 log_init(FILE *fp) 或 log_to_syslog(ident, facility) 统一设置后端
- 避免在信号处理函数中直接调用非异步信号安全函数(如 malloc、printf);如需信号内打日志,用 write() + 格式化缓冲区
支持日志滚动与自动截断
生产环境不能无限追加。简单实现可基于文件大小 + 重命名:
- 记录当前日志文件 size,每次写前检查;超限则 close → rename → open 新文件
- 用 fstat() 获取大小,rename() 原子重命名(如 app.log → app.log.1)
- 更健壮的做法:配合 open(..., O_APPEND | O_CREAT) 和定期 fork + exec 调用 logrotate(由外部管理)
不复杂但容易忽略的是错误码上下文(errno)和调用栈(backtrace)。必要时可在 ERROR 日志中自动附加 strerror(errno) 或用 backtrace()/backtrace_symbols() 抓简略栈帧——这对调试崩溃和阻塞问题很关键。

















