muduo網路庫學習之Logger類、LogStream類、LogFile類封裝中的知識點
一、Logger類、LogStream類
1、日誌作用
開發過程中:
除錯錯誤更好的理解程式
執行過程中:
診斷系統故障並處理記錄系統執行狀態
TRACE
指出比DEBUG粒度更細的一些資訊事件(開發過程中使用)
DEBUG
指出細粒度資訊事件對除錯應用程式是非常有幫助的。(開發過程中使用)
INFO
表明訊息在粗粒度級別上突出強調應用程式的執行過程。
WARN
系統能正常執行,但可能會出現潛在錯誤的情形。
ERROR
指出雖然發生錯誤事件,但仍然不影響系統的繼續執行。
FATAL
指出每個嚴重的錯誤事件將會導致應用程式的退出。
class Logger
{
public:
enum LogLevel{
TRACE,DEBUG,INFO,WARN,ERROR,FATAL,NUM_LOG_LEVELS,
};
// compile time calculation of basename of source file
class SourceFile { };
private:
class Impl { };
class Impl { };
};
template<int SIZE>
class FixedBuffer : boost::noncopyable
class FixedBuffer : boost::noncopyable
class LogStream : boost::noncopyable
{
typedef LogStream self;
public: // 4000
};typedef detail::FixedBuffer<detail::kSmallBuffer> Buffer;
class Fmt // : boost::noncopyable
{
public:
{
public:
};template<typename T>Fmt(const char* fmt, T val){ // 按照fmt 格式將val 格式化成字串放入buf_中length_ = snprintf(buf_, sizeof buf_, fmt, val);};
3、formatInteger() //是把數字或者指標的值當作字串寫入
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
const char digits[] = "9876543210123456789"; const char* zero = digits + 9; const char digitsHex[] = "0123456789ABCDEF"; LogStream& LogStream::operator<<(int v) { formatInteger(v); return *this; } template<typename T> void LogStream::formatInteger(T v) { //32 if (buffer_.avail() >= kMaxNumericSize) { size_t len = convert(buffer_.current(), v); buffer_.add(len); } } // Efficient Integer to String Conversions, by Matthew Wilson. template<typename T> size_t convert(char buf[], T value) { T i = value; char* p = buf; do { int lsd = static_cast<int>(i % 10); i /= 10; *p++ = zero[lsd]; } while (i != 0); if (value < 0) { *p++ = '-'; } *p = '\0'; std::reverse(buf, p); return p - buf; } LogStream& LogStream::operator<<(const void* p) { uintptr_t v = reinterpret_cast<uintptr_t>(p); if (buffer_.avail() >= kMaxNumericSize) { char* buf = buffer_.current(); buf[0] = '0'; buf[1] = 'x'; size_t len = convertHex(buf+2, v); buffer_.add(len+2); } return *this; } // Efficient Pointer to String Conversions // uintptr_t on 32bit as unsigned int; on 64bit as unsigned long int size_t convertHex(char buf[], uintptr_t value) { uintptr_t i = value; char* p = buf; do { int lsd = i % 16; i /= 16; *p++ = digitsHex[lsd]; } while (i != 0); *p = '\0'; std::reverse(buf, p); return p - buf; } |
4、Logger使用時序圖:
#define LOG_INFO if (muduo::Logger::logLevel() <= muduo::Logger::INFO) \
muduo::Logger(__FILE__, __LINE__).stream()
muduo::Logger(__FILE__, __LINE__).stream()
LOG_INFO<<“info ...”; // 使用方式
muduo::Logger(__FILE__, __LINE__).stream()<<“info”;
muduo::Logger(__FILE__, __LINE__).stream()<<“info”;
// LogStream& stream() { return impl_.stream_; }
Logger => Impl => LogStream => operator<< FixedBuffer => g_output => g_flush
Logger => Impl => LogStream => operator<< FixedBuffer => g_output => g_flush
棧上匿名的Logger物件使用完就要析構,在~Logger()中呼叫 g_output,即 g_output(buf.data(), buf.length());
如果是FATAL錯誤,還要呼叫g_flush,最後abort()程式。
如果沒有呼叫g_flush,會一直輸出到緩衝區(標準輸出緩衝區,檔案FILE緩衝區)滿才會真的輸出在標準輸出,或者寫入到檔案中去。注:可以使用setvbuf設定緩衝區的大小。
int setvbuf ( FILE * stream, char * buffer, int mode, size_t size );
預設日誌資訊輸出到標準輸出(g_output = defaultOutput、g_flush = defaultFlush),也可以輸出到檔案,使用SetOutput、SetFlush
設定。
測試程式:
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
#include <muduo/base/Logging.h>
#include <errno.h> #include <stdio.h> using namespace muduo; FILE *g_file; void dummyOutput(const char *msg, int len) { if (g_file) { fwrite(msg, 1, len, g_file); } } void dummyFlush() { fflush(g_file); } int main() { g_file = ::fopen("/tmp/muduo_log", "ae"); Logger::setOutput(dummyOutput); Logger::setFlush(dummyFlush); LOG_TRACE << "trace ..."; LOG_DEBUG << "debug ..."; LOG_INFO << "info ..."; LOG_WARN << "warn ..."; LOG_ERROR << "error ..."; //LOG_FATAL<<"fatal ..."; errno = 13; LOG_SYSERR << "syserr ..."; //LOG_SYSFATAL<<"sysfatal ..."; ::fclose(g_file); return 0; } |
程式執行後檢視寫入檔案的內容:
simba@ubuntu:~/Documents/build/debug/bin$ cat /tmp/muduo_log
20131102 12:33:29.812878Z 4021 TRACE main trace ... - Log_test2.cc:28
20131102 12:33:29.813108Z 4021 DEBUG main debug ... - Log_test2.cc:29
20131102 12:33:29.813112Z 4021 INFO info ... - Log_test2.cc:30
20131102 12:33:29.813114Z 4021 WARN warn ... - Log_test2.cc:31
20131102 12:33:29.813117Z 4021 ERROR error ... - Log_test2.cc:32
20131102 12:33:29.813120Z 4021 ERROR Permission denied (errno=13) syserr ... - Log_test2.cc:35
simba@ubuntu:~/Documents/build/debug/bin$
20131102 12:33:29.812878Z 4021 TRACE main trace ... - Log_test2.cc:28
20131102 12:33:29.813108Z 4021 DEBUG main debug ... - Log_test2.cc:29
20131102 12:33:29.813112Z 4021 INFO info ... - Log_test2.cc:30
20131102 12:33:29.813114Z 4021 WARN warn ... - Log_test2.cc:31
20131102 12:33:29.813117Z 4021 ERROR error ... - Log_test2.cc:32
20131102 12:33:29.813120Z 4021 ERROR Permission denied (errno=13) syserr ... - Log_test2.cc:35
simba@ubuntu:~/Documents/build/debug/bin$
5、StringPiece類
// We provide non-explicit singleton constructors so users can pass
// in a "const char*" or a "string" wherever a "StringPiece" is
// expected.
// in a "const char*" or a "string" wherever a "StringPiece" is
// expected.
只是複製字串的指標,故不涉及具體字串記憶體的拷貝,高效地傳遞字串。
class StringPiece {
private:const char* ptr_;
int length_;
....
C++ Code
1
2 3 4 5 6 7 8 9 10 |
#define STRINGPIECE_BINARY_PREDICATE(cmp,auxcmp) \
bool operator cmp (const StringPiece& x) const { \ int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); \ return ((r auxcmp 0) || ((r == 0) && (length_ cmp x.length_))); \ } STRINGPIECE_BINARY_PREDICATE( < , < ); STRINGPIECE_BINARY_PREDICATE( <= , < ); STRINGPIECE_BINARY_PREDICATE( >= , > ); STRINGPIECE_BINARY_PREDICATE( > , > ); #undef STRINGPIECE_BINARY_PREDICATE |
};
執行程式後檢視建立的日誌檔案:
二、LogFile類
日誌滾動條件
檔案大小(例如每寫滿1G換下一個檔案)一個典型的日誌檔名
時間(每天零點新建一個日誌檔案,不論前一個檔案是否寫滿)
logfile_test.20130411-115604.popo.7743.log
// 執行程式.時間.主機名.執行緒名.log
class LogFile :
boost::noncopyable
const string basename_; // 日誌檔案 basename
const size_t rollSize_; // 日誌檔案達到rollSize_換一個新檔案
const int flushInterval_; // 日誌寫入檔案間隔時間
time_t startOfPeriod_; // 開始記錄日誌時間(調整到零時時間)
time_t lastRoll_; // 上一次滾動日誌檔案時間
time_t lashFlush_; // 上一次日誌寫入檔案時間
// 60*60*24
time_t start = now / kRollPerSeconds_ * kRollPerSeconds_;
表示start對齊到kR的整數倍,也就是時間調整到當天零時
// not thread safe
class LogFile::File : boost::noncopyable
class LogFile::File : boost::noncopyable
::setbuffer(fp_,
buffer_, sizeof buffer_);
測試程式:
LogFile_test.cc:
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include <muduo/base/LogFile.h>
#include <muduo/base/Logging.h> boost::scoped_ptr<muduo::LogFile> g_logFile; void outputFunc(const char *msg, int len) { g_logFile->append(msg, len); // scoped_ptr<T> 過載operator->,呼叫LogFile::append(),
// 間接呼叫File::append(); 最後 ::fwrite_unlocked(fp_);
}void flushFunc() { g_logFile->flush(); // scoped_ptr<T> 過載operator->,呼叫LogFile::flush(),
//間接呼叫File::flush(),最後::fflush(fp_);
}int main(int argc, char *argv[]) { char name[256]; strncpy(name, argv[0], 256); g_logFile.reset(new muduo::LogFile(::basename(name), 200 * 1000)); muduo::Logger::setOutput(outputFunc); muduo::Logger::setFlush(flushFunc); muduo::string line = "1234567890 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ "; for (int i = 0; i < 10000; ++i) { LOG_INFO << line << i; // 不斷地構造匿名的Logger物件,在~Logger()中呼叫dummyOutput,將日誌資訊寫入檔案
usleep(1000); } } |
simba@ubuntu:~/Documents/build/debug/bin$ ls -lh *.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:37 logfile_test.20131102-123753.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:37 logfile_test.20131102-123756.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:38 logfile_test.20131102-123759.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:38 logfile_test.20131102-123802.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:38 logfile_test.20131102-123805.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:38 logfile_test.20131102-123808.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 87K Nov 2 05:38 logfile_test.20131102-123811.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:37 logfile_test.20131102-123753.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:37 logfile_test.20131102-123756.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:38 logfile_test.20131102-123759.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:38 logfile_test.20131102-123802.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:38 logfile_test.20131102-123805.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:38 logfile_test.20131102-123808.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 87K Nov 2 05:38 logfile_test.20131102-123811.ubuntu.4044.log
因為我們設定的滾動日誌檔案大小為200 *1000/1024 = 196k,所以現在即使沒有到另一個零時,因為檔案大小已到上限,也會自動滾動檔案。
參考:
muduo manual.pdf
《linux 多執行緒伺服器程式設計:使用muduo c++網路庫》
相關文章
- muduo網路庫學習之MutexLock類、MutexLockGuard類、Condition類、CountDownLatch類封裝中的知識點MutexCountDownLatch封裝
- muduo網路庫學習之BlockinngQueue類、ThreadPool 類、Singleton類封裝中的知識點BloCthread封裝
- muduo網路庫學習之Timestamp類、AtomicIntegerT 類封裝中的知識點封裝
- muduo網路庫學習之ThreadLocal 類、ThreadLocalSingleton類封裝知識點thread封裝
- muduo網路庫學習之Exception類、Thread 類封裝中的知識點(重點講pthread_atfork())Exceptionthread封裝
- muduo網路庫學習筆記(8):高效日誌類的封裝筆記封裝
- muduo網路庫學習之muduo_http 庫涉及到的類HTTP
- muduo網路庫學習之EventLoop(四):EventLoopThread 類、EventLoopThreadPool 類OOPthread
- muduo網路庫學習之muduo_inspect 庫涉及到的類
- muduo網路庫學習筆記(1):Timestamp類筆記
- muduo網路庫學習筆記(3):Thread類筆記thread
- muduo網路庫Timestamp類
- muduo網路庫Exception異常類Exception
- 13封裝網路請求類庫封裝
- muduo網路庫學習筆記(12):TcpServer和TcpConnection類筆記TCPServer
- muduo網路庫AtomicIntegerT原子整數類
- muduo網路庫學習之EventLoop(一):事件迴圈類圖簡介和muduo 定時器TimeQueueOOP事件定時器
- muduo原始碼解析11-logger類原始碼
- muduo網路庫學習筆記(6):單例類(執行緒安全的)筆記單例執行緒
- 靜態庫封裝之ComStr類封裝
- 靜態庫封裝之ComFile類封裝
- 靜態庫封裝之ComDir類封裝
- Laravel 小知識點之 HtmlString 類LaravelHTML
- Java中類的一些知識點Java
- java學習 -- 利用類的反射和泛型自己動手寫jdbc封裝小類庫Java反射泛型JDBC封裝
- JavaSE基礎知識學習-----Object類JavaObject
- java學習之Date類、DateFormat類JavaORM
- 封裝xunsearch類封裝
- JS 封裝類JS封裝
- java學習之基本包裝類Java
- Java學習--Java 中的包裝類Java
- VR垃圾分類體驗系統:學習垃圾分類知識科普VR
- 【入門知識】網路安全中的漏洞分為哪幾類?
- muduo網路庫學習之EventLoop(七):TcpClient、ConnectorOOPTCPclient
- C++中類相關知識點總結C++
- Android之Activity基類封裝Android封裝
- 物件與類_知識點筆記物件筆記
- Stella 知識庫--模型類的設計模型