Muduo 原版作者认为没有必要为Linux 服务器使用C++新标准线程库、时间表示等特性,但我想学习以下新知识还是有必要的;
后面将POSIX 标准替换成已有的C++标准库;
1. Timestamp
Timestamp,时间戳,记录时间相关信息;
gmtime_r(&seconds, &tm_time) 获取的是世界标准时间,localtime_r(&seconds, &tm_time) 可以依据硬件信息选择当前所在时区;
C++11 提供了chrono 库,可以如下获取当前时间;
Timestamp Timestamp::now() {
return Timestamp(std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count());
}
获取的时间单位是微秒级别;
2. Log
Log 是日志系统,为了防止系统无法处理错误,或者为了单独的错误而中断整体运行;
当前未实现异步;
2.1 LogStream
日志流的整体思路如上;
关于Boost 单元测试框架:
Boost Unit Test 包含头文件后定义测试Module 即可使用
BOOST_AUTO_TEST_CASE(TestName) {
BOOST_CHECK_EQUAL(a, b);
}
单元测试由n 个BOOST_AUTO_TEST_CASE 构成,普通的ASSERT 断言会使程序异常退出,但是单元测试会继续测试直至全部测试完毕;
测试框架以后应该尝试下Google Test;
2.2 Logger
Logger 是日志输入输出的接口,与外界交互;包含了时间戳、LogStream ;
采用C++ 风格的日志输入模式:
LOG_INFO << "Hello, world!";
并提供日志等级:
enum LogLevel {
TRACE,
DEBUG,
INFO,
WARN,
ERROR,
FATAL,
NUM_LOG_LEVELS,
};
当前记录等级若大于调用等级则当作空语句,表示不关心;
当前记录等级默认为INFO,getenv 获取当前设置并以g_logLevel 表示
Logger::LogLevel initLogLevel() {
if (::getenv("MUDUO_LOG_TRACE"))
return Logger::TRACE;
else if (::getenv("MUDUO_LOG_DEBUG"))
return Logger::DEBUG;
else
return Logger::INFO;
}
LOG_INFO 等日志输入由宏封装而成;
#define LOG_TRACE \
if (TinyMuduo::Logger::logLevel() <= TinyMuduo::Logger::TRACE) \
TinyMuduo::Logger(__FILE__, __LINE__, TinyMuduo::Logger::TRACE, __func__) \
.stream()
#define LOG_DEBUG \
if (TinyMuduo::Logger::logLevel() <= TinyMuduo::Logger::DEBUG) \
TinyMuduo::Logger(__FILE__, __LINE__, TinyMuduo::Logger::DEBUG, __func__) \
.stream()
#define LOG_INFO \
if (TinyMuduo::Logger::logLevel() <= TinyMuduo::Logger::INFO) \
TinyMuduo::Logger(__FILE__, __LINE__).stream()
#define LOG_WARN \
TinyMuduo::Logger(__FILE__, __LINE__, TinyMuduo::Logger::WARN).stream()
#define LOG_ERROR \
TinyMuduo::Logger(__FILE__, __LINE__, TinyMuduo::Logger::ERROR).stream()
#define LOG_FATAL \
TinyMuduo::Logger(__FILE__, __LINE__, TinyMuduo::Logger::FATAL).stream()
#define LOG_SYSERR TinyMuduo::Logger(__FILE__, __LINE__, false).stream()
#define LOG_SYSFATAL TinyMuduo::Logger(__FILE__, __LINE__, true).stream()
WARN、ERROR、FATAL 必须上报日志; 注意到Logger 的构造参数,TRACE 和 DEBUG 提供 function 参数便于验证,INFO 为默认等级,只需要传递 FILE 和 LINE 即够需求;
LOG_SYSERR 和 LOG_SYSFATAL 拥有 toAbort 参数,toAbort == true 则是FATAL 等级,反之为ERROR;
另外,在Logger 实际实现的Impl 类中,errno 参数通常为0,在发生LOG_SYSERR 和 LOG_SYSFATAL 时,才会传入errno;如遇errno ,则会以如下进行错误处理:
Logger 构造后,向Impl 传递参数构造
Logger::Impl::Impl(LogLevel level, int savedErrno, const char *file, int line)
: _time(Timestamp::now()), _stream(), _level(level), _line(line),
_basename(file) {
formatTime();
Fmt tid("%5d ", CurrentThread::tid());
assert(tid.length() == 6);
_stream << T(tid.data(), 6);
_stream << T(LogLevelName[level], 6);
if (savedErrno != 0) {
_stream << strerror_tl(savedErrno) << " (errno=" << savedErrno << ") ";
}
}
先打印Log 时间,接着打印线程id 和 Log 等级; 最后处理errno 情况:
const char *strerror_tl(int savedErrno) {
return strerror_r(savedErrno, t_errnobuf, sizeof t_errnobuf);
}
单条Log 信息格式为: 目前还不是线程安全的Log;
|