muduo库里面的日志使方法如下

  1. 这里定义了一个宏
  2. #define LOG_INFO if (muduo::Logger::logLevel() <= muduo::Logger::INFO) \
  3. muduo::Logger(__FILE__, __LINE__).stream()
  4. 返回的stream重载了一系列的运算符,使用方法如下
  5. LOG_INFO<<“info ...”; // 使用方式
  6. 上面那句其实就是
  7. muduo::Logger(__FILE__, __LINE__).stream()<<“info”;

调用过程实际是如下所示的

Logger => Impl => LogStream => operator<< FixedBuffer => g_output => g_flush

muduo库里面的日志类封装相关的文件为Logging.h,Logging.cc,LogSrtream.h,LogSrtream.cc,附带一个StringPiece.h文件,几个文件的注解如下所示:

Logging.h

  1. //日志输出
  2. #ifndef MUDUO_BASE_LOGGING_H
  3. #define MUDUO_BASE_LOGGING_H
  4. #include <muduo/base/LogStream.h>
  5. #include <muduo/base/Timestamp.h>
  6. namespace muduo
  7. {
  8. class Logger
  9. {
  10. public:
  11. //日志级别
  12. enum LogLevel
  13. {
  14. TRACE,
  15. DEBUG,
  16. INFO,
  17. WARN,
  18. ERROR,
  19. FATAL,
  20. NUM_LOG_LEVELS,//级别个数6
  21. };
  22. // compile time calculation of basename of source file
  23. class SourceFile
  24. {
  25. public:
  26. template<int N>
  27. inline SourceFile(const char (&arr)[N])
  28. : data_(arr),
  29. size_(N-1)
  30. {
  31. const char* slash = strrchr(data_, '/'); // builtin function
  32. if (slash)
  33. {
  34. data_ = slash + 1;
  35. size_ -= static_cast<int>(data_ - arr);
  36. }
  37. }
  38. explicit SourceFile(const char* filename)
  39. : data_(filename)
  40. {
  41. const char* slash = strrchr(filename, '/');
  42. if (slash)
  43. {
  44. data_ = slash + 1;
  45. }
  46. size_ = static_cast<int>(strlen(data_));
  47. }
  48. const char* data_;
  49. int size_;
  50. };
  51. //四个构造函数
  52. Logger(SourceFile file, int line);
  53. Logger(SourceFile file, int line, LogLevel level);
  54. Logger(SourceFile file, int line, LogLevel level, const char* func);
  55. Logger(SourceFile file, int line, bool toAbort);
  56. ~Logger();
  57. LogStream& stream() { return impl_.stream_; }
  58. static LogLevel logLevel();
  59. static void setLogLevel(LogLevel level);
  60. typedef void (*OutputFunc)(const char* msg, int len);
  61. typedef void (*FlushFunc)();
  62. static void setOutput(OutputFunc);
  63. static void setFlush(FlushFunc);
  64. private:
  65. //Loger类的内部嵌套类
  66. //Impl类主要是负责日志的格式化
  67. class Impl
  68. {
  69. public:
  70. typedef Logger::LogLevel LogLevel;
  71. //构造函数
  72. Impl(LogLevel level, int old_errno, const SourceFile& file, int line);
  73. //格式化时间函数
  74. void formatTime();
  75. void finish();
  76. Timestamp time_;//Timestamp时间戳
  77. LogStream stream_;//LogStream类对象成员
  78. LogLevel level_;//日志级别
  79. int line_;//行号
  80. SourceFile basename_;
  81. };
  82. Impl impl_;//Impl类对象成员
  83. };
  84. extern Logger::LogLevel g_logLevel;
  85. inline Logger::LogLevel Logger::logLevel()
  86. {
  87. return g_logLevel;//日志级别
  88. }
  89. //日志输出宏,输出在哪个文件? 哪一行? 哪个函数? 哪种级别?
  90. //无名对象所在语句执行后就立即被析构,然后调用析构函数将缓冲区的内容分输出
  91. // muduo::Logger(__FILE__, __LINE__, muduo::Logger::TRACE, __func__).stream()返回的是一个LogStream对象
  92. #define LOG_TRACE if (muduo::Logger::logLevel() <= muduo::Logger::TRACE) \
  93. muduo::Logger(__FILE__, __LINE__, muduo::Logger::TRACE, __func__).stream()
  94. #define LOG_DEBUG if (muduo::Logger::logLevel() <= muduo::Logger::DEBUG) \
  95. muduo::Logger(__FILE__, __LINE__, muduo::Logger::DEBUG, __func__).stream()
  96. #define LOG_INFO if (muduo::Logger::logLevel() <= muduo::Logger::INFO) \
  97. muduo::Logger(__FILE__, __LINE__).stream()
  98. #define LOG_WARN muduo::Logger(__FILE__, __LINE__, muduo::Logger::WARN).stream()
  99. #define LOG_ERROR muduo::Logger(__FILE__, __LINE__, muduo::Logger::ERROR).stream()
  100. #define LOG_FATAL muduo::Logger(__FILE__, __LINE__, muduo::Logger::FATAL).stream()
  101. //false表示不会退出程序
  102. #define LOG_SYSERR muduo::Logger(__FILE__, __LINE__, false).stream()//ERROR
  103. //true表示会退出程序
  104. #define LOG_SYSFATAL muduo::Logger(__FILE__, __LINE__, true).stream()//FATAL
  105. const char* strerror_tl(int savedErrno);
  106. // Taken from glog/logging.h
  107. //
  108. // Check that the input is non NULL. This very useful in constructor
  109. // initializer lists.
  110. #define CHECK_NOTNULL(val) \
  111. ::muduo::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val))
  112. // A small helper for CHECK_NOTNULL().
  113. template <typename T>
  114. T* CheckNotNull(Logger::SourceFile file, int line, const char *names, T* ptr) {
  115. if (ptr == NULL) {
  116. Logger(file, line, Logger::FATAL).stream() << names;
  117. }
  118. return ptr;
  119. }
  120. }
  121. #endif // MUDUO_BASE_LOGGING_H

