#include "Log4CPP.h" #include // 用于目录创建 #include // 用于字符串转换 #include // 用于字符串转换 #include #include #include #include #include #include #include // 添加strerror支持 #include #include "ResDataObject.h" Log4CPP* Log4CPP::instance = NULL; std::string Log4CPP::_screenInfo = "screenInfo"; std::string Log4CPP::_logName = "log"; // 初始化配置 LogConfig Log4CPP::config; log4cpp::Category& root = log4cpp::Category::getRoot(); log4cpp::Category& Log4CPP::logCat = root.getInstance(Log4CPP::_logName); log4cpp::Category& Log4CPP::coutCat = root.getInstance(Log4CPP::_screenInfo); // 优先级 log4cpp::Priority::PriorityLevel Log4CPP::coutPri = COUNT_PRITY; // 控制台 log4cpp::Priority::PriorityLevel Log4CPP::logPri = LOG_PRITY; // 本地文件 log4cpp::PatternLayout* Log4CPP::logLayout = NULL; log4cpp::PatternLayout* Log4CPP::screenLayout = NULL; log4cpp::PatternLayout* Log4CPP::logLayout2 = NULL; /* 回卷用这个 */ log4cpp::FileAppender* Log4CPP::logFile = NULL;//文件日志输入 log4cpp::OstreamAppender* Log4CPP::logScreen = NULL;//屏幕日志输入 log4cpp::RollingFileAppender* Log4CPP::rollLogFile; /* 回卷用这个 */ // 创建目录函数 bool Log4CPP::createDirectory(const std::string& path) { struct stat st; if (stat(path.c_str(), &st) == 0) { if (S_ISDIR(st.st_mode)) { return true; // 目录已存在 } return false; // 存在同名文件 } // 递归创建目录 size_t pos = 0; do { pos = path.find_first_of('/', pos + 1); std::string subdir = path.substr(0, pos); if (mkdir(subdir.c_str(), 0755) != 0) { if (errno != EEXIST) { std::cerr << "Failed to create directory: " << subdir << " Error: " << strerror(errno) << std::endl; return false; } } } while (pos != std::string::npos); return true; } // 解析日志级别 log4cpp::Priority::PriorityLevel Log4CPP::parseLogLevel(const std::string& level) { std::string upper; std::transform(level.begin(), level.end(), std::back_inserter(upper), ::toupper); if (upper == "EMERG") return log4cpp::Priority::EMERG; if (upper == "FATAL") return log4cpp::Priority::FATAL; if (upper == "ALERT") return log4cpp::Priority::ALERT; if (upper == "CRIT") return log4cpp::Priority::CRIT; if (upper == "ERROR") return log4cpp::Priority::ERROR; if (upper == "WARN") return log4cpp::Priority::WARN; if (upper == "NOTICE") return log4cpp::Priority::NOTICE; if (upper == "INFO") return log4cpp::Priority::INFO; if (upper == "DEBUG") return log4cpp::Priority::DEBUG; if (upper == "NOTSET") return log4cpp::Priority::NOTSET; std::cerr << "Unknown log level: " << level << ". Using DEBUG as default." << std::endl; return log4cpp::Priority::DEBUG; } // 加载配置文件 bool Log4CPP::loadConfig(const std::string& configFile) { // 读取基本配置 ResDataObject temp; if (!temp.loadFile(configFile.c_str())) { std::cerr << "Failed to load log config file: " << configFile << ". Using default settings." << std::endl; return false; } // 获取log_config节点 ResDataObject LogConfig = temp["log_config"]; // 读取基本配置 - 修复变量名错误 if (LogConfig.GetKeyCount("root_level")) { config.root_level = (std::string)LogConfig["root_level"]; std::cout << "Log4CPP::loadConfig: config.root_level:" << config.root_level << std::endl; } if (LogConfig.GetKeyCount("log_dir")) { config.log_dir = (std::string)LogConfig["log_dir"]; std::cout << "Log4CPP::loadConfig: config.log_dir:" << config.log_dir << std::endl; } if (LogConfig.GetKeyCount("history_dir")) { config.history_dir = (std::string)LogConfig["history_dir"]; std::cout << "Log4CPP::loadConfig: config.history_dir:" << config.history_dir << std::endl; } if (LogConfig.GetKeyCount("max_file_size")) { config.max_file_size = (size_t)(int)LogConfig["max_file_size"]; std::cout << "Log4CPP::loadConfig: config.max_file_size:" << config.max_file_size << std::endl; } if (LogConfig.GetKeyCount("max_backups")) { config.max_backups = (int)LogConfig["max_backups"]; std::cout << "Log4CPP::loadConfig: config.max_backups:" << config.max_backups << std::endl; } if (LogConfig.GetKeyCount("file_pattern")) { config.file_pattern = (std::string)LogConfig["file_pattern"]; std::cout << "Log4CPP::loadConfig: config.file_pattern:" << config.file_pattern << std::endl; } if (LogConfig.GetKeyCount("console_pattern")) { config.console_pattern = (std::string)LogConfig["console_pattern"]; std::cout << "Log4CPP::loadConfig: config.console_pattern:" << config.console_pattern << std::endl; } // 创建日志目录 if (!createDirectory(config.log_dir)) { std::cerr << "Failed to create log directory: " << config.log_dir << std::endl; } if (!createDirectory(config.history_dir)) { std::cerr << "Failed to create history directory: " << config.history_dir << std::endl; } return true; } bool Log4CPP::init(const std::string& configFile, std::string logName, bool toScreen) { // 加载配置文件 if (!loadConfig(configFile)) { std::cerr << "Log4CPP::init: Failed to load config, using defaults" << std::endl; } std::cout << "Log4CPP::init: Config loaded" << std::endl; // 解析日志级别 Log4CPP::coutPri = parseLogLevel(config.root_level); Log4CPP::logPri = parseLogLevel(config.root_level); std::cout << "Log4CPP::init: Log levels parsed" << std::endl; if (Log4CPP::instance == NULL) { Log4CPP::instance = new Log4CPP(toScreen); // 使用配置的日志目录 std::string year, month, day, hour, min, sec; getCurrentTime(year, month, day, hour, min, sec); std::string logPath = config.log_dir + "/" + logName + "." + year + month + day + ".log"; Log4CPP::_logName = logPath; log4cpp::Category& logCat = root.getInstance(Log4CPP::_logName); log4cpp::Category& coutCat = root.getInstance(Log4CPP::_screenInfo); logScreen = new log4cpp::OstreamAppender("logScreen", &std::cout); logFile = new log4cpp::FileAppender("logFile", Log4CPP::_logName); /* 然后注释这个 */ //rollLogFile = new log4cpp::RollingFileAppender("rollLogFile", Log4CPP::_logName, 1024*1024, 5); /* 回卷用这个 */ // 单个日志文件大小1M,5个回卷 //设置布局 Log4CPP::logLayout = new log4cpp::PatternLayout(); /* 然后注释这个 */ Log4CPP::screenLayout = new log4cpp::PatternLayout(); Log4CPP::logLayout2 = new log4cpp::PatternLayout(); /* 回卷用这个 */ // 设置日志格式 Log4CPP::logLayout->setConversionPattern(config.file_pattern.c_str()); Log4CPP::screenLayout->setConversionPattern(config.console_pattern.c_str()); Log4CPP::logLayout2->setConversionPattern(config.file_pattern.c_str()); Log4CPP::logScreen->setLayout(screenLayout); Log4CPP::logFile->setLayout(logLayout); /* 然后注释这个 */ //Log4CPP::rollLogFile->setLayout(logLayout2); /* 回卷用这个 */ std::cout << "Log4CPP::init: Setting layouts" << std::endl; //追加到目录 Log4CPP::logCat.addAppender(Log4CPP::logFile); /* 然后注释这个 */ //Log4CPP::logCat.addAppender(Log4CPP::rollLogFile); /* 回卷用这个 */ Log4CPP::coutCat.addAppender(Log4CPP::logScreen); //设置优先级 Log4CPP::logCat.setPriority(Log4CPP::logPri); Log4CPP::coutCat.setPriority(Log4CPP::coutPri); } Log4CPP::instance->outToScreen = toScreen; return true; } //获取日志函数,默认参数选择是否输出到屏幕 Log4CPP* Log4CPP::getLog(bool toScreen) { Log4CPP::instance->outToScreen = toScreen; if (NULL == Log4CPP::instance) { printf("Log4CPP::log is NULL, please use Log4CPP::init!\n"); return NULL; } return Log4CPP::instance; } //销毁日志对象 void Log4CPP::destoryLog() { log4cpp::Category::shutdown(); delete Log4CPP::instance; } //设置日志记录优先级 void Log4CPP::setPri(log4cpp::Priority::PriorityLevel coutLevel, log4cpp::Priority::PriorityLevel logLevel) { Log4CPP::logPri = logLevel; Log4CPP::coutPri = coutLevel; Log4CPP::logCat.setPriority(Log4CPP::logPri); Log4CPP::coutCat.setPriority(Log4CPP::coutPri); } // 辅助函数:格式化消息 std::string Log4CPP::formatMessage(const char* format, va_list args) { char buffer[4096]; vsnprintf(buffer, sizeof(buffer), format, args); return std::string(buffer); } // 类型转换函数 template std::string Log4CPP::toString(const T& value) { std::ostringstream oss; oss << value; return oss.str(); } // 指针特化 std::string Log4CPP::toString(const void* value) { std::ostringstream oss; oss << "0x" << std::hex << reinterpret_cast(value); return oss.str(); } // 布尔值特化 std::string Log4CPP::toString(bool value) { return value ? "true" : "false"; } // 修改后的日志函数 void Log4CPP::warn(int line, const char* function, const char* format, ...) { char info[4096] = { 0 }; snprintf(info, sizeof(info), "[%s][%d]: ", function, line); va_list args; va_start(args, format); std::string formatted = formatMessage(format, args); va_end(args); std::string message = info + formatted; if (outToScreen) { logCat.warn(message); coutCat.warn(message); } else { logCat.warn(message); } } // 其他日志函数实现类似 void Log4CPP::error(int line, const char* function, const char* format, ...) { char info[4096] = { 0 }; snprintf(info, sizeof(info), "[%s][%d]: ", function, line); va_list args; va_start(args, format); std::string formatted = formatMessage(format, args); va_end(args); std::string message = info + formatted; if (outToScreen) { logCat.error(message); coutCat.error(message); } else { logCat.error(message); } } void Log4CPP::debug(int line, const char* function, const char* format, ...) { char info[4096] = { 0 }; snprintf(info, sizeof(info), "[%s][%d]: ", function, line); va_list args; va_start(args, format); std::string formatted = formatMessage(format, args); va_end(args); std::string message = info + formatted; if (outToScreen) { logCat.debug(message); coutCat.debug(message); } else { logCat.debug(message); } } void Log4CPP::info(int line, const char* function, const char* format, ...) { char info[4096] = { 0 }; snprintf(info, sizeof(info), "[%s][%d]: ", function, line); va_list args; va_start(args, format); std::string formatted = formatMessage(format, args); va_end(args); std::string message = info + formatted; if (outToScreen) { logCat.info(message); coutCat.info(message); } else { logCat.info(message); } } std::string Log4CPP::getCurrentTime(std::string& year, std::string& month, std::string& day, std::string& hour, std::string& min, std::string& sec) { // 获取系统时间 - 年月日时分秒 time_t _time; struct tm* target_time; time(&_time); target_time = localtime(&_time); year = std::to_string(target_time->tm_year + 1900); month = target_time->tm_mon + 1 > 9 ? std::to_string(target_time->tm_mon + 1) : "0" + std::to_string(target_time->tm_mon + 1); day = target_time->tm_mday > 9 ? std::to_string(target_time->tm_mday) : "0" + std::to_string(target_time->tm_mday); hour = target_time->tm_hour > 9 ? std::to_string(target_time->tm_hour) : "0" + std::to_string(target_time->tm_hour); min = target_time->tm_min > 9 ? std::to_string(target_time->tm_min) : "0" + std::to_string(target_time->tm_min); sec = target_time->tm_sec > 9 ? std::to_string(target_time->tm_sec) : "0" + std::to_string(target_time->tm_sec); return year + month + day + hour + min + sec; }