/** * log_manager.h - 内存日志缓冲管理系统 * fix24 v36: 日志写入内存,定时刷盘,Web从内存读取 */ #ifndef LOG_MANAGER_H #define LOG_MANAGER_H #include #include #include #include #include #include // ==================== 日志条目结构 ==================== struct LogEntry { std::string timestamp; // "2026-07-05 23:15:00" std::string level; // INFO / WARN / ERROR std::string message; // 日志内容(单行) size_t byte_size; // 该条目占用内存字节数 LogEntry() : byte_size(0) {} LogEntry(const std::string& ts, const std::string& lv, const std::string& msg) : timestamp(ts), level(lv), message(msg) { byte_size = ts.size() + lv.size() + msg.size() + 32; // overhead } }; // ==================== 日志状态(Web API返回) ==================== struct LogStatus { std::string log_file_path; // 日志文件路径 long file_size_mb; // 磁盘文件大小 (MB) long buffer_size_mb; // 缓冲区上限配置 (MB) double buffer_usage_percent; // 缓冲区使用率 (%) std::string flush_time; // 定时刷盘时间 int retention_days; // 保留天数 long line_count; // 内存中总条数 std::string last_modified; // 最后修改时间(文件/刷盘) bool redirect_enabled; // stdout 重定向是否启用 bool memory_enabled; // 内存模式是否启用 long memory_usage_bytes; // 当前内存占用(字节) std::string last_flush_time; // 上次刷盘时间 long total_flush_count; // 累计刷盘次数 }; // ==================== 内存日志缓冲区 ==================== class MemoryLogBuffer { public: MemoryLogBuffer(); ~MemoryLogBuffer(); // 初始化(从config读取参数后调用) void init(size_t max_bytes, const std::string& flush_time, const std::string& log_file, int retention_days, bool redirect_stdout, bool auto_flush_on_exit); // 启动(创建刷盘线程 + stdout重定向) bool start(); // 停止(刷盘 + 关闭线程) void stop(); // 写入日志条目 void push(const std::string& level, const std::string& message); // 获取最后N条 std::deque tail(int n); // 获取状态 LogStatus get_status(); // 手动刷盘到文件 bool flush_to_file(std::string& error); // 清理过期日志 bool cleanup_old_logs(std::string& error); // 信号处理调用(SIGTERM/SIGINT时调用) void signal_flush(); // 全局单例 static MemoryLogBuffer& instance(); private: // 刷盘线程 void flush_thread_func(); // stdout读取线程(当redirect_stdout=true时) void stdout_reader_func(); // 解析刷盘时间 "HH:MM" → 时、分 bool parse_flush_time(const std::string& time_str, int& hour, int& minute); // 生成带日期的归档文件名 std::string generate_archive_filename(); // 获取当前时间字符串 std::string current_timestamp(); // 环形缓冲区 std::deque buffer_; size_t max_memory_bytes_; size_t current_bytes_; std::mutex mutex_; // 配置 std::string log_file_; // PlateRecApp.log std::string flush_time_; // "23:20" int retention_days_; bool redirect_stdout_; bool auto_flush_on_exit_; bool enabled_; // enabled=1 内存模式, =0 直写模式 // 刷盘线程 std::thread flush_thread_; std::mutex flush_mutex_; std::condition_variable flush_cv_; std::atomic flush_running_; // stdout重定向 std::thread stdout_thread_; int pipe_fd_[2]; // pipefd[0]=读端, pipefd[1]=写端 int saved_stdout_; // 备份原始stdout fd int saved_stderr_; // 备份原始stderr fd std::atomic stdout_redirect_active_; // 统计 std::atomic total_flush_count_; std::string last_flush_time_; std::mutex stats_mutex_; }; // ==================== 兼容旧接口(namespace log_mgr) ==================== namespace log_mgr { // 获取日志状态 LogStatus get_log_status(); // 手动触发日志刷新(sync) bool flush_log(std::string &error); // 清理过期日志 bool cleanup_old_logs(std::string &error); // 获取日志文件最后 N 行 std::string tail_log(int lines); } // namespace log_mgr #endif // LOG_MANAGER_H