Logging.cc

  1. #include <muduo/base/Logging.h>
  2. #include <muduo/base/CurrentThread.h>
  3. #include <muduo/base/StringPiece.h>
  4. #include <muduo/base/Timestamp.h>
  5. #include <errno.h>
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <sstream>
  9. namespace muduo
  10. {
  11. /*
  12. class LoggerImpl
  13. {
  14. public:
  15. typedef Logger::LogLevel LogLevel;
  16. LoggerImpl(LogLevel level, int old_errno, const char* file, int line);
  17. void finish();
  18. Timestamp time_;
  19. LogStream stream_;
  20. LogLevel level_;
  21. int line_;
  22. const char* fullname_;
  23. const char* basename_;
  24. };
  25. */
  26. __thread char t_errnobuf[512];
  27. __thread char t_time[32];
  28. __thread time_t t_lastSecond;
  29. const char* strerror_tl(int savedErrno)
  30. {
  31. return strerror_r(savedErrno, t_errnobuf, sizeof t_errnobuf);
  32. }
  33. //初始化日志级别
  34. Logger::LogLevel initLogLevel()
  35. {//获取环境变量
  36. if (::getenv("MUDUO_LOG_TRACE"))//如果获取到了这个环境变量
  37. return Logger::TRACE;//日志级别为TRACE
  38. else if (::getenv("MUDUO_LOG_DEBUG"))//如果获取到了这个环境变量
  39. return Logger::DEBUG;//日志级别为DEBUG
  40. else
  41. return Logger::INFO;//否则日志级别为INFO
  42. }
  43. Logger::LogLevel g_logLevel = initLogLevel();
  44. //日志级别
  45. const char* LogLevelName[Logger::NUM_LOG_LEVELS] =
  46. {
  47. "TRACE ",
  48. "DEBUG ",
  49. "INFO ",
  50. "WARN ",
  51. "ERROR ",
  52. "FATAL ",
  53. };
  54. // helper class for known string length at compile time
  55. class T
  56. {
  57. public:
  58. T(const char* str, unsigned len)
  59. :str_(str),
  60. len_(len)
  61. {
  62. assert(strlen(str) == len_);
  63. }
  64. const char* str_;
  65. const unsigned len_;
  66. };
  67. inline LogStream& operator<<(LogStream& s, T v)
  68. {
  69. s.append(v.str_, v.len_);
  70. return s;
  71. }
  72. inline LogStream& operator<<(LogStream& s, const Logger::SourceFile& v)
  73. {
  74. s.append(v.data_, v.size_);
  75. return s;
  76. }
  77. //默认输出
  78. void defaultOutput(const char* msg, int len)
  79. {//输出到标准输出
  80. size_t n = fwrite(msg, 1, len, stdout);
  81. //FIXME check n
  82. (void)n;
  83. }
  84. //默认清空
  85. void defaultFlush()
  86. {//默认清空标准输出
  87. fflush(stdout);
  88. }
  89. Logger::OutputFunc g_output = defaultOutput;
  90. Logger::FlushFunc g_flush = defaultFlush;
  91. }
  92. using namespace muduo;
  93. //Impl类的构造函数
  94. //级别,错误(没有错误则传0),文件,行
  95. //Impl类主要是负责日志的格式化
  96. Logger::Impl::Impl(LogLevel level, int savedErrno, const SourceFile& file, int line)
  97. : time_(Timestamp::now()),//登记当前的时间
  98. stream_(),//LogStream类
  99. level_(level),//级别
  100. line_(line),//行
  101. basename_(file)//文件名称
  102. {
  103. formatTime();//格式化时间
  104. CurrentThread::tid();//缓存当前线程的id
  105. //输出字符串格式的线程id
  106. stream_ << T(CurrentThread::tidString(), 6);
  107. stream_ << T(LogLevelName[level], 6);
  108. if (savedErrno != 0)//如果savedErrno不为零,还要输出对应的信息
  109. {
  110. stream_ << strerror_tl(savedErrno) << " (errno=" << savedErrno << ") ";
  111. }
  112. }
  113. void Logger::Impl::formatTime()
  114. {
  115. int64_t microSecondsSinceEpoch = time_.microSecondsSinceEpoch();//获得微秒格式的时间
  116. time_t seconds = static_cast<time_t>(microSecondsSinceEpoch / 1000000);//获得秒
  117. int microseconds = static_cast<int>(microSecondsSinceEpoch % 1000000);//微秒
  118. if (seconds != t_lastSecond)
  119. {
  120. t_lastSecond = seconds;
  121. struct tm tm_time;
  122. ::gmtime_r(&seconds, &tm_time); // FIXME TimeZone::fromUtcTime
  123. int len = snprintf(t_time, sizeof(t_time), "%4d%02d%02d %02d:%02d:%02d",
  124. tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
  125. tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec);
  126. assert(len == 17); (void)len;
  127. }
  128. Fmt us(".%06dZ ", microseconds);
  129. assert(us.length() == 9);
  130. //LogStream类重载运算符,把信息输出到缓冲区
  131. stream_ << T(t_time, 17) << T(us.data(), 9);
  132. }
  133. void Logger::Impl::finish()
  134. {
  135. stream_ << " - " << basename_ << ':' << line_ << '\n';
  136. }
  137. //构造函数,都是构造Impl对象
  138. Logger::Logger(SourceFile file, int line) : impl_(INFO, 0, file, line)
  139. {
  140. }
  141. //文件名,行,级别,函数名称
  142. Logger::Logger(SourceFile file, int line, LogLevel level, const char* func) : impl_(level, 0, file, line)
  143. {//格式化函数名称
  144. impl_.stream_ << func << ' ';
  145. }
  146. Logger::Logger(SourceFile file, int line, LogLevel level): impl_(level, 0, file, line)
  147. {
  148. }
  149. //如果toAbort是真,则级别为FATAL,否则为ERROR
  150. Logger::Logger(SourceFile file, int line, bool toAbort) : impl_(toAbort?FATAL:ERROR, errno, file, line)
  151. {
  152. }
  153. //析构函数
  154. Logger::~Logger()
  155. {
  156. impl_.finish();
  157. //取出stream类缓冲区的内容放到buf
  158. const LogStream::Buffer& buf(stream().buffer());
  159. //输出,g_output有一个默认的输出stdout
  160. g_output(buf.data(), buf.length());
  161. if (impl_.level_ == FATAL)//如果是FATAL
  162. {
  163. g_flush();//清空缓冲区
  164. abort();//终止程序
  165. }
  166. }
  167. void Logger::setLogLevel(Logger::LogLevel level)
  168. {
  169. g_logLevel = level;
  170. }
  171. //更改输出函数
  172. void Logger::setOutput(OutputFunc out)
  173. {
  174. g_output = out;
  175. }
  176. void Logger::setFlush(FlushFunc flush)
  177. {
  178. g_flush = flush;
  179. }

