首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言輕量級日志庫實現:abort/log/info/error 四級日志 + 系統日志支持

     編輯:關於C語言

設計目標

為中小型 C 項目提供**零依賴、單文件、可選系統日志 (syslog)、可變參數格式化**的輕量級日志方案。不引入 glog/log4c 等重型庫,核心代碼 < 100 行,編譯後體積極小。

頭文件 log.h


#ifndef _LOG_H_
#define _LOG_H_

#ifdef __cplusplus
extern "C" {
#endif

// 設置是否啟用 syslog (1=啟用, 0=控制台)
extern void set_syslog(int syslog);

// 致命錯誤:輸出日志後直接 exit(1)
extern void abort(const char *msg, ...);

// 調試日志:僅 _debug=1 時輸出 (需外部定義 _debug)
extern void log(const char *msg, ...);

// 錯誤日志:輸出到 stderr,不退出
extern void error(const char *msg, ...);

// 信息日志:輸出到 stderr
extern void info(const char *msg, ...);

#ifdef __cplusplus
}
#endif

#endif

實現文件 log.c


#include 
#include 
#include 

#if HAVE_SYSLOG_H
#include 
#endif

// 內部狀態
static int _syslog = 0;      // 是否使用 syslog
// 注意:原代碼中 log() 依賴外部 _debug 變量,此處補全為靜態或擴展接口
static int _debug = 0;       // 調試開關

void set_syslog(int syslog) {
    _syslog = syslog;
}

// 可選:運行時控制調試輸出
void set_debug(int debug) {
    _debug = debug;
}

// 通用格式化輸出核心
static void vlog_internal(int syslog_priority, FILE *fallback_stream, const char *fmt, va_list ap) {
#if HAVE_VSYSLOG
    if (_syslog) {
        vsyslog(syslog_priority, fmt, ap);
        return;
    }
#endif
    vfprintf(fallback_stream, fmt, ap);
}

void abort(const char *msg, ...) {
    va_list ap;
    va_start(ap, msg);
    vlog_internal(LOG_ERR, stdout, msg, ap); // abort 信息輸出到 stdout (或 stderr)
    va_end(ap);
    exit(1);
}

void log(const char *msg, ...) {
    if (!_debug) return; // 調試關閉時零開銷
    va_list ap;
    va_start(ap, msg);
    vlog_internal(LOG_DEBUG, stdout, msg, ap);
    va_end(ap);
}

void error(const char *msg, ...) {
    va_list ap;
    va_start(ap, msg);
    vlog_internal(LOG_ERR, stderr, msg, ap);
    va_end(ap);
}

void info(const char *msg, ...) {
    va_list ap;
    va_start(ap, msg);
    vlog_internal(LOG_INFO, stderr, msg, ap);
    va_end(ap);
}

關鍵設計細節解析

特性 實現方式 優勢
可變參數 va_list + vfprintf/vsyslog 支持 printf 風格格式化,類型安全由編譯器 -Wformat 保證
雙輸出通道 編譯期宏 HAVE_VSYSLOG 判斷,運行期 _syslog 開關 開發期用控制台,生產期切 syslog,零代碼修改
級別語義 abort 致命退出,error/info 輸出 stderr,log 受 _debug 控制 語義清晰,符合 syslog 標準級別 (ERR/DEBUG/INFO)
線程安全 **不保證** (簡單項目通常單線程或自行加鎖) 極簡實現,無鎖開銷。多線程項目需自行包裝 mutex
內存管理 無動態分配,棧上 va_list 零內存洩漏風險,實時性可預測

使用示例


// main.c
#include "log.h"

int _debug = 1; // 開啟調試日志 (若 log.c 中 _debug 為外部變量)

int main() {
    set_syslog(0); // 控制台模式
    // set_syslog(1); // 生產環境啟用 syslog,需編譯時定義 HAVE_SYSLOG_H
    
    info("Server started on port %d", 8080);
    log("Debug: connection from %s:%d", "192.168.1.1", 12345);
    
    int ret = connect_db();
    if (ret != 0) {
        error("DB connect failed: errno=%d", ret);
    }
    
    if (critical_failure()) {
        abort("FATAL: %s", "core dump triggered");
    }
    return 0;
}

編譯與集成


# GCC/Clang
gcc -c log.c -o log.o -DHAVE_SYSLOG_H=1  # 啟用 syslog 支持
# 或
gcc -c log.c -o log.o                    # 純控制台模式

# 鏈接
gcc main.c log.o -o myapp

# CMake 集成
add_library(log STATIC log.c)
target_compile_definitions(log PRIVATE HAVE_SYSLOG_H=1) # 可選
target_include_directories(log PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

擴展方向 (按需引入)

  1. 時間戳:在 vlog_internal 中調用 strftime 格式化時間前綴。
  2. 文件輪轉:fallback_stream 指向 fopen 的文件句柄,定期 fclose/fopen 或按大小切分。
  3. 異步寫入:生產者-消費者隊列 + 專用日志線程,避免 I/O 阻塞主邏輯。
  4. 結構化日志:輸出 JSON 格式,便於 ELK/Fluentd 採集分析。
  5. 編譯期級別過濾:#define LOG_LEVEL LOG_INFO,宏層面消除低級別調用開銷。

總結

本實現以 標準 C (C89/C99)、零第三方依賴、雙通道 (控制台/syslog)、四級語義、可變參數格式化 為核心特性,代碼量極小 (<100 行),完美適配嵌入式、單體服務、CLI 工具等輕量級場景。遵循「做一件事,做好它」的 Unix 哲學,是 C 項目引入日志系統的**最佳起步方案**。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved