侧边栏壁纸
博主头像
我的学习和日常生活记录

行动起来,活在当下

  • 累计撰写 87 篇文章
  • 累计创建 49 个标签
  • 累计收到 5 条评论

目 录CONTENT

文章目录

C/C++简易版本日志库(HeaderOnly)

Administrator
2025-06-19 / 0 评论 / 0 点赞 / 5 阅读 / 0 字 / 正在检测是否收录...
// log.h
#ifndef LOG_H
#define LOG_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>

// 平台检测
#if defined(_WIN32) || defined(_WIN64)
#define OS_WINDOWS 1
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <windows.h>
#define open _open
#define write _write
#define close _close
#define fsync _commit
#define STDERR_FILENO 2
#else
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#endif

// 日志级别定义
typedef enum
{
    LOG_DEBUG,
    LOG_INFO,
    LOG_WARNING,
    LOG_ERROR
} LogLevel;

// 全局日志文件描述符
static int log_fd = -1;
static LogLevel log_level = LOG_INFO;

// 初始化日志系统
static int log_init(const char *filename, LogLevel level)
{
    int flags = 0;
    int mode = 0;
    log_level = level;

    if (filename == NULL)
    {
        log_fd = STDERR_FILENO; // 默认输出到标准错误
        return 0;
    }

    // Windows 和 Linux 的文件打开标志处理
#ifdef OS_WINDOWS
    flags = _O_WRONLY | _O_CREAT | _O_APPEND | _O_BINARY;
    mode = _S_IREAD | _S_IWRITE;
#else
    flags = O_WRONLY | O_CREAT | O_APPEND;
    mode = 0644;
#endif
    // 打开日志文件
    log_fd = open(filename, flags, mode);
    if (log_fd < 0)
    {
#ifdef OS_WINDOWS
        char error[256];
        strerror_s(error, sizeof(error), errno);
        fprintf(stderr, "log_init failed: %s\n", error);
#else
        perror("log_init failed");
#endif
        return -1;
    }
    return 0;
}

// 关闭日志系统
static void log_close()
{
    if (log_fd >= 0 && log_fd != STDERR_FILENO)
    {
        close(log_fd);
        log_fd = -1;
    }
}

// 核心日志函数
static void log_write(LogLevel level, const char *file, int line, const char *format, ...)
{
    char header[256];
    // 获取当前时间
    time_t now = time(NULL);
    struct tm tm_now;
    // 日志级别字符串
    const char *level_str = "UNKNOWN";
    int header_len = 0;
    int msg_len = 0;
    char msg[1024];
    char log_line[2048];
    va_list args;
    if (level < log_level || log_fd < 0)
        return;

#ifdef OS_WINDOWS
    localtime_s(&tm_now, &now);
#else
    localtime_r(&now, &tm_now);
#endif

    switch (level)
    {
    case LOG_DEBUG:
        level_str = "DEBUG";
        break;
    case LOG_INFO:
        level_str = "INFO";
        break;
    case LOG_WARNING:
        level_str = "WARN";
        break;
    case LOG_ERROR:
        level_str = "ERROR";
        break;
    }
    // 构建日志头

    header_len = snprintf(header, sizeof(header),
                          "[%04d-%02d-%02d %02d:%02d:%02d] [%s] [%s:%d] ",
                          tm_now.tm_year + 1900, tm_now.tm_mon + 1, tm_now.tm_mday,
                          tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec,
                          level_str, file, line);

    // 处理可变参数

    va_start(args, format);
    msg_len = vsnprintf(msg, sizeof(msg), format, args);
    va_end(args);

    // 确保消息不会溢出缓冲区
    if (msg_len < 0)
        return;
    if (msg_len >= (int)sizeof(msg))
    {
        msg[sizeof(msg) - 1] = '\0';
        msg_len = (int)sizeof(msg) - 1;
    }

    // 组合完整日志
    memcpy(log_line, header, header_len);
    memcpy(log_line + header_len, msg, msg_len);

    // 添加换行符
    log_line[header_len + msg_len] = '\n';

    // 写入日志
    write(log_fd, log_line, header_len + msg_len + 1);
#ifndef OS_WINDOWS
    // Windows 的 _commit 在 fsync 时已经调用
    fsync(log_fd);
#endif
}

// 简化日志宏
#define LOG(level, ...) log_write(level, __FILE__, __LINE__, __VA_ARGS__)
#define LOG_DEBUG(...) LOG(LOG_DEBUG, __VA_ARGS__)
#define LOG_INFO(...) LOG(LOG_INFO, __VA_ARGS__)
#define LOG_WARNING(...) LOG(LOG_WARNING, __VA_ARGS__)
#define LOG_ERROR(...) LOG(LOG_ERROR, __VA_ARGS__)

#endif // LOG_H

0

评论区