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

自由的心兒 自由的飛翔

旅程

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>
            欧美日韩国产成人| 亚洲午夜久久久| 女同性一区二区三区人了人一 | 一区二区三区黄色| 久久人91精品久久久久久不卡| 亚洲精品视频免费在线观看| 久久国产精品毛片| 国产精品一区二区视频| 久久综合久久88| 国产日韩欧美黄色| 亚洲免费在线播放| 亚洲精品美女在线观看播放| 99国产精品一区| 欧美激情视频免费观看| …久久精品99久久香蕉国产| 久久久亚洲精品一区二区三区 | 欧美www视频在线观看| 国产日韩亚洲| 久久国产加勒比精品无码| 一本色道久久综合| 欧美性猛片xxxx免费看久爱| 一区二区三区四区五区精品| 亚洲久久成人| 欧美日韩在线一区二区| 宅男噜噜噜66一区二区| 一本色道久久88亚洲综合88| 欧美性猛交xxxx乱大交退制版| 午夜精品一区二区三区四区 | 午夜欧美大尺度福利影院在线看| 国产精品久久77777| 午夜精品久久久久久久白皮肤| 亚洲一区尤物| 国内精品久久久| 久热这里只精品99re8久| 久久天堂精品| 夜色激情一区二区| 一区二区三区精品国产| 国产精品夜夜夜| 久久免费的精品国产v∧| 久久久久久尹人网香蕉| 亚洲人体一区| 在线亚洲伦理| 国产一区二区按摩在线观看| 欧美福利在线观看| 欧美日韩在线高清| 久久精品亚洲一区二区三区浴池| 久久久蜜桃一区二区人| 亚洲理论在线观看| 亚洲欧美国产高清va在线播| 国内一区二区三区| 亚洲精品一区二区三区四区高清| 国产精品麻豆欧美日韩ww| 欧美金8天国| 午夜精品一区二区三区电影天堂| 久久久国产成人精品| 亚洲精品中文字幕女同| 午夜免费日韩视频| 99精品久久免费看蜜臀剧情介绍| 亚洲一区二区三区精品动漫| 在线国产精品播放| 中日韩男男gay无套| 精品成人在线| 中文精品一区二区三区| 亚洲高清在线视频| 一区二区三区视频在线播放| 伊人狠狠色j香婷婷综合| 一区二区久久久久| 久久激情婷婷| 亚洲四色影视在线观看| 久久亚洲欧洲| 性欧美video另类hd性玩具| 美女任你摸久久| 午夜精品999| 欧美成人性网| 美女黄毛**国产精品啪啪| 国产精品久久久久久久久久尿 | 亚洲国语精品自产拍在线观看| 制服丝袜激情欧洲亚洲| 亚洲久久一区| 老牛影视一区二区三区| 久久青青草综合| 国产日韩欧美中文| 亚洲在线成人| 亚洲欧美精品中文字幕在线| 欧美国产第一页| 美女精品在线| 国产三级欧美三级| 亚洲视频在线看| 久久久青草婷婷精品综合日韩| 先锋影音一区二区三区| 欧美日韩大片| 亚洲国产mv| 在线观看一区二区精品视频| 欧美一区二视频| 欧美日韩另类国产亚洲欧美一级| 亚洲成人在线免费| 久久精品国产精品| 国产精品日韩在线观看| 999亚洲国产精| 一本色道久久综合亚洲二区三区| 欧美激情精品久久久久久变态| 美女国产一区| 亚洲日韩欧美视频| 男女精品视频| 国产精品久久久久av| 一本色道久久综合亚洲精品不| 亚洲色在线视频| 欧美日韩视频在线一区二区| 日韩一级精品| 亚洲一区激情| 国产欧美一区二区三区另类精品 | 欧美久久一区| 一本在线高清不卡dvd | 欧美高清你懂得| 亚洲精品欧美精品| 欧美日韩在线视频一区二区| 亚洲一区二区三区777| 久久久国产精彩视频美女艺术照福利| 国产日产高清欧美一区二区三区| 午夜在线视频观看日韩17c| 久久综合影视| 亚洲免费播放| 亚洲图片欧洲图片日韩av| 久久av二区| 在线精品国精品国产尤物884a| 欧美69视频| 一区二区三欧美| 久久久精品动漫| 亚洲激情社区| 国产精品日韩一区二区三区| 久久夜色精品国产欧美乱极品| 亚洲日本无吗高清不卡| 午夜精品福利一区二区三区av| 狠狠干综合网| 欧美视频在线观看免费网址| 午夜在线电影亚洲一区| 最新精品在线| 久久精品91| a4yy欧美一区二区三区| 国产性天天综合网| 欧美日韩视频专区在线播放| 久久夜色精品国产| 亚洲欧美另类在线观看| 欧美激情第五页| 欧美一区二区三区另类| 亚洲剧情一区二区| 激情综合电影网| 国产精品免费aⅴ片在线观看| 噜噜噜久久亚洲精品国产品小说| 亚洲性图久久| 亚洲精品乱码久久久久久按摩观 | 一区二区三区视频观看| 欧美激情第五页| 久久精品在线| 亚洲永久精品大片| 亚洲精品一区二| 在线视频国产日韩| 国产一区二区三区精品久久久 | 久久精品免视看| 亚洲欧美在线免费| 亚洲美女黄网| 最新国产乱人伦偷精品免费网站| 国产日韩精品视频一区二区三区 | 久久久一本精品99久久精品66| 亚洲自啪免费| 一区二区三区日韩在线观看| 亚洲动漫精品| 伊人久久大香线蕉综合热线| 国产欧美日韩专区发布| 国产精品高潮在线| 欧美视频精品在线| 欧美日韩在线高清| 欧美日韩在线亚洲一区蜜芽| 欧美黑人在线播放| 欧美承认网站| 欧美成人首页| 欧美激情一区二区在线 | 在线成人欧美| 狠久久av成人天堂| 国内精品美女在线观看| 国产视频观看一区| 国产麻豆9l精品三级站| 国产精品一区二区久久| 国产精品美女久久久浪潮软件| 欧美午夜免费| 国产精品亚洲成人| 国产一区二区三区av电影| 国产日韩欧美一区二区| 国产亚洲欧洲| 亚洲第一福利视频| 亚洲全黄一级网站| 99精品欧美一区二区三区综合在线| 亚洲人成人一区二区在线观看| 欧美日韩伦理在线| 欧美视频四区| 国产日韩欧美不卡在线| 一区国产精品| 亚洲精品综合精品自拍| 亚洲午夜精品福利| 性视频1819p久久|