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

自由的心兒 自由的飛翔

旅程

C++博客 聯(lián)系 聚合 管理
  0 Posts :: 2 Stories :: 0 Comments :: 0 Trackbacks

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

在基于C/C++開發(fā)的應用中,log接口通常設計成帶可變參數(shù)的C風格函數(shù),像這樣:
void __cdecl PrintLog(int log_level, const char* format, ...);
對C 程序員這是很合理的選擇。但是對于強調強類型安全的C++來說,可變參函數(shù)的類型不安全特性是最遭C++程序員詬病之處,這也是C++用 iostream代替printf類函數(shù)的主要原因。但是令人奇怪的是,很久以來,我好像沒見到過基于C++的類型安全的log接口設計。本文給出了一種基于C++ iostream的類型安全且線程安全的log接口。
類似于printf的其他iostream替代者,我們希望log接口能夠這樣用,通過流操作符(<<)的重載來解決類型安全問題的同時提供一致性接口:
log << "test for iostream log";
log << "fopen failed. errno=" << errno;
但是對于log來說,用iostream的一個問題在于如何界定一條完整的log信息。用可變參的printf型接口的時候,不管輸入?yún)?shù)有多少,一條log信息產生一個函數(shù)調用,這意味著一個函數(shù)調用就是一條完整的信息。而iostream的每一個輸出(<<)流操作都是一個函數(shù)調用,這就使得界定一條完整的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信息期間就加鎖無疑會對整個軟件系統(tǒng)造成很大的性能影響。

這些問題中,最關鍵的是第一個問題,即如何從多個流操作中界定一條完整的log信息。為解決這個問題,我利用了C++的臨時對象在表達式結束時析構這一事實。我們可以這樣設計logstream接口:
class logstream : public std::ostream
...{
public:
explicit logstream();
~logstream()
...{
write_log(m_szLogText);
}
//...
};
要產生log時這樣調用:
logstream() << "fopen failed. errno=" << errno;
在這條語句結束時,logstream()臨時變量被析構,這樣在析構函數(shù)中我們就得到了一條完整的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可以調用成員函數(shù),而成員函數(shù)可以返回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()
關于臨時變量的一個比較詳細的討論可以看這里。另外一個要注意的問題是要保證析構函數(shù)中的所有操作都不能拋出異常。
附錄給出了一份比較完整的logstream接口代碼。由于logstream基于iostream,其接口非常簡單易用,繼承了iostream的很多優(yōu)點:如對所有數(shù)據(jù)類型具有一致性的接口,支持iostream library原先支持的所有數(shù)據(jù)類型,擴展能力很強-新增數(shù)據(jù)類型對iostream的重載自動適用于logstream。除此之外,該logstream是線程安全的。對于每條log信息,除了基本的log level和log time之外,logstream還能記錄生成每條log 的線程ID、模塊名稱、源文件代碼行、函數(shù)名等信息。

附:比較完整的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文件。
// 這里調用全局函數(shù),可以不用包含log.h頭文件,
// 對log接口的修改不會導致其他cpp文件的重新編譯,從而
// 降低文件的依賴性提高編譯速度。
// 在release版本中,可以考慮包含log.h頭文件從而直接調用Log接口
// 省去一個函數(shù)調用。但是另一方面,插件程序不依賴于log.h,
// 如果要在插件中使用本文件,就必須做條件編譯,更加麻煩。
// 因此這里為簡明起見,只調用一個全局函數(shù),通過在主程序和
// 插件程序里對該函數(shù)的不同實現(xiàn)調用ILog接口
//----------------------------------------------------------

//----------------------------------------------------------
// LogMessage::write()中不能拋出異常,因為在析構函數(shù)中拋出
// 異常是不安全的。具體討論見"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的析構函數(shù),在析構函數(shù)
// 中調用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可以調用成員函數(shù),成員函數(shù)
// 可以返回non-const引用,因此這里的log接口是臨時變量
// non-const引用。另一種解決方法是這樣用:
// const_cast( loginfo ) << "X";
// VC 6.0和VC .NET 7.0對臨時變量缺省選擇non-const引用(但不
// 符合C++規(guī)范),因此沒有這個問題。
// 關于臨時變量更詳細的討論參見這里:
// 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()

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

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

