国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Windows Mobile下使用Native C++開發日志類

2019-11-17 03:49:12
字體:
來源:轉載
供稿:網友
背景
這段業余時間一直都在開發iToday。在iToday中加入日志管理。關于iToday,可以參考那些一些文章。

開源(Open Source)那些事兒 (一)

開源那些事兒 (二) - iToday開源項目計劃

開源那些事兒(三)-iToday的總體設計

開源那些事兒(四)-如何使用CodePlex進行項目管理



簡介
日志管理是程序不可以缺少的一個重要組成部分,對于長期運行的后臺程序尤為重要,盡管經過了大量的測試,但是在實際運行環境下,程序未免有出錯的時候。有時候由于第三方原因導致的,例如電信網絡質量下載,掉包等等。在一些看似莫名其妙的問題下,日志文件很多時候就成了救命繩。bug free是我們一直追求的目標,但是我永遠不能保證bug free,每次我在面試中說這句話,做銷售出生的人會翻白眼,做技術的人會會心一笑。我能保證的是如何盡快的troubleshooting,提高質量,日志文件在這過程中又是最重要的手段之一。下面文章講述使用Native C++對Windows Embedded CE和Windows Mobile日志文件類的封裝。



代碼
先上代碼,下面分析。需要iToday全部代碼也可以到codeplex上去下載。

類定義文件