LogSrtream.h

  1. //日志流
  2. #ifndef MUDUO_BASE_LOGSTREAM_H
  3. #define MUDUO_BASE_LOGSTREAM_H
  4. #include <muduo/base/StringPiece.h>
  5. #include <muduo/base/Types.h>
  6. #include <assert.h>
  7. #include <string.h> // memcpy
  8. #ifndef MUDUO_STD_STRING
  9. #include <string>
  10. #endif
  11. #include <boost/noncopyable.hpp>
  12. namespace muduo
  13. {
  14. namespace detail
  15. {
  16. //定义两个缓冲区大小的常量
  17. const int kSmallBuffer = 4000;
  18. const int kLargeBuffer = 4000*1000;
  19. //缓冲区类
  20. //模板,但是SIZE是非类型参数
  21. template<int SIZE>
  22. class FixedBuffer : boost::noncopyable//不可被拷贝
  23. {
  24. public:
  25. //构造函数
  26. FixedBuffer() : cur_(data_)//初始化当前指针
  27. {//设置函数指针
  28. setCookie(cookieStart);
  29. }
  30. //析构函数
  31. ~FixedBuffer()
  32. {//传递函数指针,这个和构造函数传递的两个函数在下面
  33. setCookie(cookieEnd);
  34. }
  35. //添加数据
  36. void append(const char* /*restrict*/ buf, size_t len)
  37. {
  38. // FIXME: append partially当前可用空间长度大于len
  39. if (implicit_cast<size_t>(avail()) > len)
  40. {//复制数据
  41. memcpy(cur_, buf, len);
  42. //更新当前指针
  43. cur_ += len;
  44. }
  45. //如果当前空间不够用了,这里并没有实现添加部分进来
  46. }
  47. const char* data() const { return data_; }
  48. //已经用的长度空间
  49. int length() const { return static_cast<int>(cur_ - data_); }
  50. // write to data_ directly
  51. char* current() { return cur_; }
  52. //当前可用的空间(end减去当前指针)
  53. int avail() const { return static_cast<int>(end() - cur_); }
  54. //增加
  55. void add(size_t len) { cur_ += len; }
  56. //重置空间
  57. void reset() { cur_ = data_; }
  58. //把数据都清零,相当于memset(buf,0,sizeof(buf))
  59. void bzero() { ::bzero(data_, sizeof data_); }
  60. // for used by GDB
  61. //在数据后面加个结束符
  62. const char* debugString();
  63. //将函数指针指向传递进来的函数
  64. void setCookie(void (*cookie)()) { cookie_ = cookie; }
  65. // for used by unit test
  66. //把数据构造一个String对象出来
  67. string asString() const { return string(data_, length()); }
  68. private:
  69. //返回的是缓冲区的后一个地址
  70. const char* end() const { return data_ + sizeof data_; }
  71. // Must be outline function for cookies.
  72. static void cookieStart();
  73. static void cookieEnd();
  74. void (*cookie_)();//一个函数指针
  75. char data_[SIZE];//data就是缓冲区,容量为传进来的SIZE
  76. char* cur_;//当前指针
  77. };
  78. }
  79. //LogStream类主要是封装了插入运算符
  80. class LogStream : boost::noncopyable
  81. {
  82. typedef LogStream self;
  83. public:
  84. //包含了LogStream的缓冲区,kSmallBuffer,k开头的表示一个常量,是谷歌的编程规范
  85. typedef detail::FixedBuffer<detail::kSmallBuffer> Buffer;
  86. //输出数据首先是输出到缓冲区当中
  87. //以下重载了各种类型的插入运算符
  88. //返回的是自身的引用
  89. self& operator<<(bool v)
  90. {//输出布尔类型
  91. buffer_.append(v ? "1" : "0", 1);//长度是1
  92. return *this;
  93. }
  94. //实现在.cc文件
  95. self& operator<<(short);
  96. self& operator<<(unsigned short);
  97. self& operator<<(int);
  98. self& operator<<(unsigned int);
  99. self& operator<<(long);
  100. self& operator<<(unsigned long);
  101. self& operator<<(long long);
  102. self& operator<<(unsigned long long);
  103. //存放指针
  104. self& operator<<(const void*);
  105. //浮点数
  106. self& operator<<(float v)
  107. {
  108. *this << static_cast<double>(v);
  109. return *this;
  110. }
  111. self& operator<<(double);
  112. // self& operator<<(long double);
  113. //存放单个字符
  114. self& operator<<(char v)
  115. {
  116. buffer_.append(&v, 1);
  117. return *this;
  118. }
  119. // self& operator<<(signed char);
  120. // self& operator<<(unsigned char);
  121. //存放字符串
  122. self& operator<<(const char* v)
  123. {//把字符串添加进缓冲区
  124. buffer_.append(v, strlen(v));
  125. return *this;
  126. }
  127. self& operator<<(const string& v)
  128. {
  129. buffer_.append(v.c_str(), v.size());
  130. return *this;
  131. }
  132. //如果定义了MUDUO_STD_STRING,则使用的是std::string
  133. //否则使用的是__gnu_cxx::__sso_string
  134. #ifndef MUDUO_STD_STRING
  135. self& operator<<(const std::string& v)
  136. {
  137. buffer_.append(v.c_str(), v.size());
  138. return *this;
  139. }
  140. #endif
  141. self& operator<<(const StringPiece& v)
  142. {
  143. buffer_.append(v.data(), v.size());
  144. return *this;
  145. }
  146. //这三个只是改装了以下接口
  147. void append(const char* data, int len) { buffer_.append(data, len); }
  148. const Buffer& buffer() const { return buffer_; }
  149. void resetBuffer() { buffer_.reset(); }
  150. private:
  151. void staticCheck();
  152. //成员模板函数
  153. template<typename T>
  154. void formatInteger(T);
  155. Buffer buffer_;//大小为kSmallBuffer的缓冲区
  156. static const int kMaxNumericSize = 32;
  157. };
  158. class Fmt // : boost::noncopyable
  159. {
  160. public:
  161. //成员模板,把val进行格式化,然后存放到buf中
  162. template<typename T>
  163. Fmt(const char* fmt, T val);
  164. const char* data() const { return buf_; }//返回格式化的数据
  165. int length() const { return length_; }//返回长度
  166. private:
  167. char buf_[32];
  168. int length_;
  169. };
  170. inline LogStream& operator<<(LogStream& s, const Fmt& fmt)
  171. {
  172. s.append(fmt.data(), fmt.length());
  173. return s;
  174. }
  175. }
  176. #endif // MUDUO_BASE_LOGSTREAM_H