//--------------------------------------------------------
// 一般信息。報告目前的狀態(tài)
//--------------------------------------------------------
#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 閱讀(229) 評論(0)  編輯 收藏 引用
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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| 国产欧美91| 午夜欧美精品| 亚洲午夜视频在线| 亚洲一区三区电影在线观看| 亚洲欧美成人精品| 亚洲欧美另类综合偷拍| 欧美一激情一区二区三区| 午夜精品久久99蜜桃的功能介绍| 午夜免费久久久久| 久久精品一区蜜桃臀影院| 麻豆精品国产91久久久久久| 欧美国产专区| 国产精品美女www爽爽爽| 国产欧美日韩视频在线观看| 亚洲高清视频在线| 亚洲午夜在线| 麻豆精品视频在线观看视频| 亚洲精品一区久久久久久| 久久久蜜臀国产一区二区| 最新精品在线| 一本色道久久综合亚洲精品按摩| 一区二区av在线| 亚洲欧美色一区| 久久精品中文字幕一区| 欧美a级在线| 欧美激情女人20p| 亚洲视频日本| 老牛国产精品一区的观看方式| 欧美日韩国产黄| 国产一区二区三区丝袜| 亚洲免费av电影| 久久久久久久网站| 国产精品久久久久aaaa| 亚洲影院在线观看| 性久久久久久久久久久久| 久久国产主播精品| 日韩视频一区二区三区在线播放免费观看 | 亚洲精品免费一二三区| 欧美影院午夜播放| 亚洲三级网站| 另类图片综合电影| 狠狠色丁香婷婷综合影院 | 欧美va亚洲va国产综合| 欧美日本一区二区三区| 国产一区深夜福利| 亚洲国产精品精华液网站| 亚洲欧美在线网| 亚洲人体1000| 麻豆精品网站| 国模精品一区二区三区色天香| 亚洲一二三四区| 91久久精品国产91久久性色tv | 欧美一区二区三区男人的天堂 | 亚洲韩国青草视频| 久久久人成影片一区二区三区观看| 国产精品日韩在线一区| 在线视频亚洲| 日韩亚洲在线| 欧美日韩一区二区在线| 亚洲欧洲精品天堂一级| 麻豆国产精品777777在线| 小嫩嫩精品导航| 国产性色一区二区| 久久九九免费视频| 欧美亚洲视频| 国产亚洲欧美一区在线观看| 欧美综合国产| 久久久一二三| 99视频精品全国免费| 国产精品视频yy9099| 亚洲在线一区二区三区| 亚洲视频网站在线观看| 国产一区二区三区在线观看免费视频 | 欧美在线一区二区| 欧美在线电影| 亚洲国产第一页| 亚洲精品一二三| 国产精品天美传媒入口| 久久国产日韩| 榴莲视频成人在线观看| 亚洲黄色性网站| 亚洲日本理论电影| 欧美日韩一区二区在线| 午夜亚洲视频| 久久精品国产久精国产一老狼| 伊人春色精品| 亚洲美女av在线播放| 欧美午夜精品久久久久久超碰| 亚洲免费视频网站| 欧美一区二区三区免费大片| 亚洲国产欧美一区| 一本到高清视频免费精品| 国产日本欧美视频| 欧美国产一区二区在线观看| 欧美日韩日日骚| 久久精品水蜜桃av综合天堂| 欧美精品九九99久久| 欧美在线观看网站| 亚洲欧洲另类| 亚洲一区二区三区精品视频| 国产亚洲一区精品| 亚洲精品1区| 国产一区视频在线看| 亚洲国产日韩在线| 韩日成人在线| 日韩视频在线播放| 激情六月婷婷久久| 中文一区二区| 一区二区国产日产| 久久综合九九| 亚洲美女精品久久| 在线亚洲欧美视频| 亚洲电影观看| 亚洲欧美日本精品| 中文精品一区二区三区 | 一区二区三区不卡视频在线观看 | 欧美在线观看天堂一区二区三区| 欧美99久久| 久久久久国产精品厨房| 国产精品jizz在线观看美国 | 国产精品一区二区三区四区五区 | 欧美电影免费观看高清| 久久久久这里只有精品| 国产精品久久久久久av福利软件| 亚洲第一精品久久忘忧草社区| 国产日韩欧美在线观看| 亚洲自拍16p| 午夜免费日韩视频| 国产精品久久久久毛片软件 | 性欧美大战久久久久久久免费观看| 99国产精品99久久久久久粉嫩| 久久久人成影片一区二区三区观看 | 在线视频精品一| 一区二区三区欧美在线| 欧美激情网友自拍| 亚洲欧洲日夜超级视频| 亚洲日本成人| 欧美国产精品久久| 亚洲福利视频一区| 亚洲韩国日本中文字幕| 免费欧美在线视频| 欧美激情精品久久久久久久变态| 在线观看视频一区二区| 久久综合网络一区二区| 中文欧美字幕免费| 久久国产精品毛片| 欧美一级网站| 国产精品夜夜夜一区二区三区尤| 亚洲人成绝费网站色www| 亚洲精品中文字幕女同| 欧美激情第一页xxx| 亚洲伦理在线观看| 亚洲欧美日韩国产综合在线| 国产精品五月天| 亚洲欧美在线网| 久久午夜av| 亚洲大胆在线| 欧美久久综合| 亚洲欧美另类国产| 久久午夜国产精品| 最新中文字幕亚洲| 亚洲一区国产精品| 国产乱码精品一区二区三区av| 欧美在线免费观看亚洲| 欧美大片一区二区| 亚洲一区二区高清视频| 国产日韩欧美自拍| 免费观看成人| 夜夜嗨一区二区| 久久久久久婷| 亚洲精品裸体| 国产日韩精品一区二区| 美女在线一区二区| 日韩一区二区电影网| 欧美在线免费视屏| 亚洲国产日韩综合一区| 欧美午夜精品| 麻豆国产精品777777在线| 亚洲人成7777| 久久婷婷综合激情| 国产精品99久久久久久白浆小说 | 亚洲国产精品成人久久综合一区| 免费短视频成人日韩| 亚洲乱码视频| 免费观看在线综合色| 亚洲欧美三级伦理| 亚洲精品日韩在线观看| 国产精品外国| 欧美日韩国产综合网 | 国产乱理伦片在线观看夜一区| 蜜桃av久久久亚洲精品| 亚洲欧美日韩精品在线| 亚洲欧洲另类国产综合| 美女视频一区免费观看| 亚洲一区二区三区久久| 91久久精品日日躁夜夜躁欧美| 国产精品中文在线| 欧美精品一卡二卡| 欧美aⅴ一区二区三区视频|