From 3ef3367fb535a41f08ff5ea87a62849d661a45e0 Mon Sep 17 00:00:00 2001
From: user_ch-ml <1303079376@qq.com>
Date: 星期三, 02 七月 2025 15:59:58 +0800
Subject: [PATCH] Merge branch 'master' of ssh://115.28.86.8:29418/~admin/智能网联_25-0305_617_v1

---
 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