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;
}
效果展示
- 控制台彩色显示
- 每条日志带:时间 + 等级 + 文件名 + 行号 + 内容
- 同时可输出到文件
- 线程安全,多线程随便用