在软件开发中,日志记录是一个不可或缺的部分。它帮助开发者追踪程序的执行流程,定位问题,以及监控程序的运行状态。今天,要介绍的是一个名为Loguru的轻量级日志库。Loguru以其出色的文档和人性化的输出格式而闻名。使用Loguru非常简单,只需要添加一个头文件和一个源文件即可编译使用。然而,这在某种程度上也是一个缺点。虽然它易于安装和使用,但在部署后,系统操作员可能希望定义自己的日志记录方式。在这种情况下,使用通用的日志接口(如slf4cxx,类似于Java中的slf4j)可能更为合适。
Loguru支持多种功能,包括日志回调、错误处理、断言和中止操作,以及在中止时的堆栈跟踪。它甚至支持{fmt}库,这使得习惯于Java/Spring日志输出的用户能够快速上手。
下面是一个使用Loguru的C++示例代码:
#include <thread>
#include "loguru.hpp"
#include "loguru.cpp"
void sleep(int ms) {
VLOG_F(0, "Sleeping for %d ms", ms);
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
}
void complex() {
LOG_SCOPE_F(INFO, "Preparing complex calculation");
VLOG_F(0, "Heating up CPU");
sleep(500);
std::thread([](){
loguru::set_thread_name("complex lambda");
const bool value = true;
LOG_IF_F(INFO, value, "This log is printed inside another thread");
}).join();
}
void crashingFunction(int index) {
ERROR_CONTEXT("Computing with index", index);
std::vector list;
CHECK_F(index > 1, "Oh no, wrong index, index is %d!!", index);
}
int main(int argc, char* argv[]) {
loguru::init(argc, argv);
loguru::add_file("important.log", loguru::Truncate, loguru::Verbosity_INFO);
LOG_F(INFO, "We are starting our complex threaded computation!");
complex();
LOG_F(INFO, "Complex computation done!");
crashingFunction(-1);
return 0;
}
Loguru的日志输出格式如下:
date time ( uptime ) [ thread name/id ] file:line v|
2019-03-11 21:46:14.591 ( 0.000s) [main thread ] loguru.cpp:587 INFO| arguments: /mnt/c/Develop/LoggingWithLoguru/cmake-build-debug-wsl/LoggingWithLoguru
2019-03-11 21:46:14.591 ( 0.000s) [main thread ] loguru.cpp:590 INFO| Current dir: /mnt/c/Develop/LoggingWithLoguru/cmake-build-debug-wsl
2019-03-11 21:46:14.591 ( 0.000s) [main thread ] loguru.cpp:592 INFO| stderr verbosity: 0
2019-03-11 21:46:14.592 ( 0.001s) [main thread ] loguru.cpp:593 INFO| -----------------------------------
2019-03-11 21:46:14.592 ( 0.001s) [main thread ] loguru.cpp:751 INFO| Logging to 'important.log', mode: 'w', verbosity: 0
2019-03-11 21:46:14.592 ( 0.001s) [main thread ] main.cpp:47 INFO| We are starting our complex threaded computation!
2019-03-11 21:46:14.592 ( 0.001s) [main thread ] main.cpp:15 INFO| { Preparing complex calculation
2019-03-11 21:46:14.592 ( 0.001s) [main thread ] main.cpp:18 INFO| . Heating up CPU
2019-03-11 21:46:14.592 ( 0.001s) [main thread ] main.cpp:8 INFO| . Sleeping for 500 ms
2019-03-11 21:46:15.094 ( 0.502s) [complex lambda ] main.cpp:25 INFO| . This log is printed inside another thread
2019-03-11 21:46:15.094 ( 0.503s) [main thread ] main.cpp:15 INFO| } 0.502 s: Preparing complex calculation
2019-03-11 21:46:15.094 ( 0.503s) [main thread ] main.cpp:49 INFO| Complex computation done!
Stack trace:
3 0x7ff08b806a7a /mnt/c/Develop/LoggingWithLoguru/cmake-build-debug-wsl/LoggingWithLoguru(+0x6a7a) [0x7ff08b806a7a]
2 0x7ff08a641b97 __libc_start_main + 231
1 0x7ff08b80cfb5 /mnt/c/Develop/LoggingWithLoguru/cmake-build-debug-wsl/LoggingWithLoguru(+0xcfb5) [0x7ff08b80cfb5]
0 0x7ff08b80ceb5 /mnt/c/Develop/LoggingWithLoguru/cmake-build-debug-wsl/LoggingWithLoguru(+0xceb5) [0x7ff08b80ceb5]
------------------------------------------------
[ErrorContext] main.cpp:32 Computing with index: -1
------------------------------------------------
2019-03-11 21:46:15.094 ( 0.503s) [main thread ] main.cpp:36 FATL| CHECK FAILED: index > 1 Oh no, wrong index, index is -1!!
如所见,使用Loguru非常简单。不仅记录了多个INFO级别的消息,还在名为“complex lambda”的命名线程中记录了一条消息。如果没有使用loguru::set_thread_name(“complex lambda”)定义线程名称,Loguru会以十六进制ID的形式显示线程名称。主线程通过调用loguru::init(…)获得其名称。因为小工具崩溃了,Loguru打印了堆栈跟踪,虽然认为它没有达到预期的有用程度,但ERROR_CONTEXT提供了更好的输出。