玩转小项目之日志库
今天分享arrow日志库的设计与实现,所有源码均在星球提供(加入方式见末尾),本次项目重写arrow日志库,将arrow日志库提取出来,整个项目基于bazel构建。
目前支持的特性有:
- 默认日志格式
- spdlog日志格式
- 支持堆栈输出
- 支持日志在终端打印
- 支持日志输出至文件
- 支持日志高亮显示
- 支持日志插件扩展
- 支持多种日志级别
先来看第一个特性:默认日志格式输出与终端打印:
代码语言:javascript复制➜ light-log bazel-bin/tests/log_test
tests/log_test.cc:13: This is the INFO message
tests/log_test.cc:15: This is the WARNING message
tests/log_test.cc:17: This is the ERROR message
This is the DEBUG message
tests/log_test.cc:13: This is the INFO message
tests/log_test.cc:15: This is the WARNING message
tests/log_test.cc:17: This is the ERROR message
===============================================================================
test cases: 1 | 1 passed
assertions: - none -
第二个特性:spdlog终端与文件输出:
编译时,通过宏参数控制,只需要传递ARROW_USE_SPDLOG即可。
代码语言:javascript复制 bazel test //tests:log_test --define ARROW_WITH_BACKTRACE=true --define ARROW_USE_SPDLOG=true
- 终端打印
[2023-08-16 07:15:14,660 I 21004 41898222] log_test.cc:13: This is the INFO message
[2023-08-16 07:15:14,660 W 21004 41898222] log_test.cc:15: This is the WARNING message
[2023-08-16 07:15:14,661 E 21004 41898222] log_test.cc:17: This is the ERROR message
===============================================================================
test cases: 1 | 1 passed
assertions: - none -
- 文件输出
堆栈特性输出:
代码语言:javascript复制➜ light-log bazel-bin/main
0 main 0x0000000105e8d8fb _ZN5arrow4util14PrintBackTraceERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEE 75
1 main 0x0000000105ef1937 _ZN5arrow4util13SpdLogMessage5FlushEv 231
2 main 0x0000000105ef180c _ZN5arrow4util13SpdLogMessageD2Ev 28
3 main 0x0000000105e8f395 _ZN5arrow4util13SpdLogMessageD1Ev 21
4 main 0x0000000105e8f34e _ZN5arrow4util8ArrowLogD2Ev 78
5 main 0x0000000105e8f3b5 _ZN5arrow4util8ArrowLogD1Ev 21
6 main 0x0000000105e8c131 main 113
7 libdyld.dylib 0x00007fff2041cf3d start 1
[2023-08-16 07:20:05,798 C 21937 41909787] test:10: hello logginghello2 logginghello3 logging
*** StackTrace Information ***
[1] 21937 abort bazel-bin/main
1.实现
1.1 可插拔
通过使用宏:
代码语言:javascript复制ARROW_USE_SPDLOG
来达到开关spdlog库的功能。
通过使用宏:
代码语言:javascript复制ARROW_WITH_BACKTRACE
来达到堆栈是否输出的功能。
实现层面,抽象出公共基类:
代码语言:javascript复制class ARROW_EXPORT ArrowLogBase {
public:
virtual ~ArrowLogBase() {}
virtual bool IsEnabled() const { return false; }
template <typename T>
ArrowLogBase& operator<<(const T& t) {
if (IsEnabled()) {
Stream() << t;
}
return *this;
}
protected:
virtual std::ostream& Stream() = 0;
};
所有日志扩展通过继承的方式实现这些接口。
对于所有的扩展,采用typedef来实现可扩展性。
代码语言:javascript复制#ifdef ARROW_USE_SPDLOG
typedef SpdLogMessage LoggingProvider;
#else
typedef CerrLog LoggingProvider;
#endif
1.2 宏
沿用arrow原始的宏定义,只需要简单的ARROW_LOG便可以输出各种日志级别的日志。
代码语言:javascript复制ARROW_LOG(ARROW_DEBUG) << "This is the"
<< " DEBUG"
<< " message";
1.3 日志级别
通过枚举实现,覆盖所有日志级别。
代码语言:javascript复制enum class ArrowLogLevel : int {
ARROW_TRACE = -2,
ARROW_DEBUG = -1,
ARROW_INFO = 0,
ARROW_WARNING = 1,
ARROW_ERROR = 2,
ARROW_FATAL = 3
};