From 8f47fa7f6813f683b07ffa4ae68bd04b7b4492d6 Mon Sep 17 00:00:00 2001
From: wpz <1249632539@qq.com>
Date: 星期三, 02 七月 2025 15:24:26 +0800
Subject: [PATCH] wpz
---
Server/王鹏哲/code/logger.h | 334 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
Server/王鹏哲/log/日志_王鹏哲_20250701.doc | 0
Server/王鹏哲/log/日志_王鹏哲_20250629.doc | 0
Server/王鹏哲/log/日志_王鹏哲_20250630.doc | 0
4 files changed, 334 insertions(+), 0 deletions(-)
diff --git "a/Server/\347\216\213\351\271\217\345\223\262/code/logger.h" "b/Server/\347\216\213\351\271\217\345\223\262/code/logger.h"
new file mode 100644
index 0000000..10cf437
--- /dev/null
+++ "b/Server/\347\216\213\351\271\217\345\223\262/code/logger.h"
@@ -0,0 +1,334 @@
+#pragma once
+#include "common.h"
+#include <cstring> // 用于strerror
+#include <cstdio> // 用于std::rename, std::remove
+#include <utility> // 用于std::forward
+// 日志级别枚举
+enum class LogLevel {
+ TRACE, // 最详细的跟踪信息
+ DEBUG, // 调试信息
+ INFO, // 常规信息
+ WARNING, // 警告信息
+ ERRORL, // 错误信息
+ FATAL // 严重错误
+};
+
+// 将日志级别转换为字符串
+inline const char* levelToString(LogLevel level) {
+ switch (level) {
+ case LogLevel::TRACE: return "TRACE";
+ case LogLevel::DEBUG: return "DEBUG";
+ case LogLevel::INFO: return "INFO";
+ case LogLevel::WARNING: return "WARNING";
+ case LogLevel::ERRORL: return "ERROR";
+ case LogLevel::FATAL: return "FATAL";
+ default: return "UNKNOWN";
+ }
+}
+
+// 日志配置结构
+struct LogConfig {
+ LogLevel minLevel = LogLevel::INFO; // 最小日志级别
+ bool consoleOutput = true; // 是否输出到控制台
+ bool fileOutput = false; // 是否输出到文件
+ std::string logFilePath = "temp.log";// 日志文件路径
+ bool includeTimestamp = true; // 是否包含时间戳
+ bool includeThreadId = false; // 是否包含线程ID
+ size_t maxFileSize = 10 * 1024 * 1024; // 最大文件大小 (10MB)
+ int maxBackupFiles = 5; // 最大备份文件数
+};
+
+class Logger {
+public:
+ // 获取日志实例
+ static Logger& instance() {
+ static Logger instance;
+ return instance;
+ }
+
+ // 配置日志系统
+ void configure(const LogConfig& config) {
+ std::lock_guard<std::mutex> lock(configMutex_);
+ config_ = config;
+
+ // 如果启用文件输出,确保文件已打开
+ if (config.fileOutput) {
+ openLogFile();
+ }
+ }
+
+ // 记录日志 (模板方法,支持任何可流式输出的类型)
+ template<typename... Args>
+ void log(LogLevel level, Args&&... args) {
+ if (shutdown_) return;
+
+ // 复制配置以最小化锁范围
+ LogConfig currentConfig;
+ {
+ std::lock_guard<std::mutex> lock(configMutex_);
+ if (level < config_.minLevel) return;
+ currentConfig = config_;
+ }
+
+ // 构造日志消息
+ std::ostringstream oss;
+ formatLogPrefix(oss, level, currentConfig);
+
+ using expander = int[];
+ (void)expander {
+ 0, (void(oss << std::forward<Args>(args)), 0)...
+ };
+
+ // 添加换行符
+ oss << '\n';
+ std::string message = oss.str();
+
+ // 直接写入日志
+ /*writeLog(message);*/
+
+ // 将日志消息加入队列
+ {
+ std::lock_guard<std::mutex> lock(queueMutex_);
+ logQueue_.push(std::move(message));
+ }
+
+ // 通知日志线程有新消息
+ queueCond_.notify_one();
+ }
+ // 便捷日志方法
+ template<typename... Args> void trace(Args&&... args) {
+ log(LogLevel::TRACE, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args> void debug(Args&&... args) {
+ log(LogLevel::DEBUG, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args> void info(Args&&... args) {
+ log(LogLevel::INFO, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args> void warning(Args&&... args) {
+ log(LogLevel::WARNING, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args> void error(Args&&... args) {
+ log(LogLevel::ERRORL, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args> void fatal(Args&&... args) {
+ log(LogLevel::FATAL, std::forward<Args>(args)...);
+ flush();
+ std::exit(EXIT_FAILURE);
+ }
+
+ // 刷新日志缓冲区
+ void flush() {
+ std::lock_guard<std::mutex> lock(fileMutex_);
+ if (logFile_.is_open()) {
+ logFile_.flush();
+ }
+ }
+
+ // 析构函数
+ ~Logger() {
+ shutdown();
+ flush();
+ }
+ // 安全关闭日志系统
+ void shutdown() {
+ if (shutdown_) return;
+
+ shutdown_ = true;
+ queueCond_.notify_all(); // 唤醒线程以处理退出
+
+ if (workerThread_.joinable()) {
+ workerThread_.join(); // 等待线程结束
+ }
+
+ flush(); // 最终刷新
+ }
+ // 删除拷贝构造函数和赋值运算符
+ Logger(const Logger&) = delete;
+ Logger& operator=(const Logger&) = delete;
+
+private:
+ LogConfig config_; // 日志配置
+ std::ofstream logFile_; // 日志文件流
+ std::mutex configMutex_; // 配置互斥锁
+ std::mutex fileMutex_; // 文件操作互斥锁
+ std::atomic<bool> shutdown_{ false }; // 关闭标志
+ // 新增线程安全队列相关成员
+ std::queue<std::string> logQueue_; // 日志消息队列
+ std::mutex queueMutex_; // 队列互斥锁
+ std::condition_variable queueCond_; // 队列条件变量
+ std::thread workerThread_; // 日志写入线程
+
+ // 私有构造函数
+ Logger() {
+ // 启动日志写入线程
+ workerThread_ = std::thread(&Logger::processLogs, this);
+ };
+ // 日志处理线程函数
+ void processLogs() {
+ while (true) {
+ std::unique_lock<std::mutex> lock(queueMutex_);
+
+ // 等待新日志或关闭信号
+ queueCond_.wait(lock, [this] {
+ return !logQueue_.empty() || shutdown_;
+ });
+
+ // 处理关闭信号
+ if (shutdown_ && logQueue_.empty()) {
+ break;
+ }
+
+ // 取出所有待处理日志
+ std::queue<std::string> tempQueue;
+ std::swap(logQueue_, tempQueue);
+ lock.unlock();
+
+ // 处理所有取出的日志
+ while (!tempQueue.empty()) {
+ writeLog(tempQueue.front());
+ tempQueue.pop();
+ }
+ }
+ }
+
+ // 格式化日志前缀
+ void formatLogPrefix(std::ostringstream& oss, LogLevel level, const LogConfig& config) {
+ // 日志级别标签
+ oss << "[" << levelToString(level) << "] ";
+
+ // 时间戳
+ if (config.includeTimestamp) {
+ auto now = std::chrono::system_clock::now();
+ auto in_time_t = std::chrono::system_clock::to_time_t(now);
+ auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
+ now.time_since_epoch()) % 1000;
+
+ std::tm tm;
+#ifdef _WIN32
+ localtime_s(&tm, &in_time_t);
+#else
+ localtime_r(&in_time_t, &tm);
+#endif
+
+ oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
+ oss << '.' << std::setfill('0') << std::setw(3) << ms.count() << " ";
+ }
+
+ // 线程ID
+ if (config.includeThreadId) {
+ oss << "[Thread:" << std::this_thread::get_id() << "] ";
+ }
+ }
+
+ // 打开日志文件
+ void openLogFile() {
+ // 关闭当前文件(如果已打开)
+ if (logFile_.is_open()) {
+ logFile_.close();
+ }
+
+ // 检查文件大小,必要时轮转
+ std::ifstream in(config_.logFilePath, std::ios::binary | std::ios::ate);
+ if (in) {
+ auto size = in.tellg();
+ if (static_cast<size_t>(size) >= config_.maxFileSize) {
+ rotateLogFiles();
+ }
+ }
+ in.close();
+
+ // 打开新日志文件
+ logFile_.open(config_.logFilePath, std::ios::out | std::ios::app);
+ if (!logFile_.is_open()) {
+ std::cerr << "Failed to open log file: "
+ << config_.logFilePath << " - "
+ << errno << std::endl;
+ }
+ }
+
+ // 轮转日志文件
+ void rotateLogFiles() {
+ // 删除最旧的备份文件
+ if (config_.maxBackupFiles > 0) {
+ std::string oldestFile = config_.logFilePath + "." + std::to_string(config_.maxBackupFiles);
+ std::remove(oldestFile.c_str());
+
+ // 重命名现有备份文件
+ for (int i = config_.maxBackupFiles - 1; i >= 1; i--) {
+ std::string oldName = config_.logFilePath + "." + std::to_string(i);
+ std::string newName = config_.logFilePath + "." + std::to_string(i + 1);
+
+ if (fileExists(oldName)) {
+ std::rename(oldName.c_str(), newName.c_str());
+ }
+ }
+
+ // 重命名当前日志文件为备份1
+ if (fileExists(config_.logFilePath)) {
+ std::string newName = config_.logFilePath + ".1";
+ std::rename(config_.logFilePath.c_str(), newName.c_str());
+ }
+ }
+ }
+
+ // 检查文件是否存在
+ bool fileExists(const std::string& path) {
+ std::ifstream f(path);
+ return f.good();
+ }
+
+ // 实际写入日志
+ void writeLog(const std::string& message) {
+ LogConfig currentConfig;
+ {
+ std::lock_guard<std::mutex> configLock(configMutex_);
+ currentConfig = config_;
+ }
+
+ // 输出到控制台
+ if (currentConfig.consoleOutput) {
+ if (message.find("[ERROR]") != std::string::npos ||
+ message.find("[FATAL]") != std::string::npos) {
+ std::cerr << message;
+ }
+ else {
+ std::cout << message;
+ }
+ }
+
+ // 输出到文件
+ if (currentConfig.fileOutput) {
+ std::lock_guard<std::mutex> fileLock(fileMutex_);
+ if (!logFile_.is_open() || !logFile_.good()) {
+ openLogFile();
+ }
+
+ if (logFile_.good()) {
+ logFile_ << message;
+ logFile_.flush(); // 实时刷新到磁盘
+
+ // 检查文件大小
+ auto pos = logFile_.tellp();
+ if (static_cast<size_t>(pos) >= currentConfig.maxFileSize) {
+ logFile_.close();
+ rotateLogFiles();
+ logFile_.open(currentConfig.logFilePath, std::ios::out | std::ios::app);
+ }
+ }
+ }
+ }
+};
+
+// 日志宏定义 - 提供文件名和行号信息
+#define LOG_TRACE(...) Logger::instance().trace("(", __FILE__, ":", __LINE__, ") ", __VA_ARGS__)
+#define LOG_DEBUG(...) Logger::instance().debug("(", __FILE__, ":", __LINE__, ") ", __VA_ARGS__)
+#define LOG_INFO(...) Logger::instance().info(__VA_ARGS__)
+#define LOG_WARN(...) Logger::instance().warning("(", __FILE__, ":", __LINE__, ") ", __VA_ARGS__)
+#define LOG_ERROR(...) Logger::instance().error("(", __FILE__, ":", __LINE__, ") ", __VA_ARGS__)
+#define LOG_FATAL(...) Logger::instance().fatal("(", __FILE__, ":", __LINE__, ") ", __VA_ARGS__)
\ No newline at end of file
diff --git "a/Server/\347\216\213\351\271\217\345\223\262/log/\346\227\245\345\277\227_\347\216\213\351\271\217\345\223\262_20250629.doc" "b/Server/\347\216\213\351\271\217\345\223\262/log/\346\227\245\345\277\227_\347\216\213\351\271\217\345\223\262_20250629.doc"
new file mode 100644
index 0000000..25b1c97
--- /dev/null
+++ "b/Server/\347\216\213\351\271\217\345\223\262/log/\346\227\245\345\277\227_\347\216\213\351\271\217\345\223\262_20250629.doc"
Binary files differ
diff --git "a/Server/\347\216\213\351\271\217\345\223\262/log/\346\227\245\345\277\227_\347\216\213\351\271\217\345\223\262_20250630.doc" "b/Server/\347\216\213\351\271\217\345\223\262/log/\346\227\245\345\277\227_\347\216\213\351\271\217\345\223\262_20250630.doc"
new file mode 100644
index 0000000..78def34
--- /dev/null
+++ "b/Server/\347\216\213\351\271\217\345\223\262/log/\346\227\245\345\277\227_\347\216\213\351\271\217\345\223\262_20250630.doc"
Binary files differ
diff --git "a/Server/\347\216\213\351\271\217\345\223\262/log/\346\227\245\345\277\227_\347\216\213\351\271\217\345\223\262_20250701.doc" "b/Server/\347\216\213\351\271\217\345\223\262/log/\346\227\245\345\277\227_\347\216\213\351\271\217\345\223\262_20250701.doc"
new file mode 100644
index 0000000..61462ad
--- /dev/null
+++ "b/Server/\347\216\213\351\271\217\345\223\262/log/\346\227\245\345\277\227_\347\216\213\351\271\217\345\223\262_20250701.doc"
Binary files differ
--
Gitblit v1.8.0