一:日志的作用
1、定义
日志(Log)是记录系统中发生的事件或操作的详细信息的文件或数据流。这些事件或操作可能包括程序执行、系统错误、用户活动、安全事件等日志(Log)是记录系统中发生的事件或操作的详细信息的文件或数据流。这些事件或操作可能包括程序执行、系统错误、用户活动、安全事件等。其中可以带来以下作用:
1:可以追踪程序的运行状态。
2:当出现问题之后可以提供现场运行的信息:包括所在文件,行号,所在线程等。
3:分析性能瓶颈和潜在系统故障。
2、异步日志和同步日志
我们都知道打印输出是IO操作,是很浪费时间的,那我们可不可以把这个打印输出作为一种耗时操作放入到线程池中去呢,作为异步操作执行呢?
答案是当然可以,我们将这个打印作为一个任务,放入到线程池中去执行,不会占用核心线程,提高性能。
但是异步打印有一些问题所在,比如异步打印中,我们如何保证时间的准确?在并发中我们如何做到顺序打印(并发乱序问题)?
对于时间的准确,这个容易解决,可以在打包任务的时候,就将时间进行携带,这样保证时间的准确性。而并发乱序问题,我们在每次打印的时候在这条信息前面加入排序号,我们可以通过后面使用输出排序进行按顺序打印,比如通过Linux下sort的命令进行按顺序查看。
二、spdlog
1、spdlog 介绍
spdlog 是一款高效的 C++ 日志库,它以其极高的性能和零成本的抽象而著称。spdlog 支持异步和同步日志记录,提供多种日志级别,并允许用户将日志输出到控制台、文件或自定义的接收器。
2、spdlog 为什么高效
spdlog 的设计哲学是尽量减少日志记录的开销,即使在高负载 的情况下也能保持高性能。它通过以下几种方式实现这一点:
零成本抽象:spdlog 通过模板和内联函数来实现零成本抽象, 确保只有在真正需要时才进行日志记录。
异步日志记录:spdlog 支持异步日志记录,这意味着它可以将日志消息发送到线程池进行处理,从而减少对主线程性能的影响。
高效地格式化:spdlog 使用 fmt 库进行高效的字符串格式化, 减少了格式化日志消息所需的时间。
3、spdlog 特征
spdlog 的性能特点使其在高性能应用中非常受欢迎:
极高的日志记录速度: spdlog 能够在每秒记录数百万条日志消 息,这对于需要处理大量日志数据的应用来说是非常重要的。
低内存占用: spdlog 的设计确保了即使在高负载下,它也能保持 低内存占用。
灵活的配置: 用户可以根据需要配置 spdlog,选择异步或同步日 志记录,以及选择不同的日志级别和输出目标。
4、spdlog 的输出控制
spdlog 提供了丰富的输出控制选项,允许用户根据需要定制日志输出:
多种日志级别: spdlog 支持多种日志级别,包括 trace、 debug、info、warn、error 和 critical,用户可以根据需要选择 合适的日志级别。
多种输出目标: 用户可以将日志输出到控制台、文件或通过网络 发送到远程服务器。
格式化输出: spdlog 支持格式化输出,允许用户以结构化的方式 输出日志消息。
5、spdlog 处理流程
Spdlog 的流程非常简单,但是每个组件都扮演着重要的角色。 Loggers 负责记录日志消息,Sinks 决定了日志消息的输出位 置,Formatters 负责将日志消息转换为特定格式,Async Logger 异步地将日志消息写入到目标 Sink 中,Registry 用于管理这些组件。
其中的异步日志Async Logger还包含一个线程池,用来异步处理。Registry是用来对这些loggers进行注册使用的,相当于管理。
三、具体使用
//默认输出到控制台
spdlog::info("hello world");
//下面是同步和异步的写入文件的方法
auto logger1 = spdllog::basic_logger_mt("basic","basic.txt");
logger1->info("hello world from basic_sink");
spdlog::get("basic")->info("hello world from basic_sink too");
//通过异步
auto logger2 = spdllog::basic_logger_mt<spdlog::async_factory>("basic","basic.txt");
logger1->info("hello world from basic_sink");
spdlog::get("basic")->info("hello world from basic_sink too");
//通过手动搭配
auto sink1 = std::make_shared<spdlog::sinks::ansicolor_stdout_sink_mt>();
auto sink2 = std::make_shared<spdlog::sinks::basic_file_sink_mt>("mark.txt",true);
auto logger3 = std::make_shared<spdlog::logger>("self");
logger3->sinks().push_back(sink1);
logger3->sinks().push_back(sink2);
spdlog::register_logger(logger3);
logger3->info("multi sinks");