typedef enum tagLOG_LEVEL{    LOG_TRACE,    LOG_INFO,    LOG_WARNING,    LOG_ERROR,    LOG_FATAL,    LOG_NONE = 10,}LOG_LEVEL;class Logger{public:    static Logger& Instance();        static void SetLogFilePath( const std::string& strFilePath);    static void SetLogLevel( const LOG_LEVEL enLogLevel);    static void Initialise();    static void Dispose();    //void Log( LOG_TRACE const TCHAR *format, ...  );    //void LogInfo( const TCHAR *format, ...  );    //void LogWarning( const TCHAR *format, ...  );    //void LogError( const TCHAR *format, ...  );    //void LogFatal( const TCHAR *format, ...  );        void Log( LOG_LEVEL logLevel ,const TCHAR *format, ...  );    PRivate:    /* more (non-static) functions here */    Logger(); // ctor hidden    Logger(Logger const&); // copy ctor hidden    Logger& Operator=(Logger const&); // assign op. hidden    ~Logger(); // dtor hidden    static FILE*            m_hLogFile;    static std::string        m_strFilePath;    static LOG_LEVEL        m_enLogLevel;};
類實現文件

FILE* Logger::m_hLogFile = NULL;LOG_LEVEL Logger::m_enLogLevel = LOG_TRACE;std::string Logger::m_strFilePath = "//Storage Card//DebugInfo.log";TCHAR * LogLevelStr[]={    TEXT("TRACE"),    TEXT("INFO"),    TEXT("WARN"),    TEXT("ERROR"),    TEXT("FATAL"),};Logger& Logger::Instance() {  static Logger oLogger;  return oLogger;}void Logger::SetLogFilePath( const std::string& strFilePath){    m_strFilePath = strFilePath;    Dispose();    Initialise();}void Logger::SetLogLevel( const LOG_LEVEL enLogLevel){    m_enLogLevel = enLogLevel;}Logger::Logger(){    Initialise();}//never useLogger::~Logger(){    Dispose();}void Logger::Initialise(){    if( m_strFilePath.length() > 0 )    {        m_hLogFile = fopen(m_strFilePath.c_str(), "a+");        }}void Logger::Dispose(){    if( NULL != m_hLogFile )    {        fflush( m_hLogFile );        fclose( m_hLogFile );        m_hLogFile = NULL;    }}void Logger::Log( LOG_LEVEL enLogLevel ,const TCHAR *format, ... ){    if( m_enLogLevel > enLogLevel)    {        return;    }#ifndef DEBUG    if ( NULL == m_hLogFile )    {        return;        }#endif    TCHAR szBuffer[1024];    va_list args;    va_start(args, format);    vswprintf(szBuffer, format, args);    va_end(args);#ifdef DEBUG    wprintf(_T("%S THR:%8.8x %s/t%s/n"), GetCurrentTime(), GetCurrentThread(), LogLevelStr[enLogLevel], szBuffer);#else    //combine time stamp, thread number and log level together.    if( 0 > fwprintf(m_hLogFile, _T("%S THR:%8.8x %s/t%s/n"), GetCurrentTime(), GetCurrentThreadId(), LogLevelStr[enLogLevel], szBuffer) )    {        Dispose();    }    else    {        fflush(m_hLogFile);    }#endif    }

Singleton模式
這個Logger類使用Singleton模式來實現,不知道什么時候開始博客園已經不再流行設計模式了,一方面說明設計模式不再是陽春白雪,已經深入人間。另一方面又興起了反模式熱潮。在反模式的風潮中,Singleton是給人批評最多的模式,Singleton有點像變相的全局變量,破壞了封裝,混亂了各個類的依賴關系。

我還是那句話,模式本身沒有錯,看用的人是否把特定的模式用在特定的場景下。Singleton我還是會用到,如果某個資源類有且只有一份,我就使用Singleton。沒有必要產生多個對象,而且多個對象訪問獨占資源會有同步問題。在Logger類,我還是使用Singleton,因為我只寫一個文件。

Singleton的具體實現一般關心三個問題: 1. 有且只有一個對象實例化。 2.多線程的控制。其實第二個問題也是為了保證第一個問題。3. 按需實例化。

private:    /* more (non-static) functions here */    Logger(); // ctor hidden    Logger(Logger const&); // copy ctor hidden    Logger& operator=(Logger const&); // assign op. hidden    ~Logger(); // dtor hidden上面的代碼用于保證只有一個對象的實例化,很多做C#的開發人員會忽略上面的代碼,因為C#沒有深拷貝的概念,也沒有運算符重載的概念。



Logger& Logger::Instance() {  static Logger oLogger;  return oLogger;}上面的代碼保證線程安全以及按需實例化。我覺得這個實現模式很好,同時滿足三個愿望。



日志分級管理
打印日志的時候,分級管理很重要,不同時期需要顯示不同級別的日志,開發時期,可能需要Trace級別的日志,到了運行時可能只需要Error以上級別的日志了,日志分級管理能均衡時間與空間的合理利用。

通過級別管理,打印級別高于需要顯示級別的日志。

if( m_enLogLevel > enLogLevel){    return;}

在打印過程中,顯示級別,我在找問題的時候都是從高級往低級找。

if( 0 > fwprintf(m_hLogFile, _T("%S THR:%8.8x %s/t%s/n"), GetCurrentTime(), GetCurrentThreadId(), LogLevelStr[enLogLevel], szBuffer) ){    Dispose();}由于這是在Windows Embedded CE和Windows Mobile平臺下的實現,所以都是有Unicode的API。下面是打印的日志,包含了級別。

2010-02-24T09:17:38 THR:de428d7e TRACE    FILE=[./iToday.cpp], LINE=[44]2010-02-24T09:17:39 THR:de428d7e INFO    FILE=[./iToday.cpp], LINE=[47]2010-02-24T09:17:39 THR:de428d7e WARN    FILE=[./iToday.cpp], LINE=[50]2010-02-24T09:17:40 THR:de428d7e ERROR    FILE=[./iToday.cpp], LINE=[53]2010-02-24T09:17:40 THR:de428d7e FATAL    FILE=[./iToday.cpp], LINE=[56]2010-02-24T09:17:41 THR:de428d7e WARN    FILE=[./iToday.cpp], LINE=[67]2010-02-24T09:17:42 THR:de428d7e ERROR    FILE=[./iToday.cpp], LINE=[70]2010-02-24T09:17:42 THR:de428d7e FATAL    FILE=[./iToday.cpp], LINE=[73]


時間與線程號
在多線程環境下,打印時間和線程十分重要,這樣能查線程同步問題。時間和線程號見上面的日志。



使用Logger
void LoggerTest(){    Logger::Instance().Log(LOG_TRACE, _T("FILE=[%S], LINE=[%d]"), __FILE__, __LINE__);    Sleep(500);        Logger::Instance().Log(LOG_INFO, _T("FILE=[%S], LINE=[%d]"), __FILE__, __LINE__);    Sleep(500);    Logger::Instance().Log(LOG_WARNING, _T("FILE=[%S], LINE=[%d]"), __FILE__, __LINE__);    Sleep(500);    Logger::Instance().Log(LOG_ERROR, _T("FILE=[%S], LINE=[%d]"), __FILE__, __LINE__);    Sleep(500);    Logger::Instance().Log(LOG_FATAL, _T("FILE=[%S], LINE=[%d]"), __FILE__, __LINE__);    Sleep(500);    Logger::SetLogLevel(LOG_WARNING);    Logger::Instance().Log(LOG_TRACE, _T("FILE=[%S], LINE=[%d]"), __FILE__, __LINE__);    Sleep(500);        Logger::Instance().Log(LOG_INFO, _T("FILE=[%S], LINE=[%d]"), __FILE__, __LINE__);    Sleep(500);    Logger::Instance().Log(LOG_WARNING, _T("FILE=[%S], LINE=[%d]"), __FILE__, __LINE__);    Sleep(500);    Logger::Instance().Log(LOG_ERROR, _T("FILE=[%S], LINE=[%d]"), __FILE__, __LINE__);    Sleep(500);    Logger::Instance().Log(LOG_FATAL, _T("FILE=[%S], LINE=[%d]"), __FILE__, __LINE__);    Sleep(500);    Logger::SetLogLevel(LOG_INFO);    Logger::SetLogFilePath("//Storage Card//DebugInfo2.log");    Logger::Instance().Log(LOG_TRACE, _T("FILE=[%S], LINE=[%d]"), __FILE__, __LINE__);    Sleep(500);        Logger::Instance().Log(LOG_INFO, _T("FILE=[%S], LINE=[%d]"), __FILE__, __LINE__);    Sleep(500);    Logger::Instance().Log(LOG_WARNING, _T("FILE=[%S], LINE=[%d]"), __FILE__, __LINE__);    Sleep(500);    Logger::Instance().Log(LOG_ERROR, _T("FILE=[%S], LINE=[%d]"), __FILE__, __LINE__);    Sleep(500);    Logger::Instance().Log(LOG_FATAL, _T("FILE=[%S], LINE=[%d]"), __FILE__, __LINE__);    Sleep(500);}使用Logger類很簡單,直接調用Log()函數就可以了,可以參考printf的模式來使用,也就是C#的String.Format()的模式。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 察隅县| 原阳县| 镇平县| 德庆县| 东山县| 怀宁县| 安阳县| 阿城市| 英德市| 特克斯县| 平乡县| 贵溪市| 广平县| 满洲里市| 玉田县| 海南省| 营山县| 虞城县| 凌海市| 万全县| 鄢陵县| 庆城县| 克拉玛依市| 昆明市| 手机| 综艺| 岚皋县| 平谷区| 顺昌县| 通州市| 洪泽县| 蛟河市| 宁海县| 五常市| 永德县| 揭西县| 封开县| 铜梁县| 黔东| 高安市| 巴彦县|