构建高效、线程安全的C++简易日志系统
构建一个高效、线程安全的C++简易日志系统涉及多个方面,包括日志输出、文件写入、格式控制以及线程安全性。同时,保持系统的简洁和易于使用也是重要的。下面是一个基本的设计实现思路,包括代码样例:
基本思路
- 日志级别控制:支持不同的日志级别(如INFO, DEBUG, WARNING, ERROR)。
- 线程安全性:使用互斥锁或其他同步机制确保多线程环境下的安全性。
- 异步日志记录:使用队列和后台线程将日志记录与应用程序主线程解耦,以提高性能。
- 日志格式:支持时间戳、日志级别、源文件名、行号等信息。
- 配置和扩展性:允许用户配置日志输出位置、日志级别等。
代码实现
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <mutex>
#include <thread>
#include <queue>
#include <condition_variable>
#include <atomic>
#include <chrono>
enum class LogLevel {
INFO,
DEBUG,
WARNING,
ERROR
};
class Logger {
public:
Logger(const std::string& filename) : logFile(filename), exitFlag(false) {
logThread = std::thread(&Logger::processEntries, this);
}
~Logger() {
{
std::lock_guard<std::mutex> lock(queueMutex);
exitFlag = true;
queueCondVar.notify_one();
}
if (logThread.joinable()) {
logThread.join();
}
}
void log(LogLevel level, const std::string& message, const char* file, int line) {
std::stringstream ss;
ss << "[" << currentDateTime() << "] "
<< "[" << logLevelToString(level) << "] "
<< "[" << file << ":" << line << "] "
<< message << "\n";
{
std::lock_guard<std::mutex> lock(queueMutex);
logQueue.push(ss.str());
}
queueCondVar.notify_one();
}
private:
std::ofstream logFile;
std::thread logThread;
std::mutex queueMutex;
std::condition_variable queueCondVar;
std::queue<std::string> logQueue;
std::atomic<bool> exitFlag;
void processEntries() {
while (true) {
std::unique_lock<std::mutex> lock(queueMutex);
queueCondVar.wait(lock, [this] { return !logQueue.empty() || exitFlag; });
while (!logQueue.empty()) {
logFile << logQueue.front();
logQueue.pop();
}
if (exitFlag) break;
}
}
std::string logLevelToString(LogLevel level) {
switch (level) {
case LogLevel::INFO: return "INFO";
case LogLevel::DEBUG: return "DEBUG";
case LogLevel::WARNING: return "WARNING";
case LogLevel::ERROR: return "ERROR";
default: return "UNKNOWN";
}
}
std::string currentDateTime() {
std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
char buf[100] = {0};
std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", std::localtime(&now));
return buf;
}
};
// Usage example with a simple logging macro
#define LOG(level, message) LoggerInstance.log(level, message, __FILE__, __LINE__)
int main() {
Logger LoggerInstance("log.txt");
LOG(LogLevel::INFO, "This is an info message");
LOG(LogLevel::DEBUG, "Debugging the application");
LOG(LogLevel::WARNING, "This is a warning");
LOG(LogLevel::ERROR, "An error occurred");
return 0;
}
说明
- LogLevel: 使用枚举表示不同的日志级别。
- Logger类: 负责日志文件的打开和写入,使用线程和条件变量实现异步日志处理。
- log方法: 将日志消息格式化并加入队列。
- processEntries方法: 由独立线程运行,负责从队列中取出日志并写入文件。
- 线程安全: 使用
std::mutex
和std::condition_variable
确保队列操作的线程安全性。 - 日志格式: 包含时间、级别、文件名和行号的信息。
这个系统提供了一个简单高效的日志解决方案,在需要时可以扩展或调整以满足更复杂的需求。