#include "rdp_log.h" #include "parameters.h" #include #include #include #include namespace { //日志模块内部状态:日志文件流 + 重定向前 std::cout 的原始缓冲区 struct RdpLogState { std::ofstream file; //日志文件输出流 std::streambuf *original_buf; //重定向前 std::cout 的原始缓冲区 bool enabled; //是否已成功重定向到日志文件 RdpLogState() : original_buf(0), enabled(false) {} ~RdpLogState() { //进程退出兜底:若宿主进程未调用 Data_Process_Factory::Destroy(), //此处恢复 std::cout,避免其仍指向即将析构的日志文件流缓冲区。 if (enabled && original_buf) { std::cout.rdbuf(original_buf); enabled = false; } } }; RdpLogState &State() { static RdpLogState s; return s; } //当前本地时间字符串,格式 "YYYY-MM-DD HH:MM:SS" std::string CurrentTime() { char buf[32] = {0}; time_t now = time(NULL); struct tm local; if (localtime_s(&local, &now) != 0) { return std::string(); } strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &local); return std::string(buf); } //提取纯文件名(去掉路径前缀),日志前缀中只显示 文件名:行号 const char *FileName(const char *path) { if (path == 0) { return ""; } const char *base = path; for (const char *p = path; *p != '\0'; ++p) { if (*p == '\\' || *p == '/') { base = p + 1; } } return base; } } namespace rdp_log { bool Init() { RdpLogState &st = State(); if (st.enabled) { return true; //已经重定向,避免重复初始化 } #ifdef RDP_LOG_ENABLE //创建日志目录(目录已存在时 _mkdir 返回 EEXIST,忽略) std::string log_dir = RDP_LOG_DIR; while (log_dir.size() > 0 && (log_dir[log_dir.size() - 1] == '\\' || log_dir[log_dir.size() - 1] == '/')) { log_dir.erase(log_dir.size() - 1); } if (log_dir.size() > 0) { _mkdir(log_dir.c_str()); } //按当前日期+时间生成日志文件名:rdp_YYYYMMDD_HHMMSS.log char time_buf[32] = {0}; time_t now = time(NULL); struct tm local; if (localtime_s(&local, &now) != 0) { return false; } strftime(time_buf, sizeof(time_buf), "%Y%m%d_%H%M%S", &local); std::string log_path = RDP_LOG_DIR; log_path += "rdp_"; log_path += time_buf; log_path += ".log"; st.file.open(log_path.c_str(), std::ios::out | std::ios::trunc); if (!st.file.is_open()) { //日志文件打开失败(目录不可写等):保持控制台输出,不做重定向 std::cout << "[rdp_log] cannot open log file: " << log_path << std::endl; return false; } //用 rdbuf() 将 std::cout 的流缓冲区替换为日志文件输出流 st.original_buf = std::cout.rdbuf(); std::cout.rdbuf(st.file.rdbuf()); st.enabled = true; //重定向成功后写入起始标记(该行已写入日志文件) std::cout << prefix(__FILE__, __LINE__) << "rdp_log enabled, log file: " << log_path << std::endl; return true; #else //日志开关关闭:不重定向,日志仍输出到标准输出 return false; #endif } void Shutdown() { RdpLogState &st = State(); if (!st.enabled) { return; } //写入结束标记后刷新、恢复 std::cout 并关闭日志文件 std::cout << prefix(__FILE__, __LINE__) << "rdp_log shutdown" << std::endl; st.file.flush(); std::cout.rdbuf(st.original_buf); st.enabled = false; st.file.close(); } std::string prefix(const char *file, int line) { std::ostringstream oss; oss << "[" << CurrentTime() << "][" << FileName(file) << ":" << line << "] "; return oss.str(); } }