青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

自由的心兒 自由的飛翔

旅程

C++博客 聯系 聚合 管理
  0 Posts :: 2 Stories :: 0 Comments :: 0 Trackbacks

 
        在實際的應用開發中,log模塊設計是必不可少的一部分,log模塊設計的好壞直接影響到系統的性能和日后的維護。總的來說,log模塊在功能上除了日志級別、時間和消息正文這些必須的信息外,最好還能記錄日志產生時盡可能多的信息,比如線程ID、模塊名稱、源文件、代碼行等。在log接口的設計上應該盡可能簡化,以方便調用。一個調用起來很麻煩的接口,估計是沒人想用的。

在基于C/C++開發的應用中,log接口通常設計成帶可變參數的C風格函數,像這樣:
void __cdecl PrintLog(int log_level, const char* format, ...);
對C 程序員這是很合理的選擇。但是對于強調強類型安全的C++來說,可變參函數的類型不安全特性是最遭C++程序員詬病之處,這也是C++用 iostream代替printf類函數的主要原因。但是令人奇怪的是,很久以來,我好像沒見到過基于C++的類型安全的log接口設計。本文給出了一種基于C++ iostream的類型安全且線程安全的log接口。
類似于printf的其他iostream替代者,我們希望log接口能夠這樣用,通過流操作符(<<)的重載來解決類型安全問題的同時提供一致性接口:
log << "test for iostream log";
log << "fopen failed. errno=" << errno;
但是對于log來說,用iostream的一個問題在于如何界定一條完整的log信息。用可變參的printf型接口的時候,不管輸入參數有多少,一條log信息產生一個函數調用,這意味著一個函數調用就是一條完整的信息。而iostream的每一個輸出(<<)流操作都是一個函數調用,這就使得界定一條完整的log信息變得困難。
同時,log level和log time也是log信息的必要組成部分,必須要記錄。如果接口弄成這樣:
log << loglvl_info << log_time << "test for iostream log";
log << loglvl_err << log_time << "fopen failed. errno=" << errno;
估計沒有誰喜歡用。還有一個要注意的是多線程安全問題,由于一條完整的log信息可能由多個流操作完成,在棧上構造信息變得不可行,因此存放log信息的buffer要在多個流操作(調用)中使用,這可能帶來線程安全問題。如果用簡單的加鎖解決的話,在構造log信息期間就加鎖無疑會對整個軟件系統造成很大的性能影響。

這些問題中,最關鍵的是第一個問題,即如何從多個流操作中界定一條完整的log信息。為解決這個問題,我利用了C++的臨時對象在表達式結束時析構這一事實。我們可以這樣設計logstream接口:
class logstream : public std::ostream
...{
public:
explicit logstream();
~logstream()
...{
write_log(m_szLogText);
}
//...
};
要產生log時這樣調用:
logstream() << "fopen failed. errno=" << errno;
在這條語句結束時,logstream()臨時變量被析構,這樣在析構函數中我們就得到了一條完整的log信息,log time也可以在這時產生。而且由于logstream()只是一個局部的臨時變量,不會有線程安全問題,沒必要用鎖。log level則可以在logstream構造的時候記錄,改進class logstream如下:
#define LL_ERROR 1
#define LL_INFO 2

class logstream : public std::ostream
...{
public:
explicit logstream( int level);
~logstream()
...{
write_log(m_szLogText);
}
};
#define logerr logstream( LL_ERROR)
#define loginfo logstream( LL_INFO)
這樣調用log接口:
logerr << "fopen failed. errno=" << errno;
上面這行其實有一個問題:在C++標準草案中,臨時變量是r-value,不能有non-const引用。因此在VC .NET 7.1中你會看到 loginfo << "X"調用的是成員操作符ostream::operator<<(const void*),而不是非成員的operator<<(ostream&,const char*),這導致loginfo << "X"輸出一個內存地址而非期望的字符串。
我這里的work-around利用了r-value可以調用成員函數,而成員函數可以返回non-const引用這一事實:
class logstream : public std::ostream
...{
public:
explicit logstream( int level);
~logstream();
logstream& l_value() ...{ return *this; }
};
#define logerr logstream( LL_ERROR).l_value()
#define loginfo logstream( LL_INFO).l_value()
關于臨時變量的一個比較詳細的討論可以看這里。另外一個要注意的問題是要保證析構函數中的所有操作都不能拋出異常。
附錄給出了一份比較完整的logstream接口代碼。由于logstream基于iostream,其接口非常簡單易用,繼承了iostream的很多優點:如對所有數據類型具有一致性的接口,支持iostream library原先支持的所有數據類型,擴展能力很強-新增數據類型對iostream的重載自動適用于logstream。除此之外,該logstream是線程安全的。對于每條log信息,除了基本的log level和log time之外,logstream還能記錄生成每條log 的線程ID、模塊名稱、源文件代碼行、函數名等信息。

