Log4CPP.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. #include "Log4CPP.h"
  2. #include <sys/stat.h> // 用于目录创建
  3. #include <cctype> // 用于字符串转换
  4. #include <algorithm> // 用于字符串转换
  5. #include <cstdio>
  6. #include <ctime>
  7. #include <cstdarg>
  8. #include <vector>
  9. #include <sstream>
  10. #include <iomanip>
  11. #include <cstring> // 添加strerror支持
  12. #include <memory>
  13. #include "ResDataObject.h"
  14. Log4CPP* Log4CPP::instance = NULL;
  15. std::string Log4CPP::_screenInfo = "screenInfo";
  16. std::string Log4CPP::_logName = "log";
  17. // 初始化配置
  18. LogConfig Log4CPP::config;
  19. log4cpp::Category& root = log4cpp::Category::getRoot();
  20. log4cpp::Category& Log4CPP::logCat = root.getInstance(Log4CPP::_logName);
  21. log4cpp::Category& Log4CPP::coutCat = root.getInstance(Log4CPP::_screenInfo);
  22. // 优先级
  23. log4cpp::Priority::PriorityLevel Log4CPP::coutPri = COUNT_PRITY; // 控制台
  24. log4cpp::Priority::PriorityLevel Log4CPP::logPri = LOG_PRITY; // 本地文件
  25. log4cpp::PatternLayout* Log4CPP::logLayout = NULL;
  26. log4cpp::PatternLayout* Log4CPP::screenLayout = NULL;
  27. log4cpp::PatternLayout* Log4CPP::logLayout2 = NULL; /* 回卷用这个 */
  28. log4cpp::FileAppender* Log4CPP::logFile = NULL;//文件日志输入
  29. log4cpp::OstreamAppender* Log4CPP::logScreen = NULL;//屏幕日志输入
  30. log4cpp::RollingFileAppender* Log4CPP::rollLogFile; /* 回卷用这个 */
  31. // 创建目录函数
  32. bool Log4CPP::createDirectory(const std::string& path) {
  33. struct stat st;
  34. if (stat(path.c_str(), &st) == 0) {
  35. if (S_ISDIR(st.st_mode)) {
  36. return true; // 目录已存在
  37. }
  38. return false; // 存在同名文件
  39. }
  40. // 递归创建目录
  41. size_t pos = 0;
  42. do {
  43. pos = path.find_first_of('/', pos + 1);
  44. std::string subdir = path.substr(0, pos);
  45. if (mkdir(subdir.c_str(), 0755) != 0) {
  46. if (errno != EEXIST) {
  47. std::cerr << "Failed to create directory: " << subdir
  48. << " Error: " << strerror(errno) << std::endl;
  49. return false;
  50. }
  51. }
  52. } while (pos != std::string::npos);
  53. return true;
  54. }
  55. // 解析日志级别
  56. log4cpp::Priority::PriorityLevel Log4CPP::parseLogLevel(const std::string& level) {
  57. std::string upper;
  58. std::transform(level.begin(), level.end(), std::back_inserter(upper), ::toupper);
  59. if (upper == "EMERG") return log4cpp::Priority::EMERG;
  60. if (upper == "FATAL") return log4cpp::Priority::FATAL;
  61. if (upper == "ALERT") return log4cpp::Priority::ALERT;
  62. if (upper == "CRIT") return log4cpp::Priority::CRIT;
  63. if (upper == "ERROR") return log4cpp::Priority::ERROR;
  64. if (upper == "WARN") return log4cpp::Priority::WARN;
  65. if (upper == "NOTICE") return log4cpp::Priority::NOTICE;
  66. if (upper == "INFO") return log4cpp::Priority::INFO;
  67. if (upper == "DEBUG") return log4cpp::Priority::DEBUG;
  68. if (upper == "NOTSET") return log4cpp::Priority::NOTSET;
  69. std::cerr << "Unknown log level: " << level << ". Using DEBUG as default." << std::endl;
  70. return log4cpp::Priority::DEBUG;
  71. }
  72. // 加载配置文件
  73. bool Log4CPP::loadConfig(const std::string& configFile) {
  74. // 读取基本配置
  75. ResDataObject temp;
  76. if (!temp.loadFile(configFile.c_str())) {
  77. std::cerr << "Failed to load log config file: " << configFile
  78. << ". Using default settings." << std::endl;
  79. return false;
  80. }
  81. // 获取log_config节点
  82. ResDataObject LogConfig = temp["log_config"];
  83. // 读取基本配置 - 修复变量名错误
  84. if (LogConfig.GetKeyCount("root_level")) {
  85. config.root_level = (std::string)LogConfig["root_level"];
  86. std::cout << "Log4CPP::loadConfig: config.root_level:" << config.root_level << std::endl;
  87. }
  88. if (LogConfig.GetKeyCount("log_dir")) {
  89. config.log_dir = (std::string)LogConfig["log_dir"];
  90. std::cout << "Log4CPP::loadConfig: config.log_dir:" << config.log_dir << std::endl;
  91. }
  92. if (LogConfig.GetKeyCount("history_dir")) {
  93. config.history_dir = (std::string)LogConfig["history_dir"];
  94. std::cout << "Log4CPP::loadConfig: config.history_dir:" << config.history_dir << std::endl;
  95. }
  96. if (LogConfig.GetKeyCount("max_file_size")) {
  97. config.max_file_size = (size_t)(int)LogConfig["max_file_size"];
  98. std::cout << "Log4CPP::loadConfig: config.max_file_size:" << config.max_file_size << std::endl;
  99. }
  100. if (LogConfig.GetKeyCount("max_backups")) {
  101. config.max_backups = (int)LogConfig["max_backups"];
  102. std::cout << "Log4CPP::loadConfig: config.max_backups:" << config.max_backups << std::endl;
  103. }
  104. if (LogConfig.GetKeyCount("file_pattern")) {
  105. config.file_pattern = (std::string)LogConfig["file_pattern"];
  106. std::cout << "Log4CPP::loadConfig: config.file_pattern:" << config.file_pattern << std::endl;
  107. }
  108. if (LogConfig.GetKeyCount("console_pattern")) {
  109. config.console_pattern = (std::string)LogConfig["console_pattern"];
  110. std::cout << "Log4CPP::loadConfig: config.console_pattern:" << config.console_pattern << std::endl;
  111. }
  112. // 创建日志目录
  113. if (!createDirectory(config.log_dir)) {
  114. std::cerr << "Failed to create log directory: " << config.log_dir << std::endl;
  115. }
  116. if (!createDirectory(config.history_dir)) {
  117. std::cerr << "Failed to create history directory: " << config.history_dir << std::endl;
  118. }
  119. return true;
  120. }
  121. bool Log4CPP::init(const std::string& configFile, std::string logName, bool toScreen) {
  122. // 加载配置文件
  123. if (!loadConfig(configFile)) {
  124. std::cerr << "Log4CPP::init: Failed to load config, using defaults" << std::endl;
  125. }
  126. std::cout << "Log4CPP::init: Config loaded" << std::endl;
  127. // 解析日志级别
  128. Log4CPP::coutPri = parseLogLevel(config.root_level);
  129. Log4CPP::logPri = parseLogLevel(config.root_level);
  130. std::cout << "Log4CPP::init: Log levels parsed" << std::endl;
  131. if (Log4CPP::instance == NULL) {
  132. Log4CPP::instance = new Log4CPP(toScreen);
  133. // 使用配置的日志目录
  134. std::string year, month, day, hour, min, sec;
  135. getCurrentTime(year, month, day, hour, min, sec);
  136. std::string logPath = config.log_dir + "/" + logName + "." +
  137. year + month + day + ".log";
  138. Log4CPP::_logName = logPath;
  139. log4cpp::Category& logCat = root.getInstance(Log4CPP::_logName);
  140. log4cpp::Category& coutCat = root.getInstance(Log4CPP::_screenInfo);
  141. logScreen = new log4cpp::OstreamAppender("logScreen", &std::cout);
  142. logFile = new log4cpp::FileAppender("logFile", Log4CPP::_logName); /* 然后注释这个 */
  143. //rollLogFile = new log4cpp::RollingFileAppender("rollLogFile", Log4CPP::_logName, 1024*1024, 5); /* 回卷用这个 */ // 单个日志文件大小1M,5个回卷
  144. //设置布局
  145. Log4CPP::logLayout = new log4cpp::PatternLayout(); /* 然后注释这个 */
  146. Log4CPP::screenLayout = new log4cpp::PatternLayout();
  147. Log4CPP::logLayout2 = new log4cpp::PatternLayout(); /* 回卷用这个 */
  148. // 设置日志格式
  149. Log4CPP::logLayout->setConversionPattern(config.file_pattern.c_str());
  150. Log4CPP::screenLayout->setConversionPattern(config.console_pattern.c_str());
  151. Log4CPP::logLayout2->setConversionPattern(config.file_pattern.c_str());
  152. Log4CPP::logScreen->setLayout(screenLayout);
  153. Log4CPP::logFile->setLayout(logLayout); /* 然后注释这个 */
  154. //Log4CPP::rollLogFile->setLayout(logLayout2); /* 回卷用这个 */
  155. std::cout << "Log4CPP::init: Setting layouts" << std::endl;
  156. //追加到目录
  157. Log4CPP::logCat.addAppender(Log4CPP::logFile); /* 然后注释这个 */
  158. //Log4CPP::logCat.addAppender(Log4CPP::rollLogFile); /* 回卷用这个 */
  159. Log4CPP::coutCat.addAppender(Log4CPP::logScreen);
  160. //设置优先级
  161. Log4CPP::logCat.setPriority(Log4CPP::logPri);
  162. Log4CPP::coutCat.setPriority(Log4CPP::coutPri);
  163. }
  164. Log4CPP::instance->outToScreen = toScreen;
  165. return true;
  166. }
  167. //获取日志函数,默认参数选择是否输出到屏幕
  168. Log4CPP* Log4CPP::getLog(bool toScreen) {
  169. Log4CPP::instance->outToScreen = toScreen;
  170. if (NULL == Log4CPP::instance) {
  171. printf("Log4CPP::log is NULL, please use Log4CPP::init!\n");
  172. return NULL;
  173. }
  174. return Log4CPP::instance;
  175. }
  176. //销毁日志对象
  177. void Log4CPP::destoryLog() {
  178. log4cpp::Category::shutdown();
  179. delete Log4CPP::instance;
  180. }
  181. //设置日志记录优先级
  182. void Log4CPP::setPri(log4cpp::Priority::PriorityLevel coutLevel, log4cpp::Priority::PriorityLevel logLevel) {
  183. Log4CPP::logPri = logLevel;
  184. Log4CPP::coutPri = coutLevel;
  185. Log4CPP::logCat.setPriority(Log4CPP::logPri);
  186. Log4CPP::coutCat.setPriority(Log4CPP::coutPri);
  187. }
  188. // 辅助函数:格式化消息
  189. std::string Log4CPP::formatMessage(const char* format, va_list args) {
  190. char buffer[4096];
  191. vsnprintf(buffer, sizeof(buffer), format, args);
  192. return std::string(buffer);
  193. }
  194. // 类型转换函数
  195. template <typename T>
  196. std::string Log4CPP::toString(const T& value) {
  197. std::ostringstream oss;
  198. oss << value;
  199. return oss.str();
  200. }
  201. // 指针特化
  202. std::string Log4CPP::toString(const void* value) {
  203. std::ostringstream oss;
  204. oss << "0x" << std::hex << reinterpret_cast<uintptr_t>(value);
  205. return oss.str();
  206. }
  207. // 布尔值特化
  208. std::string Log4CPP::toString(bool value) {
  209. return value ? "true" : "false";
  210. }
  211. // 修改后的日志函数
  212. void Log4CPP::warn(int line, const char* function, const char* format, ...) {
  213. char info[4096] = { 0 };
  214. snprintf(info, sizeof(info), "[%s][%d]: ", function, line);
  215. va_list args;
  216. va_start(args, format);
  217. std::string formatted = formatMessage(format, args);
  218. va_end(args);
  219. std::string message = info + formatted;
  220. if (outToScreen) {
  221. logCat.warn(message);
  222. coutCat.warn(message);
  223. }
  224. else {
  225. logCat.warn(message);
  226. }
  227. }
  228. // 其他日志函数实现类似
  229. void Log4CPP::error(int line, const char* function, const char* format, ...) {
  230. char info[4096] = { 0 };
  231. snprintf(info, sizeof(info), "[%s][%d]: ", function, line);
  232. va_list args;
  233. va_start(args, format);
  234. std::string formatted = formatMessage(format, args);
  235. va_end(args);
  236. std::string message = info + formatted;
  237. if (outToScreen) {
  238. logCat.error(message);
  239. coutCat.error(message);
  240. }
  241. else {
  242. logCat.error(message);
  243. }
  244. }
  245. void Log4CPP::debug(int line, const char* function, const char* format, ...) {
  246. char info[4096] = { 0 };
  247. snprintf(info, sizeof(info), "[%s][%d]: ", function, line);
  248. va_list args;
  249. va_start(args, format);
  250. std::string formatted = formatMessage(format, args);
  251. va_end(args);
  252. std::string message = info + formatted;
  253. if (outToScreen) {
  254. logCat.debug(message);
  255. coutCat.debug(message);
  256. }
  257. else {
  258. logCat.debug(message);
  259. }
  260. }
  261. void Log4CPP::info(int line, const char* function, const char* format, ...) {
  262. char info[4096] = { 0 };
  263. snprintf(info, sizeof(info), "[%s][%d]: ", function, line);
  264. va_list args;
  265. va_start(args, format);
  266. std::string formatted = formatMessage(format, args);
  267. va_end(args);
  268. std::string message = info + formatted;
  269. if (outToScreen) {
  270. logCat.info(message);
  271. coutCat.info(message);
  272. }
  273. else {
  274. logCat.info(message);
  275. }
  276. }
  277. std::string Log4CPP::getCurrentTime(std::string& year, std::string& month, std::string& day, std::string& hour, std::string& min, std::string& sec) {
  278. // 获取系统时间 - 年月日时分秒
  279. time_t _time;
  280. struct tm* target_time;
  281. time(&_time);
  282. target_time = localtime(&_time);
  283. year = std::to_string(target_time->tm_year + 1900);
  284. month = target_time->tm_mon + 1 > 9 ? std::to_string(target_time->tm_mon + 1) : "0" + std::to_string(target_time->tm_mon + 1);
  285. day = target_time->tm_mday > 9 ? std::to_string(target_time->tm_mday) : "0" + std::to_string(target_time->tm_mday);
  286. hour = target_time->tm_hour > 9 ? std::to_string(target_time->tm_hour) : "0" + std::to_string(target_time->tm_hour);
  287. min = target_time->tm_min > 9 ? std::to_string(target_time->tm_min) : "0" + std::to_string(target_time->tm_min);
  288. sec = target_time->tm_sec > 9 ? std::to_string(target_time->tm_sec) : "0" + std::to_string(target_time->tm_sec);
  289. return year + month + day + hour + min + sec;
  290. }