应封装带时间戳的日志宏:用clock_gettime获取毫秒级时间,结合__FILE__、__LINE__、__func__自动注入上下文,支持日志级别开关和pthread_mutex线程安全输出。

在 Linux 中做函数封装时,如果想让每个被封装的函数自动输出带时间戳的日志,核心是把日志逻辑“注入”到函数行为中,而不是每次手动调用 printf 或 fprintf。关键在于:统一的时间获取、格式化、线程安全输出,以及低侵入性的调用方式。
时间戳要精确且可复用
日志时间戳不能靠运行时临时调用 date 命令(开销大、不可控),应直接在 C/C++ 层获取:
- 秒级精度用
time()+strftime(),适合一般调试 - 毫秒级推荐
gettimeofday()(注意:在较新内核中建议用clock_gettime(CLOCK_REALTIME, ...)更标准) - 封装一个内联函数或静态工具函数,比如
get_timestamp(char* buf, size_t len),内部完成秒+毫秒拼接,如"2026-09-16 07:00:12.483"
日志内容要自动包含上下文
避免每次写 log("func_x called") 这种重复劳动。利用 C 预处理器宏自动捕获信息:
- 用
__FILE__、__LINE__、__func__获取文件名、行号、函数名 - 定义宏如:
#define LOG_INFO(fmt, ...) do { char ts[64]; get_timestamp(ts, sizeof(ts)); fprintf(stderr, "[%s] [%s:%d %s] INFO: " fmt "\n", ts, __FILE__, __LINE__, __func__, ##__VA_ARGS__); } while(0) - 这样在任意封装函数里写
LOG_INFO("value=%d", x),就能打出完整上下文
封装函数里嵌入日志要轻量且可控
不是所有调用都要打日志,得支持开关和分级:
- 加一个全局日志级别变量(如
int g_log_level = LOG_LEVEL_INFO),宏里先判断是否启用该级别 - 把日志输出逻辑抽成独立函数(如
do_log(int level, const char* file, int line, const char* func, const char* fmt, ...)),封装函数内部调用它 - 例如封装一个安全的内存分配函数:
void* safe_malloc(size_t size) { void* p = malloc(size); LOG_DEBUG("allocated %zu bytes → %p", size, p); return p; }
多线程环境下必须加锁
多个封装函数可能被不同线程并发调用,stderr 或日志文件是共享资源:
- 用
pthread_mutex_t初始化一个全局互斥锁,在do_log开头pthread_mutex_lock,结尾unlock - 若追求性能,可用线程局部缓冲 + 定期刷出,但简单封装场景直接加锁更稳妥
- 避免用
printf(非异步信号安全),优先用fwrite+snprintf组合