LogSrtream.cc

  1. #include <muduo/base/LogStream.h>
  2. #include <algorithm>
  3. #include <limits>
  4. #include <boost/static_assert.hpp>
  5. #include <boost/type_traits/is_arithmetic.hpp>
  6. #include <assert.h>
  7. #include <string.h>
  8. #include <stdint.h>
  9. #include <stdio.h>
  10. using namespace muduo;
  11. using namespace muduo::detail;
  12. #pragma GCC diagnostic ignored "-Wtype-limits"
  13. //#pragma GCC diagnostic error "-Wtype-limits"
  14. namespace muduo
  15. {
  16. namespace detail
  17. {
  18. const char digits[] = "9876543210123456789";
  19. const char* zero = digits + 9;//digits + 9就是"0"
  20. BOOST_STATIC_ASSERT(sizeof(digits) == 20);
  21. const char digitsHex[] = "0123456789ABCDEF";
  22. BOOST_STATIC_ASSERT(sizeof digitsHex == 17);
  23. // Efficient Integer to String Conversions, by Matthew Wilson.
  24. //将 一个数转换成字符串
  25. template<typename T>
  26. size_t convert(char buf[], T value)
  27. {
  28. T i = value;
  29. char* p = buf;
  30. do
  31. {//对10取模得到最后一位数字
  32. int lsd = static_cast<int>(i % 10);
  33. i /= 10;//更新当前数
  34. //zero将数字转换成字符串,zero指针指向的字符是0,再偏移lsd个位置可以得到相应的字符
  35. *p++ = zero[lsd];
  36. } while (i != 0);
  37. //比如-123会转成"321-"
  38. if (value < 0)//如果要转换的值小于0
  39. {
  40. *p++ = '-';
  41. }
  42. *p = '\0';//添加结束符
  43. std::reverse(buf, p);//使用reverse将字符串进行逆转
  44. return p - buf;//返回转换的字符数
  45. }
  46. //uintptr_t类型对于32位平台来说就是unsigned int
  47. //对于64位平台来说就是unsigned long int
  48. size_t convertHex(char buf[], uintptr_t value)
  49. {//转换成16进制的字符,和转换成10进制的差不多
  50. uintptr_t i = value;
  51. char* p = buf;
  52. do
  53. {
  54. int lsd = i % 16;
  55. i /= 16;
  56. *p++ = digitsHex[lsd];
  57. } while (i != 0);
  58. *p = '\0';
  59. std::reverse(buf, p);
  60. return p - buf;
  61. }
  62. }
  63. }
  64. //在数据后面加个\0,相当于字符串
  65. template<int SIZE>
  66. const char* FixedBuffer<SIZE>::debugString()
  67. {
  68. *cur_ = '\0';//加入结束符
  69. return data_;
  70. }
  71. template<int SIZE>
  72. void FixedBuffer<SIZE>::cookieStart()
  73. {
  74. }
  75. template<int SIZE>
  76. void FixedBuffer<SIZE>::cookieEnd()
  77. {
  78. }
  79. template class FixedBuffer<kSmallBuffer>;
  80. template class FixedBuffer<kLargeBuffer>;
  81. void LogStream::staticCheck()
  82. {
  83. BOOST_STATIC_ASSERT(kMaxNumericSize - 10 > std::numeric_limits<double>::digits10);
  84. BOOST_STATIC_ASSERT(kMaxNumericSize - 10 > std::numeric_limits<long double>::digits10);
  85. BOOST_STATIC_ASSERT(kMaxNumericSize - 10 > std::numeric_limits<long>::digits10);
  86. BOOST_STATIC_ASSERT(kMaxNumericSize - 10 > std::numeric_limits<long long>::digits10);
  87. }
  88. //类型转换成员模板的实现
  89. template<typename T>
  90. void LogStream::formatInteger(T v)
  91. {//当前缓冲区大于32
  92. if (buffer_.avail() >= kMaxNumericSize)//kMaxNumericSize为32
  93. {//把v转换成字符串,存放到buffer_.current()
  94. size_t len = convert(buffer_.current(), v);
  95. //调整buffer_.current()指针
  96. buffer_.add(len);
  97. }
  98. }
  99. //重载各种运算符
  100. LogStream& LogStream::operator<<(short v)
  101. {//short转成int
  102. *this << static_cast<int>(v);
  103. return *this;
  104. }
  105. LogStream& LogStream::operator<<(unsigned short v)
  106. {//unsigned short转成unsigned int
  107. *this << static_cast<unsigned int>(v);
  108. return *this;
  109. }
  110. LogStream& LogStream::operator<<(int v)
  111. {
  112. formatInteger(v);
  113. return *this;
  114. }
  115. LogStream& LogStream::operator<<(unsigned int v)
  116. {
  117. formatInteger(v);
  118. return *this;
  119. }
  120. LogStream& LogStream::operator<<(long v)
  121. {
  122. formatInteger(v);
  123. return *this;
  124. }
  125. LogStream& LogStream::operator<<(unsigned long v)
  126. {
  127. formatInteger(v);
  128. return *this;
  129. }
  130. LogStream& LogStream::operator<<(long long v)
  131. {
  132. formatInteger(v);
  133. return *this;
  134. }
  135. LogStream& LogStream::operator<<(unsigned long long v)
  136. {
  137. formatInteger(v);
  138. return *this;
  139. }
  140. //转换指针,是转成16进制的
  141. LogStream& LogStream::operator<<(const void* p)
  142. {//把指针强制转换为uintptr_t类型
  143. //uintptr_t类型对于32位平台来说就是unsigned int
  144. //对于64位平台来说就是unsigned long int
  145. uintptr_t v = reinterpret_cast<uintptr_t>(p);
  146. if (buffer_.avail() >= kMaxNumericSize)
  147. {
  148. char* buf = buffer_.current();//获取当前的位置
  149. buf[0] = '0';//添加两个字符表示是16进制
  150. buf[1] = 'x';
  151. size_t len = convertHex(buf+2, v);
  152. buffer_.add(len+2);//更新当前指针
  153. }
  154. return *this;
  155. }
  156. // FIXME: replace this with Grisu3 by Florian Loitsch.
  157. LogStream& LogStream::operator<<(double v)
  158. {
  159. if (buffer_.avail() >= kMaxNumericSize)
  160. {
  161. int len = snprintf(buffer_.current(), kMaxNumericSize, "%.12g", v);
  162. buffer_.add(len);
  163. }
  164. return *this;
  165. }
  166. //把T按fmt格式化后存放到buf中
  167. template<typename T>
  168. Fmt::Fmt(const char* fmt, T val)
  169. {//断言T是算术类型
  170. BOOST_STATIC_ASSERT(boost::is_arithmetic<T>::value == true);
  171. //使用snprintf函数进行格式化
  172. length_ = snprintf(buf_, sizeof buf_, fmt, val);
  173. assert(static_cast<size_t>(length_) < sizeof buf_);
  174. }
  175. // Explicit instantiations
  176. //模板的特化
  177. template Fmt::Fmt(const char* fmt, char);
  178. template Fmt::Fmt(const char* fmt, short);
  179. template Fmt::Fmt(const char* fmt, unsigned short);
  180. template Fmt::Fmt(const char* fmt, int);
  181. template Fmt::Fmt(const char* fmt, unsigned int);
  182. template Fmt::Fmt(const char* fmt, long);
  183. template Fmt::Fmt(const char* fmt, unsigned long);
  184. template Fmt::Fmt(const char* fmt, long long);
  185. template Fmt::Fmt(const char* fmt, unsigned long long);
  186. template Fmt::Fmt(const char* fmt, float);
  187. template Fmt::Fmt(const char* fmt, double);

