C++ 轻量级日志系统

C++ 轻量级日志系统(完整版)

Logger.h

cpp 复制代码
#ifndef LOGGER_H
#define LOGGER_H

#include <string>
#include <fstream>
#include <mutex>
#include <ctime>

// 日志等级
enum LogLevel {
    DEBUG,
    INFO,
    WARNING,
    ERROR,
    FATAL
};

class Logger {
public:
    static Logger& instance();

    // 设置输出文件(不设置则只输出控制台)
    void setLogFile(const std::string& filename);

    // 核心日志输出
    void log(LogLevel level, const char* file, int line, const char* format, ...);

private:
    Logger();
    ~Logger();

    std::string getLevelStr(LogLevel level);
    std::string getTime();
    void printColor(LogLevel level);

    std::ofstream m_file;
    std::mutex m_mutex;
    bool m_useFile;
};

// 宏定义,简化调用
#define LOGD(...) Logger::instance().log(DEBUG, __FILE__, __LINE__, __VA_ARGS__)
#define LOGI(...) Logger::instance().log(INFO, __FILE__, __LINE__, __VA_ARGS__)
#define LOGW(...) Logger::instance().log(WARNING, __FILE__, __LINE__, __VA_ARGS__)
#define LOGE(...) Logger::instance().log(ERROR, __FILE__, __LINE__, __VA_ARGS__)
#define LOGF(...) Logger::instance().log(FATAL, __FILE__, __LINE__, __VA_ARGS__)

#endif // LOGGER_H

Logger.cpp

cpp 复制代码
#include "Logger.h"
#include <cstdarg>
#include <iostream>
#include <iomanip>

#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif

Logger::Logger() : m_useFile(false) {}
Logger::~Logger() {
    if (m_file.is_open()) m_file.close();
}

Logger& Logger::instance() {
    static Logger logger;
    return logger;
}

void Logger::setLogFile(const std::string& filename) {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_file.is_open()) m_file.close();
    m_file.open(filename, std::ios::out | std::ios::app);
    m_useFile = m_file.is_open();
}

std::string Logger::getLevelStr(LogLevel level) {
    switch (level) {
        case DEBUG: return "DEBUG";
        case INFO:  return "INFO ";
        case WARNING: return "WARN ";
        case ERROR: return "ERROR";
        case FATAL: return "FATAL";
        default: return "UNKNOWN";
    }
}

std::string Logger::getTime() {
    char buf[64];
    time_t now = time(nullptr);
    tm t{};
#ifdef _WIN32
    localtime_s(&t, &now);
#else
    localtime_r(&now, &t);
#endif
    strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &t);
    return buf;
}

void Logger::printColor(LogLevel level) {
#ifdef _WIN32
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    switch (level) {
        case DEBUG: SetConsoleTextAttribute(hConsole, FOREGROUND_GREEN); break;
        case INFO:  SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); break;
        case WARNING: SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN); break;
        case ERROR: SetConsoleTextAttribute(hConsole, FOREGROUND_RED); break;
        case FATAL: SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_INTENSITY); break;
        default: SetConsoleTextAttribute(hConsole, 7);
    }
#else
    switch (level) {
        case DEBUG: std::cout << "\033[32m"; break;
        case INFO:  std::cout << "\033[0m"; break;
        case WARNING: std::cout << "\033[33m"; break;
        case ERROR: std::cout << "\033[31m"; break;
        case FATAL: std::cout << "\033[35m"; break;
        default: std::cout << "\033[0m";
    }
#endif
}

void Logger::log(LogLevel level, const char* file, int line, const char* format, ...) {
    std::lock_guard<std::mutex> lock(m_mutex);

    // 颜色
    printColor(level);

    // 头部:时间 等级 [文件:行号]
    std::string head = "[" + getTime() + "] [" + getLevelStr(level) + "] ["
                     + std::string(file) + ":" + std::to_string(line) + "] ";

    // 输出到控制台
    std::cout << head;

    // 格式化内容
    char buf[1024];
    va_list args;
    va_start(args, format);
    vsnprintf(buf, sizeof(buf), format, args);
    va_end(args);

    std::cout << buf << "\033[0m" << std::endl;

    // 输出到文件
    if (m_useFile) {
        m_file << head << buf << std::endl;
        m_file.flush();
    }
}

使用示例(main.cpp)

cpp 复制代码
#include "Logger.h"

int main() {
    // 可选:输出到日志文件
    Logger::instance().setLogFile("app.log");

    LOGD("这是调试信息,数字=%d,字符串=%s", 123, "测试");
    LOGI("程序启动成功");
    LOGW("内存占用偏高");
    LOGE("打开文件失败");
    LOGF("程序崩溃,即将退出");

    return 0;
}

效果展示

  • 控制台彩色显示
  • 每条日志带:时间 + 等级 + 文件名 + 行号 + 内容
  • 同时可输出到文件
  • 线程安全,多线程随便用

相关推荐
_wyt00110 小时前
洛谷 B3930 [GESP202312 五级] 烹饪问题 题解
c++·gesp
LDR00612 小时前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术12 小时前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript
码云数智-园园12 小时前
C++20 Modules 模块详解
java·开发语言·spring
swordbob13 小时前
NIO的channel中什么是 fd(File Descriptor,文件描述符)
java·开发语言·nio
源分享13 小时前
Java线程同步的多种实现方法(非常详细)
java·开发语言·jvm
Luminous.13 小时前
C语言--day30
c语言·开发语言
玖玥拾14 小时前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
何以解忧,唯有..14 小时前
Go语言循环语句详解:for、range与循环控制
开发语言·算法·golang
謓泽14 小时前
C语言不是语法,是通往机器的地图。
c语言·开发语言