附:比較完整的logstream接口部分代碼。
#ifndef __LOG_STREAM_H__
#define __LOG_STREAM_H__

#include
#include
#include
#include "logleveldef.h"

using std::ostream; // 為了應付vc6.0的bug

class logstream : public std::ostream
...{
logstream( const logstream& );
const logstream& operator=( const logstream& );
public:
explicit logstream( int level, int line, const char* file, const char* function );
~logstream();
logstream& l_value() ...{ return *this; }

// strstreambuf標準接口
std::strstreambuf *rdbuf() const
...{return ( (std::strstreambuf *)&streambuf_ ); }
void freeze(bool f = true)
...{streambuf_.freeze(f); }
char *str()
...{return (streambuf_.str()); }
std::streamsize pcount() const
...{return (streambuf_.pcount()); }

private:
std::strstreambuf streambuf_;
LogMessage message;
};

inline
logstream::logstream( int level, int line, const char* file, const char* function )
: ostream(&streambuf_)
, streambuf_( &LogMessage::mem_alloc, &LogMessage::mem_free )
, message(level, line, file, function)
...{
}

inline
logstream::~logstream()
.{
//----------------------------------------------------------
// logstream.h包含在stdhdrs.h中,因此也包含在所有cpp文件中。
// 如果直接調用Log接口需要包含log.h文件。這樣使文件的依賴性
// 大大提高,如果修改Log接口會導致編譯所有cpp文件。
// 這里調用全局函數,可以不用包含log.h頭文件,
// 對log接口的修改不會導致其他cpp文件的重新編譯,從而
// 降低文件的依賴性提高編譯速度。
// 在release版本中,可以考慮包含log.h頭文件從而直接調用Log接口
// 省去一個函數調用。但是另一方面,插件程序不依賴于log.h,
// 如果要在插件中使用本文件,就必須做條件編譯,更加麻煩。
// 因此這里為簡明起見,只調用一個全局函數,通過在主程序和
// 插件程序里對該函數的不同實現調用ILog接口
//----------------------------------------------------------

//----------------------------------------------------------
// LogMessage::write()中不能拋出異常,因為在析構函數中拋出
// 異常是不安全的。具體討論見"More exceptional C++"一書。
//----------------------------------------------------------
const char* ptr = this->str();
this->freeze( false );
message.write( ptr, this->pcount() ); // never throw
}


// __FILE__, __LINE__是ANSI C標準,__FUNCTION__是VC擴展,在vc.net中才有
#ifndef __FUNCTION__
#define __FUNCTION__ NULL
#endif // __FUNCTION__

#ifdef _DEBUG

#define logdbg(message) do{ _logdbg << message; }while(0)

#else // NDEBUG

#define logdbg(message) do{}while(0)

#endif // _DEBUG

//--------------------------------------------------------
// 以下define定義了幾個臨時變量。這些臨時變量在語句結束
// 時析構,導致調用logstream的析構函數,在析構函數
// 中調用write_log()接口寫日志
//--------------------------------------------------------

//----------------------------------------------------------
// 注意以下定義的log接口都是一些臨時變量,C++標準草案中
// 臨時變量是r-value,不能有non-const引用,
// 因此在VC.NET 7.1中你會看到loginfo << "X"調用的是成員操作符
// ostream::operator<<(const void*),而不是非成員的
// operator<<(ostream&,const char*),這導致loginfo << "X"輸出
// 一個內存地址,而非期望的字符串。
// 我這里的解決方法是:由于r-value可以調用成員函數,成員函數
// 可以返回non-const引用,因此這里的log接口是臨時變量
// non-const引用。另一種解決方法是這樣用:
// const_cast( loginfo ) << "X";
// VC 6.0和VC .NET 7.0對臨時變量缺省選擇non-const引用(但不
// 符合C++規范),因此沒有這個問題。
// 關于臨時變量更詳細的討論參見這里:
// http://groups.google.com/groups?hl=zh-CN&lr=&ie=UTF-8&threadm=77q8ju8cqfg11td4qnn24i9unqp54801in%404ax.com&rnum=1&prev=/groups%3Fselm%3D77q8ju8cqfg11td4qnn24i9unqp54801in%25404ax.com
//----------------------------------------------------------

