(三)底层封装Timestamp 和 Log

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;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值