spdlog中的异步日志方案

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: spdlog中的异步日志方案

日志方案

同步日志方案:立即输出日志记录的方案才能继续执行其他任务。

异步日志方案:先抛出一个日志记录的任务到某个地方,不马上执行打印也不影响往下执行其他任务。

二者关键区别是产生日志记录并调用相关的日志任务接口之后,是否需要马上打印才能往下执行其他任务。

使用多线程的日志方案不一定是异步日志,多线程也能通过锁实现日志的串行打印。

使用单线程的也不一定是同步日志方案,也有可能通过网络通信将日志异步地抛给其他节点完成打印日志的任务。

Spdlog介绍

Spdlog是性能极高的C++日志库。

Spdlog的特点

零成本抽象:spdlog主要编程语言是C++,C++的设计理念之一就是零成本抽象。零成本抽象主要通过内联函数和模板实现。抽象意思是先放置一个大致的框架在代码中,等到真正使用的时候稍加输入和调用就能迅速地构建出要使用的复杂实例或数据结构,不用从0开始编写。零成本指的是相比起用C语言从0开始构建的实例,性能成本几乎一样,没有额外的资源开销,同时大大减少了开发成本。

可异步进行日志记录:把日志信息发送到线程池异步地进行处理,减少对主线程的影响。用户可以自定义线程的个数与队列的大小。如果队列已满可选:抛弃部分日志或者阻塞。

高效格式化:类似python的.format方法。

Spdlog的输出控制

Spdlog日志级别,日志级别非spdlog独有,由低到高(重要等级从轻到重):trace、debug、info、warn、error、critical。

Spdlog多种输出目标:可以把日志输出到控制台、文件或者远程服务器。

格式化输出:类似python的.format方法。

Spdlog抽象模型

Registry管理logger/async logger, logger/async logger管理并输出到sink,sink把日志按某种格式输出到目的地,async logger需要依赖一个thread pool。

spd各部件主要功能

用伪代码介绍

Register:

register是一个全局的单例。如果没有显式地创建,一般在创建logger的时候会自动创建。

Spdlog::register_logger(std::shared_ptr<logger> new_logger) //把logger配置到register中去进行管理

Spdlog::get(logger_name) #获取logger

Logger:

如果没有显式地创建而是直接调用spd相关的输出函数,会自动创建默认参数的logger。

Flush策略 #指定sink把日志刷到目的地的方式

Logger->log(…) #输入日志到sink

Set_level #设置日志级别,只有大于等于设置的level才能输出出去

Async logger:

Logger->log(…) #在异步日志中仅仅是发布一个消息到线程池

Sink:

Set_level #自定义日志级别

Set_pattern #自定义日志格式

Set_formatter #补充Set_pattern的功能

Spdlog的使用

安装

方法一

方法二

初级应用

把日志按默认格式输出到控制台,背后会按默认参数创建logger和register并完成注册。

创建logger

Spdlog工厂方法创建

工厂方法的目的:屏蔽复杂的创建对象的流程。

工厂设计模式:有多个具体工厂类继承自一个抽象类,有多个具体产品类继承自另一个抽象类。每个具体工厂类里放置对应的具体产品生产类,只要创建了一个具体工厂实例就能调用具体的产品生产、使用等相关函数。

Spdlog里由很多头文件,不同的头文件里的有不同的“工厂”。

比如daily_file_sink.h指向的是把不同的日期的日志分开记录的“工厂”,hourly_file_sink是把每小时的日志分开记录的“工厂”,mongo_sink.h是把日志写到mongo数据库的“工厂”,ratating_file_sink.h是把日志文件按大小或者条数分割的“工厂”。

需要导入相关的头文件才能实现具体的“工厂”。用相应的头文件里的函数就能实现工厂的实力并“生产”对应的“产品”了。

Mt:multigthread。St:single thread。

这里的stdout_color_mt主要做了几件事情:

  1. 生成了一个对应的patten formatter(日志的输出格式)
  2. 基于默认的sink创建了一个logger,因为logger创建需要sink参数。
  3. 给logger起了一个名字“console”。
  4. 把logger注册到register。Register没有显式地创建,而是在logger创建的时候自动创建的单例。

在工厂模式的封装下,这些复杂的步骤和流程都被隐藏了。

手工方法创建

把工厂模式下被隐藏的步骤全部由自己显式书写,在这种模式下更方便设置多个日志的输出sink,参考sink模块。

创建sink

常规sink

如图创建两个sink,都将其绑定到logger上,于是logger可以输出日志到终端和文件上。