//--------------------------------------------------------
// 致命錯誤。程序即將退出
//--------------------------------------------------------
#define logexit logstream( LL_FATALERR, __LINE__, __FILE__, __FUNCTION__ ).l_value()

//--------------------------------------------------------
// 一般錯誤。某個模塊功能錯誤,但其它部模塊不受影響,
// 程序還能繼續工作。
//--------------------------------------------------------
#define logerr logstream( LL_ERROR, __LINE__, __FILE__, __FUNCTION__ ).l_value()

//--------------------------------------------------------
// 警告信息。需要提醒用戶注意的信息,比如對某個接口傳遞的
// 調用參數不正確,內存溢出,或設備驅動收到一個不能識別的參數。
// 警告和一般錯誤的區別在于一般錯誤是程序的邏輯出現問題,
// 警告則是程序本身的自我保護,是正確的邏輯
//--------------------------------------------------------
#define logwarn logstream( LL_WARNING, __LINE__, __FILE__, __FUNCTION__ ).l_value()

//--------------------------------------------------------
// 一般信息。報告目前的狀態
//--------------------------------------------------------
#define loginfo logstream( LL_INFO, __LINE__, __FILE__, __FUNCTION__ ).l_value()

//--------------------------------------------------------
// 調試信息。有助于程序員調試使用的信息。
//--------------------------------------------------------
#define _logdbg logstream( LL_DBGINFO, __LINE__, __FILE__, __FUNCTION__ ).l_value()


#endif // __LOG_STREAM_H__

posted on 2008-07-22 11:14 Ashuar 閱讀(231) 評論(0)  編輯 收藏 引用

