Linux C多级日志方案通过预处理器宏控制编译开关、运行时级别过滤(DEBUG/INFO/WARN/ERROR)、自动上下文补全(__FILE__等)及可配置输出目标实现轻量实用的日志功能。

在 Linux C 程序中实现支持多级日志(如 DEBUG、INFO、WARN、ERROR)的输出函数,核心是结合预处理器宏控制编译期日志开关、运行时级别过滤、格式化输出和可选的输出目标(终端/文件/stderr)。下面给出一个轻量、实用、可直接集成的方案。
定义日志级别与全局控制开关
用整数常量定义级别,数值越小表示越重要(便于比较过滤),再用宏控制是否编译调试日志:
#define LOG_LEVEL_DEBUG 0 #define LOG_LEVEL_INFO 1 #define LOG_LEVEL_WARN 2 #define LOG_LEVEL_ERROR 3 <p>// 全局最低生效级别(可运行时修改,也可设为宏常量) extern int g_log_level;</p><p>// 编译期开关:注释掉则完全不编译 DEBUG 日志,减小体积</p><h1>define ENABLE_DEBUG_LOG</h1><p></p>
封装带级别判断的日志宏
使用 do { ... } while(0) 避免宏展开歧义;利用 __FILE__、__LINE__、__func__ 自动补全上下文;只在满足级别条件且宏启用时才执行:
#ifdef ENABLE_DEBUG_LOG
#define LOG_DEBUG(fmt, ...) do { \
if (g_log_level define LOG_INFO(fmt, ...) do { \<pre class="brush:php;toolbar:false;">if (g_log_level <p>} while(0)</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill6580" title="Linux installer"><img
src="https://img.php.cn/upload/skill/000/000/081/179101817874041.jpg" alt="Linux installer" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill6580" title="Linux installer" class="overflowclass">Linux installer</a>
<p class="overflowclass">先解析安全源,运行本地CLI安装、启动、卸载Linux桌面应用。用户请求时使用。</p>
</div>
<a rel="nofollow" href="/xiazai/skill6580" title="Linux installer" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><h1>define LOG_WARN(fmt, ...) do { \</h1><pre class="brush:php;toolbar:false;">if (g_log_level <p>} while(0)</p><h1>define LOG_ERROR(fmt, ...) do { \</h1><pre class="brush:php;toolbar:false;">if (g_log_level <p>} while(0)
</p>支持运行时动态调整与输出重定向
定义全局变量 g_log_level 并提供设置函数;如需输出到文件,可将 fprintf 替换为自定义输出函数(如用 vfprintf + 可变参数转发):
int g_log_level = LOG_LEVEL_INFO; // 默认只显示 INFO 及以上
<p>void set_log_level(int level) {
g_log_level = level;
}</p><p>// 示例:输出到文件句柄(需外部维护 fd 或 FILE<em>)
static FILE </em>g_log_fp = stderr;
void set_log_output(FILE *fp) {
if (fp) g_log_fp = fp;
}</p><p>// 改写 LOG_INFO 使用自定义输出:</p><h1>define LOG_INFO(fmt, ...) do { \</h1><pre class="brush:php;toolbar:false;">if (g_log_level <p>} while(0)
</p>进阶建议:线程安全与性能优化
多线程场景下注意避免 fprintf 冲突(stderr 默认是线程安全的,但自定义 FILE* 需加锁);高频日志可考虑缓冲+异步刷盘,或用 write() 替代 stdio(绕过缓冲和锁):
- 对每条日志加
pthread_mutex_lock/unlock(简单但有开销) - 用
write(STDERR_FILENO, buf, len)直接系统调用(无锁、无缓冲,适合关键错误) - 调试阶段启用
ENABLE_DEBUG_LOG,发布时关闭,避免性能损耗 - 级别字符串可用查表法(如
const char *level_str[] = {"DEBUG","INFO",...})统一管理










