C++開源跨平臺OJ系統判題核心FreeJudger(二)——logger設計
C++開源跨平臺OJ系統判題核心FreeJudger(二)——logger設計
By 馬冬亮(凝霜 Loki)
一個人的戰爭(http://blog.csdn.net/MDL13412)
前言
日誌庫在中等規模以上程式中的重要意義不必多說,特別在一些並行程式中,其起著“偵錯程式”的作用。現在開源的日誌庫很多,下面列舉其中一些著名的專案,並分析其特點:
由於以前在linux下封裝過log4cxx日誌庫,所以在FreeJudger專案中logger模組採用log4cxx為核心。
介面設計
日誌介面需要提供Fatal、Error、Warn、Info、Debug、Trace幾種日誌級別,因此ILogger介面設計如下:
class JUDGER_API ILogger { public: ILogger(); virtual ~ILogger(); virtual void logFatal(const OJString &msg) const = 0; virtual void logError(const OJString &msg) const = 0; virtual void logWarn(const OJString &msg) const = 0; virtual void logInfo(const OJString &msg) const = 0; virtual void logDebug(const OJString &msg) const = 0; virtual void logTrace(const OJString &msg) const = 0; };
由於FreeJudger是多執行緒判題,因此每個執行緒需要獨立的日誌例項,並將日誌輸出到多個檔案中,為了方便管理,需要設計LoggerFactory,其介面如下所示:使用時,首先要將ILogger例項通過registerLogger註冊到LoggerFactory中,程式碼如下:class JUDGER_API LoggerFactory { public: typedef std::map<OJInt32_t, ILogger*> LoggerList; typedef std::shared_ptr<LoggerList> SharedLoggerList; public: static ILogger* getLogger(const OJInt32_t loggerId); static bool registerLogger(ILogger *logger, const OJInt32_t loggerId); private: LoggerFactory(); ~LoggerFactory(); private: static SharedLoggerList loggers_; private: struct deleter { void operator()(LoggerFactory::LoggerList *pLoggerFactory) { for (LoggerFactory::LoggerList::iterator iter = LoggerFactory::loggers_->begin(); LoggerFactory::loggers_->end() != iter; ++iter) { JUDGER_SAFE_DELETE_OBJ_AND_RESET((*iter).second); } } }; };
上述程式碼中的IMUST::LoggerId::AppInitLoggerId是用於程式主執行緒日誌例項的id,對於其他執行緒,其定義如下:IMUST::LoggerFactory::registerLogger( new IMUST::Log4CxxLoggerImpl(GetOJString("log.cfg"), GetOJString("logger0")), IMUST::LoggerId::AppInitLoggerId);
namespace LoggerId { const OJInt32_t AppInitLoggerId = 0; const OJInt32_t Thread1LoggerId = 1; const OJInt32_t Thread2LoggerId = 2; const OJInt32_t Thread3LoggerId = 3; const OJInt32_t Thread4LoggerId = 4; const OJInt32_t Thread5LoggerId = 5; const OJInt32_t Thread6LoggerId = 6; const OJInt32_t Thread7LoggerId = 7; const OJInt32_t Thread8LoggerId = 8; // 通用ID從100以後開始編號,1-100留給執行緒 }
由於具體實現繼承自ILogger,因此日誌例項可以同時使用不同的底層實現,其例項的獲取及使用如下所示:
ILogger *logger = LoggerFactory::getLogger(LoggerId::AppInitLoggerId); logger->logTrace(GetOJString("[Daemon] - IMUST::InitApp"));
log4cxx封裝
這裡直接給出完整程式碼,首先是Logger_log4cxx.h:
接下來是Logger_log4cxx.cpp:#ifndef IMUST_OJ_LOGGER_LOG4CXX_H #define IMUST_OJ_LOGGER_LOG4CXX_H #include "Logger.h" namespace IMUST { // log4cxx的LoggerPtr無法使用前置宣告,因此要做包裝 class LoggerPtrWrapper; class JUDGER_API Log4CxxLoggerImpl : public ILogger { public: Log4CxxLoggerImpl(const OJString &configFileName, const OJString &logTag); virtual ~Log4CxxLoggerImpl(); virtual void logFatal(const OJString &msg) const; virtual void logError(const OJString &msg) const; virtual void logWarn(const OJString &msg) const; virtual void logInfo(const OJString &msg) const; virtual void logDebug(const OJString &msg) const; virtual void logTrace(const OJString &msg) const; private: LoggerPtrWrapper *logger_; }; } #endif // IMUST_OJ_LOGGER_LOG4CXX_H
#include "Logger_log4cxx.h" #include "../../thirdpartylib/log4cxx/log4cxx.h" #include "../../thirdpartylib/log4cxx/propertyconfigurator.h" namespace IMUST { class LoggerPtrWrapper { public: log4cxx::LoggerPtr &operator ->() { return loggerPtr_; } log4cxx::LoggerPtr &operator *() { return loggerPtr_; } log4cxx::LoggerPtr &operator =(const log4cxx::LoggerPtr loggerPtr) { loggerPtr_ = loggerPtr; return loggerPtr_; } private: log4cxx::LoggerPtr loggerPtr_; }; Log4CxxLoggerImpl::Log4CxxLoggerImpl(const OJString &configFileName, const OJString &logTag) : logger_(new LoggerPtrWrapper) { assert(!configFileName.empty() && "Config filename can not be empty"); log4cxx::PropertyConfigurator::configure(configFileName); *logger_ = log4cxx::Logger::getLogger(logTag); } Log4CxxLoggerImpl::~Log4CxxLoggerImpl() { } void Log4CxxLoggerImpl::logFatal(const OJString &msg) const { (*logger_)->fatal(msg); } void Log4CxxLoggerImpl::logError(const OJString &msg) const { (*logger_)->error(msg); } void Log4CxxLoggerImpl::logWarn(const OJString &msg) const { (*logger_)->warn(msg); } void Log4CxxLoggerImpl::logInfo(const OJString &msg) const { (*logger_)->info(msg); } void Log4CxxLoggerImpl::logDebug(const OJString &msg) const { (*logger_)->debug(msg); } void Log4CxxLoggerImpl::logTrace(const OJString &msg) const { (*logger_)->trace(msg); } }
解決log4cxx中文亂碼
log4cxx在Windows平臺,即使使用了Unicode進行編譯,在輸出中文日誌時,還是會產生亂碼,其實解決方法非常簡單,只需在main函式開始時,呼叫下述程式碼即可:
setlocale(LC_ALL, "");
完整程式碼
完整程式碼請參考FreeJudger專案中的judgerlib/logger
歡迎加入
群117975329,驗證資訊CSDN。
主要維護人:
- 周寶 you_lan_hai@foxmail.com
- 馬冬亮 mdl2009@vip.qq.com
相關文章
- C++開源跨平臺OJ系統判題核心—— FreeJudger(一)C++
- C++開源跨平臺OJ系統判題核心FreeJudger(三)——log4cxx同時使用多個日誌檔案C++
- c++跨平臺開發經驗C++
- 使用c++開發跨平臺的程式C++
- 一個基於.NET Core開源、跨平臺的倉儲管理系統
- 微軟開源 .NET 框架 實現跨平臺微軟框架
- CLion 2022開發C及C++所設計的跨平臺IDEC++IDE
- 設計和而不同的跨平臺AppAPP
- Remax One - 重新設計小程式的跨平臺開發REM
- 跨平臺開源通訊元件elastic communication元件AST
- 4個.Net跨平臺圖形開源庫
- 一個開源的OJ二次開發
- 設計電商平臺優惠券系統
- 微軟借力.NET開源跨平臺支援,佈局物聯網平臺開發微軟
- 阿里二面:設計一個電商平臺積分兌換系統!阿里
- 開源、高效、跨平臺:深剖Google FlatBuffers工作原理Go
- 怎樣下載C/C++的免費、開源且跨平臺IDE——Code::BlocksC++IDEBloC
- MobileLab跨平臺開發專題交流會
- Apache Wayang :跨平臺資料處理系統Apache
- 跨平臺程式設計開發工具:Xojo 2023 for Mac程式設計Mac
- 跨平臺渲染引擎之路:框架與核心模組框架
- 應用跨平臺問題?
- 開源跨平臺資料格式化框架概覽框架
- 資訊系統設計一個平臺--利於實施的平臺
- 宜信開源|漏洞管理平臺『洞察』的設計理念和平臺功能
- 原生體驗擋不住!JavaScript開源跨平臺框架NativeScriptJavaScript框架
- 各種SmartPhone上的跨平臺開源框架的總結框架
- 基於系統融合的統一監控平臺設計
- 開源面試題社群平臺上線了面試題
- 如何基於開源構架設計一個影片平臺?
- C++核心程式設計C++程式設計
- 致敬社群開源介面平臺並二次開發
- NFT數字藏品交易系統平臺開發技術(程式設計示例)程式設計
- NODE_ENV跨平臺設定
- C++分散式系統——《開題》C++分散式
- 藏品數字收藏系統開發NFT藏品交易平臺開發(系統建設)
- NeuChar 平臺使用及開發教程(二):設定平臺賬號
- 跨平臺開發框架的大旗框架