只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            最新中文字幕亚洲| 亚洲精品乱码久久久久久蜜桃麻豆 | 一本色道综合亚洲| 你懂的成人av| 亚洲图片欧洲图片日韩av| 亚洲激情在线播放| 蜜臀av性久久久久蜜臀aⅴ四虎| 欧美一区中文字幕| 欧美va天堂| 欧美成人免费在线| 欧美精品在线网站| 久久精品中文| 亚洲最快最全在线视频| 欧美风情在线| 亚洲人成网站999久久久综合| 久久久久在线| 亚洲一区二区影院| 亚洲欧美国产三级| 亚洲永久精品大片| 91久久久国产精品| 国产精品欧美日韩| 亚洲欧美精品伊人久久| 亚洲精品免费网站| 国产一区二区在线免费观看 | 欧美激情欧美激情在线五月| 免费精品视频| 欧美激情bt| 亚洲国产成人午夜在线一区| 欧美中文字幕视频| 亚洲美女在线看| 欧美日韩情趣电影| 欧美一级大片在线免费观看| 久久久久久久网| 在线不卡视频| 亚洲精品日韩精品| 一区二区三区三区在线| 国产欧美成人| 欧美成人在线影院| 亚洲国产精品免费| 欧美亚洲免费| 亚洲精品久久久久久久久久久久 | 国产精品二区在线观看| 亚洲黄网站在线观看| 亚洲国产精品小视频| 国产精品电影在线观看| 亚洲一区国产精品| 欧美黄色aaaa| 亚洲欧美日韩精品久久久久| 欧美亚洲一区三区| 亚洲在线网站| 久久综合九色99| 久色婷婷小香蕉久久| 欧美在线观看视频一区二区三区| 激情六月婷婷综合| 国内精品久久久久影院色| 国产精品美女久久久免费| 欧美h视频在线| 欧美一区二区三区在线观看视频 | 欧美激情精品久久久久久大尺度 | 国产情侣久久| 亚洲尤物在线| av成人免费在线| 99riav久久精品riav| 久久成人久久爱| 久久成人免费电影| 久久五月天婷婷| 欧美成人r级一区二区三区| 一区二区精品在线| 亚洲——在线| 美国成人直播| 老司机精品福利视频| 国产伦精品一区二区三区四区免费| 久久久美女艺术照精彩视频福利播放 | 韩国av一区二区三区四区| 欧美日韩另类一区| 激情文学综合丁香| 亚洲一级片在线看| 欧美成人国产| 久久三级视频| 夜夜嗨av一区二区三区四区| 久久大逼视频| 亚洲毛片网站| 女仆av观看一区| 欧美精品免费在线| 在线成人黄色| 亚洲综合色视频| 国产日产欧产精品推荐色| 亚洲片在线观看| 蜜臀久久99精品久久久久久9| 国产精品亚洲综合色区韩国| 欧美激情a∨在线视频播放| 欧美一区二视频在线免费观看| 亚洲欧美国产高清| 久久久久国产精品一区三寸| 国产伦精品一区二区三区| 亚洲精品激情| 午夜精品久久久久久| 欧美专区日韩专区| 国产精品入口| 一本久久青青| 亚洲欧美日韩精品久久久久| 亚洲电影在线看| 一区二区三区四区五区在线| 国产精品白丝黑袜喷水久久久| 亚洲日本免费电影| 国产日韩精品久久久| 亚洲性xxxx| 欧美大尺度在线观看| 久久综合九九| 久久精品视频网| 久久一区精品| 国产色综合久久| 亚洲欧洲另类| 欧美日韩福利在线观看| 午夜精品福利一区二区蜜股av| 香蕉久久夜色精品国产| 狠狠干成人综合网| 亚洲免费影视第一页| 国产欧美日韩视频| 麻豆精品一区二区综合av| 欧美激情免费观看| 亚洲天堂av高清| 欧美日本精品| 美女诱惑一区| 国产精品jvid在线观看蜜臀| 久久国产主播| 欧美午夜理伦三级在线观看| 夜夜爽99久久国产综合精品女不卡| 欧美日本乱大交xxxxx| 亚洲影院污污.| 欧美成年人网| 91久久国产综合久久| 亚洲精品一区二区三区樱花| 欧美国产日韩精品免费观看| 欧美一区二区三区婷婷月色| 欧美吻胸吃奶大尺度电影| 久久免费少妇高潮久久精品99| 欧美xx69| 亚洲黄色一区| 亚洲精品自在久久| 欧美激情在线免费观看| 欧美视频精品在线观看| 久久国产免费看| 猫咪成人在线观看| 午夜精品久久久久久久久久久久久| 欧美日韩第一区| 久久久91精品国产| 亚洲图片在区色| 亚洲欧美美女| 欧美国产精品v| 亚洲经典在线看| 欧美在线观看一二区| 91久久精品国产91久久性色tv | 91久久精品国产91久久性色| 在线中文字幕不卡| 欧美电影免费观看高清| 欧美一区二区视频观看视频| 国产午夜亚洲精品理论片色戒| 久久激情综合网| 一区二区三区av| 鲁鲁狠狠狠7777一区二区| 久久都是精品| 在线日韩av片| 国产免费成人av| 国产精品免费电影| 欧美日韩一级大片网址| 欧美中文字幕第一页| 午夜精品久久久99热福利| 小黄鸭精品密入口导航| 亚洲视频在线一区| 久久夜色精品一区| 久热re这里精品视频在线6| 午夜亚洲性色视频| 欧美国产日韩视频| 国产欧美日韩伦理| 韩国av一区二区三区在线观看| 欧美午夜久久| 日韩图片一区| 欧美在线看片| 激情小说亚洲一区| 欧美在线播放高清精品| 亚洲一区二区在线| 国产欧美日韩不卡| 久久国产精品99精品国产| 欧美黄污视频| 久久久久成人精品| 欧美成人免费一级人片100| 欧美日韩国产一中文字不卡| 国产日本欧美在线观看| 午夜激情一区| av成人黄色| 国产三级精品三级| 香蕉久久久久久久av网站| 久久午夜av| 最新日韩精品| 亚洲欧美在线一区| 国产精品久久久久aaaa九色| 国模私拍一区二区三区| 国内精品久久久久影院 日本资源| 亚洲激情国产|