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;
}

效果展示

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

相关推荐
小技与小术4 小时前
玩转Flask
开发语言·python·flask
SilentSamsara4 小时前
Python 性能优化:tracemalloc、profiling 与 C 扩展加速
开发语言·python·青少年编程·性能优化
冰小忆5 小时前
大驼峰命名规范和小驼峰命名规范的区别是什么?
开发语言·python
এ慕ོ冬℘゜6 小时前
JS 前端基础面试题
开发语言·前端·javascript
浩少7026 小时前
【无标题】
java·开发语言
nnsix7 小时前
C# 字符串 根据换行符分割
开发语言·c#
Vallelonga7 小时前
Rust Conversion 工具 trait AsRef AsMut
开发语言·rust
王老师青少年编程7 小时前
2026年全国青少年信息素养大赛初赛真题(算法应用主题赛C++初中组初赛真题3:文末附答案和解析)
c++·真题·答案·初赛·2026年·青少年信息素养大赛·初中组
Vallelonga7 小时前
Rust 中的“解引用”和智能指针与 MutexGuard 等
开发语言·rust