// logger.cpp #include "logger.hpp" #include #include #include #include #include #include std::ofstream Logger::log_file; std::string Logger::current_log_filename; void Logger::set_log_to_file(const std::string& filename) { current_log_filename = filename; log_file.open(filename, std::ios::app); if (!log_file.is_open()) { std::cerr << "[Logger] Failed to open log file: " << filename << std::endl; } } std::string Logger::get_time_string() { using namespace std::chrono; auto now = system_clock::now(); auto zt = zoned_time{current_zone(), now}; // 自动使用系统时区(Asia/Shanghai) // 获取毫秒部分 auto ms = duration_cast(zt.get_local_time().time_since_epoch()) % 1000; // 格式化 std::ostringstream ss; ss << format("{:%Y-%m-%d %H:%M:%S}", zt) << '.' << std::setw(3) << std::setfill('0') << ms.count(); return ss.str(); } std::string Logger::get_current_time_utc8() { using namespace std::chrono; auto now = system_clock::now(); zoned_time zt{current_zone(), now}; auto ms = duration_cast(zt.get_local_time().time_since_epoch()) % 1000; std::ostringstream ss; ss << format("{:%Y%m%d%H%M%S}", zt) << std::setw(3) << std::setfill('0') << ms.count(); return ss.str(); } void Logger::log(LogLevel level, const std::string& msg) { std::string level_str; switch (level) { case LogLevel::INFO: level_str = "[INFO] "; break; case LogLevel::WARN: level_str = "[WARN] "; break; case LogLevel::ERROR: level_str = "[ERROR]"; break; } std::string full_msg = get_time_string() + " " + level_str + " " + msg; std::cout << full_msg << std::endl; if (log_file.is_open()) { log_file << full_msg << std::endl; log_file.flush(); // 检查是否需要轮转 if (get_file_size(current_log_filename) >= MAX_LOG_FILE_SIZE) { rotate_logs(); } } } size_t Logger::get_file_size(const std::string& filename) { std::ifstream in(filename, std::ifstream::ate | std::ifstream::binary); return in.is_open() ? static_cast(in.tellg()) : 0; } void Logger::rotate_logs() { log_file.close(); // 删除最旧的日志 std::string oldest = current_log_filename + "." + std::to_string(MAX_LOG_BACKUP_COUNT); std::remove(oldest.c_str()); // 重命名 *.4 -> *.5, ..., *.1 -> *.2 for (int i = MAX_LOG_BACKUP_COUNT - 1; i >= 1; --i) { std::string old_name = current_log_filename + "." + std::to_string(i); std::string new_name = current_log_filename + "." + std::to_string(i + 1); std::rename(old_name.c_str(), new_name.c_str()); } // 当前日志 -> .1 std::string first_backup = current_log_filename + ".1"; std::rename(current_log_filename.c_str(), first_backup.c_str()); // 重新打开新日志 log_file.open(current_log_filename, std::ios::trunc); }