自定义pattern

sink2被修改了输出格式。

%^:表示日志级别的起始颜色标记。这个占位符可以用于在彩色控制台输出中设置日志级别的颜色。

%l:表示日志级别的占位符。它将被替换为实际的日志级别,例如 "info"、"error" 等。

%$:表示日志级别的结束颜色标记。这个占位符用于终止彩色控制台输出中的日志级别颜色。

%v:表示日志消息的占位符。它将被替换为实际的日志消息内容。

自定义formmater

formmater一般和pattern一起使用,是对pattern的补充。

class my_formatter_flag是固定用法,不必深究,只需要关注小红圈里的自定义的text的值。formatter->add_flag<my_formatter_flag>('*') 是往pattern里插入了一个*,也就是占位符*,未来这个占位符会被替换成hct。

创建异步日志

如果,先创建了一个队列8292,线程数量为8的线程池。选择异步工厂的数据类型创建logger并导入线程池。最后一个参数表示:如果等待队列已满,覆盖队列里存在时间最长是日志事件。类似的还有:

block: 当日志消息队列已满时,调用线程将被阻塞,直到有空间来写入新的消息。这种策略可以确保不会丢失任何日志消息,但可能会导致调用线程的阻塞。

discard_log_msg: 当日志消息队列已满时,新的日志消息将被直接丢弃,而不进行任何处理。这可能会导致丢失部分日志消息。

discard_policy: 与 discard_log_msg 类似,当日志消息队列已满时,新的日志消息将被丢弃。但是,相比于 discard_log_msg,discard_policy 会尝试创建一个新的日志消息对象,以便在资源释放后可以重新使用。这样可以减少内存分配的开销。

设置flush策略

sink输出日志一般都是先输出到缓存的,什么时候把日志记录从缓冲区刷到磁盘中,我们可以为此设置策略。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
4月前
|
存储 监控 Serverless
阿里泛日志设计与实践问题之Grafana Loki在日志查询方案中存在哪些设计限制,如何解决
阿里泛日志设计与实践问题之Grafana Loki在日志查询方案中存在哪些设计限制,如何解决
|
29天前
|
消息中间件 存储 监控
微服务日志监控的挑战及应对方案
【10月更文挑战第23天】微服务化带来模块独立与快速扩展,但也使得日志监控复杂。日志作用包括业务记录、异常追踪和性能定位。
|
3月前
|
Kubernetes API Docker
跟着iLogtail学习容器运行时与K8s下日志采集方案
iLogtail 作为开源可观测数据采集器,对 Kubernetes 环境下日志采集有着非常好的支持,本文跟随 iLogtail 的脚步,了解容器运行时与 K8s 下日志数据采集原理。
|
4月前
|
XML 监控 Java
异步日志:性能优化的金钥匙
本文主要介绍了Log4j2框架的核心原理、实践应用以及一些实用的小Tips,力图揭示Log4j2这一强大日志记录工具在现代分布式服务架构运维中的关键作用。
|
4月前
|
Java 编译器 数据库
异步日志方案——spdlog
异步日志方案——spdlog
|
4月前
|
SQL JavaScript 前端开发
【Azure 应用服务】Azure JS Function 异步方法中执行SQL查询后,Callback函数中日志无法输出问题
【Azure 应用服务】Azure JS Function 异步方法中执行SQL查询后,Callback函数中日志无法输出问题
|
4月前
|
存储 Prometheus Kubernetes
在K8S中,如何收集K8S日志?有哪些方案?
在K8S中,如何收集K8S日志?有哪些方案?
|
4月前
|
存储 Kubernetes Java
阿里泛日志设计与实践问题之在写多查少的降本场景下,通过SLS Scan方案降低成本,如何实现
阿里泛日志设计与实践问题之在写多查少的降本场景下,通过SLS Scan方案降低成本,如何实现
|
23天前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
170 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
2月前
|
XML JSON Java
Logback 与 log4j2 性能对比:谁才是日志框架的性能王者?
【10月更文挑战第5天】在Java开发中,日志框架是不可或缺的工具,它们帮助我们记录系统运行时的信息、警告和错误,对于开发人员来说至关重要。在众多日志框架中,Logback和log4j2以其卓越的性能和丰富的功能脱颖而出,成为开发者们的首选。本文将深入探讨Logback与log4j2在性能方面的对比,通过详细的分析和实例,帮助大家理解两者之间的性能差异,以便在实际项目中做出更明智的选择。
255 3