一个轻量高效的C++日志库需支持多级别、线程安全及多输出目标。1. 定义DEBUG/INFO/WARN/ERROR/FATAL五种级别;2. 设计单例Logger类,封装格式化输出与文件/控制台双写入;3. 使用__VA_ARGS__宏自动传入文件名行号,简化调用;4. log函数中通过mutex加锁,按级别过滤并格式化消息写入多目标,确保线程安全。

在C++项目中,一个轻量且高效的日志库能极大提升开发效率和调试能力。实现一个简单的日志系统并不复杂,关键在于设计清晰的接口、支持多级别输出、灵活的输出目标(控制台、文件等),以及线程安全的基础保障。
日志级别用于区分消息的重要程度,常见的有:
可以用枚举来表示:
enum class LogLevel {
DEBUG,
INFO,
WARN,
ERROR,
FATAL
};
核心是封装一个单例的Logger类,提供简洁的调用接口。它应支持格式化输出,并允许同时输出到控制台和文件。
立即学习“C++免费学习笔记(深入)”;
基本结构如下:
class Logger {
public:
static Logger& instance() {
static Logger logger;
return logger;
}
<pre class='brush:php;toolbar:false;'>void set_level(LogLevel level) { log_level_ = level; }
void set_file_output(const std::string& filename);
void log(LogLevel level, const char* file, int line, const char* format, ...);private: LogLevel loglevel = LogLevel::DEBUG; std::FILE* filehandle = nullptr; std::mutex mutex_; // 保证线程安全 };
通过静态instance方法获取唯一实例,避免全局变量污染。log函数使用可变参数处理格式化字符串,类似printf。
直接调用log函数需要手动传入文件名和行号,使用宏可以自动完成:
#define LOG_DEBUG(fmt, ...) \
Logger::instance().log(LogLevel::DEBUG, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define LOG_INFO(fmt, ...) \
Logger::instance().log(LogLevel::INFO, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define LOG_WARN(fmt, ...) \
Logger::instance().log(LogLevel::WARN, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define LOG_ERROR(fmt, ...) \
Logger::instance().log(LogLevel::ERROR, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define LOG_FATAL(fmt, ...) \
Logger::instance().log(LogLevel::FATAL, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
这样在代码中就可以像这样使用:
LOG_INFO("User %s logged in.", username);
LOG_ERROR("Failed to open file: %s", filename);
在log函数中,先判断当前级别是否满足输出条件,再格式化消息并加锁写入:
void Logger::log(LogLevel level, const char* file, int line, const char* format, ...) {
if (level < log_level_) return;
<pre class='brush:php;toolbar:false;'>char time_buf[64];
auto now = std::time(nullptr);
std::strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", std::localtime(&now));
char msg_buf[1024];
va_list args;
va_start(args, format);
vsnprintf(msg_buf, sizeof(msg_buf), format, args);
va_end(args);
std::lock_guard<std::mutex> lock(mutex_);
// 输出到控制台
const char* level_str;
switch (level) {
case LogLevel::DEBUG: level_str = "DEBUG"; break;
case LogLevel::INFO: level_str = "INFO"; break;
case LogLevel::WARN: level_str = "WARN"; break;
case LogLevel::ERROR: level_str = "ERROR"; break;
case LogLevel::FATAL: level_str = "FATAL"; break;
}
printf("[%s] %s:%d %s\n", time_buf, file, line, msg_buf);
// 同时输出到文件(如果开启)
if (file_handle_) {
fprintf(file_handle_, "[%s] %s %s:%d %s\n", time_buf, level_str, file, line, msg_buf);
fflush(file_handle_);
}}
set_file_output函数用于打开日志文件:
void Logger::set_file_output(const std::string& filename) {
if (file_handle_) {
std::fclose(file_handle_);
}
file_handle_ = std::fopen(filename.c_str(), "a");
}
基本上就这些。这个简易日志库已具备实用功能:分级输出、文件位置追踪、时间戳、线程安全、文件持久化。后续可扩展异步写入、滚动日志、颜色输出等功能,但对大多数小项目来说,这个版本已经够用。
以上就是c++++中如何实现一个简单的日志库_C++日志系统设计与实现的详细内容,更多请关注php中文网其它相关文章!
c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号