编写两个简单的程序使用下日志功能,Log_test1.cc将日志输出到终端,代码如下

  1. //日志输出到标准输出
  2. #include <muduo/base/Logging.h>
  3. #include <errno.h>
  4. using namespace muduo;
  5. int main()
  6. { //简单的使用下日志输出
  7. //各种级别的日志输出
  8. LOG_TRACE<<"trace ...";
  9. LOG_DEBUG<<"debug ...";
  10. LOG_INFO<<"info ...";
  11. LOG_WARN<<"warn ...";
  12. LOG_ERROR<<"error ...";
  13. //LOG_FATAL<<"fatal ...";//这里会中断程序,先注释掉
  14. errno = 13;
  15. LOG_SYSERR<<"syserr ...";
  16. //LOG_SYSFATAL<<"sysfatal ...";//这里会中断程序,先注释掉
  17. return 0;
  18. }

运行结果如下所示:



Log_test2.cc将日志输出到文件,代码如下所示:

  1. //日志输出到文件
  2. #include <muduo/base/Logging.h>
  3. #include <errno.h>
  4. #include <stdio.h>
  5. using namespace muduo;
  6. FILE* g_file;//定义一个文件
  7. //muduo中的 typedef void (*OutputFunc)(const char* msg, int len);
  8. void dummyOutput(const char* msg, int len)
  9. {
  10. if (g_file)
  11. {//将内容写到文件里
  12. fwrite(msg, 1, len, g_file);
  13. }
  14. }
  15. void dummyFlush()
  16. {
  17. fflush(g_file);//清空输出
  18. }
  19. int main()
  20. {
  21. g_file = ::fopen("/mnt/hgfs/lcw_program/lcw_muduo_learning/tests/muduo_log", "ae");//打开文件
  22. Logger::setOutput(dummyOutput);//设置输出到文件,dummyOutput为函数
  23. Logger::setFlush(dummyFlush);
  24. LOG_TRACE<<"trace ...";
  25. LOG_DEBUG<<"debug ...";
  26. LOG_INFO<<"info ...";
  27. LOG_WARN<<"warn ...";
  28. LOG_ERROR<<"error ...";
  29. //LOG_FATAL<<"fatal ...";//这里会中断程序,先注释掉
  30. errno = 13;
  31. LOG_SYSERR<<"syserr ...";
  32. //LOG_SYSFATAL<<"sysfatal ...";
  33. ::fclose(g_file);//关闭文件
  34. return 0;
  35. }

