该日志服务器是基于双缓冲区来接收并且写入日志,采用了单例模式,线程,信号量,文件流机制,并且能根据日志文件大小重写创建文件并且写入(采用c++17)
#include <iostream>
#include <fstream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <chrono>
#include <ctime>
#include <stdexcept>
#include <string>
#include <filesystem>
class AsyncLogger {
public:
// 获取单例实例
static AsyncLogger& getInstance() {
static AsyncLogger instance;
return instance;
}
// 删除拷贝构造和赋值运算符
AsyncLogger(const AsyncLogger&) = delete;
AsyncLogger& operator=(const AsyncLogger&) = delete;
// 日志接口
void info(const std::string& message) {
log("INFO", message);
}
void error(const std::string& message) {
log("ERROR", message);
}
void debug(const std::string& message) {
log("DEBUG", message);
}
private:
AsyncLogger() : exit_flag(false), max_file_size(10 * 1024 * 1024) { // 10MB
openLogFile();
// 启动日志线程
log_thread = std::thread(&AsyncLogger::processLogs, this);
}
~AsyncLogger() {
{
std::unique_lock<std::mutex> lock(queue_mutex);
exit_flag = true;
}
cv.notify_all();
if (log_thread.joinable())
log_thread.join();
if (log_file.is_open())
log_file.close();
}
// 打开日志文件
void openLogFile() {
if (log_file.is_open()) {
log_file.close();
}
log_file.open("application.log", std::ios::out | std::ios::app);
if (!log_file.is_open()) {
throw std::runtime_error("无法打开日志文件");
}
}
// 检查日志文件大小
void checkLogFileSize() {
if (log_file.tellp() >= max_file_size) {
log_file.close();
// 重命名当前日志文件
std::string new_file_name = "application_" + getTimestamp() + ".log";
std::filesystem::rename("application.log", new_file_name);
openLogFile(); // 重新打开新的日志文件
}
}
// 日志记录函数
void log(const std::string& level, const std::string& message) {
std::string timestamp = getTimestamp();
std::unique_lock<std::mutex> lock(queue_mutex);
active_buffer.emplace("[" + timestamp + "] [" + level + "] " + message + "\n");
cv.notify_one();
}
// 处理日志的线程函数
void processLogs() {
while (true) {
std::queue<std::string> local_queue;
{
std::unique_lock<std::mutex> lock(queue_mutex);
// 等待有日志或退出信号
cv.wait(lock, [this] { return exit_flag || !active_buffer.empty(); });
if (exit_flag && active_buffer.empty())
break;
// 交换缓冲区
std::swap(active_buffer, local_queue);
}
// 将日志写入文件
while (!local_queue.empty()) {
checkLogFileSize(); // 检查文件大小
log_file << local_queue.front();
local_queue.pop();
}
// 确保日志被写入磁盘
log_file.flush();
}
}
// 获取当前时间戳
std::string getTimestamp() {
auto now = std::chrono::system_clock::now();
std::time_t now_time = std::chrono::system_clock::to_time_t(now);
char buf[20];
std::strftime(buf, sizeof(buf), "%Y%m%d_%H%M%S", std::localtime(&now_time)); // 格式化为适合文件名的形式
return std::string(buf);
}
std::ofstream log_file;
std::queue<std::string> active_buffer;
std::mutex queue_mutex;
std::condition_variable cv;
std::thread log_thread;
bool exit_flag;
const std::streamoff max_file_size; // 最大文件大小
};