运行结果如下:



文件内容如下:

muduo网络库源码学习————日志类封装的更多相关文章

  1. muduo网络库源码学习————线程类

    muduo库里面的线程类是使用基于对象的编程思想,源码目录为muduo/base,如下所示: 线程类头文件: // Use of this source code is governed by a B ...

  2. muduo网络库源码学习————日志滚动

    muduo库里面的实现日志滚动有两种条件,一种是日志文件大小达到预设值,另一种是时间到达超过当天.滚动日志类的文件是LogFile.cc ,LogFile.h 代码如下: LogFile.cc #in ...

  3. muduo网络库源码学习————Exception类

    Exception类是为异常捕获而设计,可以获得异常的信息以及栈的回溯信息 (原来的代码没有demangle成员函数,输出的格式比较难看,加了demangle成员函数,利用demangle成员函数可以 ...

  4. muduo网络库源码学习————Timestamp.cc

    今天开始学习陈硕先生的muduo网络库,moduo网络库得到很多好评,陈硕先生自己也说核心代码不超过5000行,所以我觉得有必要拿过来好好学习下,学习的时候在源码上面添加一些自己的注释,方便日后理解, ...

  5. muduo网络库源码学习————线程本地单例类封装

    muduo库中线程本地单例类封装代码是ThreadLocalSingleton.h 如下所示: //线程本地单例类封装 // Use of this source code is governed b ...

  6. muduo网络库源码学习————线程池实现

    muduo库里面的线程池是固定线程池,即创建的线程池里面的线程个数是一定的,不是动态的.线程池里面一般要包含线程队列还有任务队列,外部程序将任务存放到线程池的任务队列中,线程池中的线程队列执行任务,也 ...

  7. muduo网络库源码学习————互斥锁

    muduo源码的互斥锁源码位于muduo/base,Mutex.h,进行了两个类的封装,在实际的使用中更常使用MutexLockGuard类,因为该类可以在析构函数中自动解锁,避免了某些情况忘记解锁. ...

  8. muduo网络库源码学习————线程特定数据

    muduo库线程特定数据源码文件为ThreadLocal.h //线程本地存储 // Use of this source code is governed by a BSD-style licens ...

  9. muduo网络库源码学习————无界队列和有界队列

    muduo库里实现了两个队列模板类:无界队列为BlockingQueue.h,有界队列为BoundedBlockingQueue.h,两个测试程序实现了生产者和消费者模型.(这里以无界队列为例,有界队 ...

随机推荐

  1. 2017蓝桥杯最大公共子串(C++B组)

    题目: 最大公共子串长度问题就是:求两个串的所有子串中能够匹配上的最大长度是多少.比如:"abcdkkk" 和 "baabcdadabc",可以找到的最长的公共 ...

  2. Linux常用命令02(远程管理)

    01 关机/重启 序号 命令 对应英文 作用 01 shutdown 选项 时间 shutdown 关机/重新启动 1.1 shutdown shutdown 命令可以 安全 关闭 或者 重新启动系统 ...

  3. Python—一个简单搜索引擎索引库

    因为课业要求,搭建一个简单的搜索引擎,找了一些相关资料并进行了部分优化(坑有点多) 一.数据 数据是网络上爬取的旅游相关的攻略页面 这个是travels表,在索引中主要用到id和url两个字段. 页面 ...

  4. stand up meeting 12/8/2015

    part 组员 今日工作 工作耗时/h 明日计划 工作耗时/h UI 冯晓云  --------------    --  -----------  -- PDF Reader 朱玉影         ...

  5. Bi-shoe and Phi-shoe LightOJ - 1370

    欧拉函数. 欧拉函数打表模板: #define maxn 3000010 int p[maxn]; void oula(){ int i,j; ; i<=maxn; i++) p[i]=i; ; ...

  6. PHP本地开发利器:内置Web Server

    PHP 5.4.0起, CLI SAPI 提供了一个内置的Web服务器. 命令:php -S 这个内置的Web服务器主要用于本地开发使用,不可用于线上产品环境. URI请求会被发送到PHP所在的的工作 ...

  7. ntp和chrony

    目录 chrony 简介 ntp pool ntp 配置文件 chrony 配置文件 chronyc 命令行工具 修改时区 chrony 简介 chrony 是 RedHat 开发的,它是网络时间协议 ...

  8. Java面试系列第2篇-Object类中的方法

    Java的Object是所有引用类型的父类,定义的方法按照用途可以分为以下几种: (1)构造函数 (2)hashCode() 和 equals() 函数用来判断对象是否相同 (3)wait().wai ...

  9. pytorch 中HWC转CHW

    import torch import numpy as np from torchvision.transforms import ToTensor t = torch.tensor(np.aran ...

  10. python安装pil库,操作流程以及安装中出现的问题。

    0.用管理员方式打开cmd窗口. 1.跳转到python对应目录 比我: ***或者直接在该路径下输入cmd直接跳转.**** 例如: 直接回车搞定!! 2.输入 pip install pillow ...