当前位置: 首页 > news >正文

第二章 Logback的架构(三)

Logger, Appenders 和 Layouts

工作原理概述

在介绍了基本的Logback组件之后,我们现在可以描述当用户调用Logger的打印方法时,Logback框架日志请求的执行步骤。
现在让我们分析一下当用户调用名为com.wombat的Logger的info()方法时,Logback日志请求的执行步骤。如果
过滤器链返回FilterReply.DENY,则日志请求被拒绝;如果返回 FilterReply.NEUTRAL,则继续下一步骤(即步骤2);
如果返回FilterReply.ACCEPT,则跳过下一步,直接进入步骤3。

  1. 获取过滤器链的决策结果

如果存在,TurboFilter过滤器链将会被调用。Turbo过滤器可以设置一个全局阈值,或者基于日志请求关联的信息
(如Marker, Level, Logger、消息或Throwable)过滤掉某些事件。

  1. 应用基本选择规则

在这个步骤中,Logback会比较Logger的生效级别和日志请求的级别。如果请求日志的级别验证不通过,则日志请求被拒绝;
否则,它将继续执行下一步。

  1. 创建LoggingEvent对象

如果日志请求通过前面所述的过滤器链,Logback会创建一个ch.qos.logback.classic.LoggingEvent对象。
这个对象包含日志请求的所有信息,如logger对象、日志级别、日志消息、可能随请求一起传递的异常对象、当前时间、
当前线程、发出日志请求的类的各种数据以及MDC。请注意,有些属性字段是在需要时才会初始化(延迟加载)。
MDC 用于为日志请求添加额外的上下文信息。MDC的相关内容将在后续章节中讨论。

  1. 调用Appender

创建完LoggingEvent对象后,Logback会调用所有适用的Appender的doAppend()方法,这些Appender是从Logger Context中继承的。

所有随Logback发行版提供的Appender都扩展自AppenderBase抽象类,该类在一个同步块中实现了doAppend方法以确保线程安全。
AppenderBasedoAppend()方法还会调用添加到该Appender的自定义过滤器(如果存在这样的过滤器)。
动态添加自定义过滤器到Appender将在单独的章节中介绍。

  1. 格式化输出

一般来讲,被调用的Appender会负责日志事件的格式化输出。然而,一些(但不是全部)Appender会将格式化任务委托给Layout。
Layout会格式化LoggingEvent实例并返回结果字符串。请注意,一些Appender(如SocketAppender)不会将日志事件转换为字符串,
而是对其进行序列化。因此,它们不需要也不依赖Layout。

  1. 发送LoggingEvent

在日志事件完全格式化之后,每个Appender都会将其发送到目标地址。

下面是一个UML时序图,显示了所有的工作流程。

Logback执行步骤UML时序图

性能

日志记录的计算成本是一个值得关注的问题,因为即使是一个中等规模的应用程序也可能产生成千上万的日志请求。我们投入了大量开发精力来测量和微调
Logback的性能。然而,无论这些努力如何,用户仍然应该意识到以下性能问题。

  1. 当日志记录全部被关闭时的性能表现

可以通过将Root Logger的日志级别设置成Level.OFF关闭所有的日志记录。当日志记录被完全关闭时,日志请求的计算成本由方法调用和整数比较组成。
在一个3.2Ghz Pentium D机器上,这个成本通常在20纳秒左右。

然而,任何方法调用都涉及参数构造的“隐藏”成本。例如,对于某个Logger x的写法

x.debug("Entry number: " + i + "is " + entry[i]);

无论日志消息是否被记录,构造参数(即把整数字符串、整数i、和entry[i]连接成字符串)带来的成本都是存在的。

参数构造的成本取决于所涉及参数的多少,这个构造成本可能会很高。为了避免这种参数构造的成本,你可以使用 SLF4J 的参数化日志记录功能:

x.debug("Entry number: {} is {}", i, entry[i]);

这种变体不会产生参数构造的成本,与前一种debug()方法调用相比,它在性能上会有显著提升。
只有当日志请求需要发送到Appender时,才会格式化消息。此外,负责格式化消息的组件也经过了高度优化。

尽管如此,将日志语句放在紧密循环中(即频繁调用的代码)仍是一个双输的做法,极易导致性能下降。
即使日志功能被关闭,紧密循环中的日志也会拖慢你的应用程序;如果日志功能开启,则会产生大量无用的输出。

  1. 开启日志功能时,决策是否记录日志的性能表现

在Logback中,判定日志额生效级别是不需要遍历Logger的层级结构的。当Logger创建创建时他就已经设定好了生效级别(考虑了级别继承之后的实际级别)。
如果某个父Logger的级别发生了状态变化,那么所有子Logger都会收到通知以更新状态。因此,在根据有效级别接受或拒绝一个日志请求之前,Logger可以
几乎实时地做出决策,而无需咨询其祖先。

  1. 实际的日志记录(格式化并写入输出设备)

这是指格式化日志输出并将它发送到目标地址的成本。再次强调,我们做出了大量努力来使Layout(格式化器)尽可能快速执行。Appender同样也是如此优化的。
当向本地机器上的文件进行日志记录时,实际的日志记录成本通常在9到12微秒之间;而在远程服务器上向数据库写入日志时,这一成本会上升到几毫秒。

尽管Logback功能丰富,但其设计中最优先考虑的目标之一就是执行速度,仅次于可靠性。为了提高性能,一些Logback组件已经被重写了多次。

相关文章:

  • Web 自动化之 HTML JavaScript 详解
  • HTML10:iframe内联框架
  • HTML9:页面结构分析
  • 利用session在html和MySQL实现登录
  • 桥隧坡灾害监测报警:用科技筑起生命安全的“智能防线”
  • 计算机网络:深入分析三层交换机硬件转发表生成过程
  • php java go python面向对象的设计原则和常用设计模式
  • Ubuntu 22.04 出现 ‘Temporary failure resolving‘ 解决方案
  • 什么是死信队列?死信队列是如何导致的?
  • 〖 Linux 〗解决 VS Code 远程连接服务器的常见问题
  • 使用Scrapeless Scraping Browser的自动化和网页抓取最佳实践
  • SM2Utils NoSuchMethodError: org.bouncycastle.math.ec.ECFieldElement$Fp.<init
  • React 笔记[1] hello world
  • 画流程超神组合deepseek + UML
  • leaflet-velocity风场粒子效果及数据处理
  • 阿里云 golang 一面
  • 在Git历史中移除现有的Commit
  • 云原生架构实战:打造高可用、可扩展的现代应用体系
  • 电力电子simulink练习08:闭环控制的引入与PI调节器
  • Oracle EBS AP发票被预付款核算创建会计科目时间超长
  • 七方面118项任务,2025年知识产权强国建设推进计划印发
  • 复旦大学文科杰出教授裘锡圭逝世,享年90岁
  • 水利部:山西、陕西等地旱情将持续
  • 国家发改委:目前有的核电项目民间资本参股比例已经达到20%
  • 王日春已任教育部社会科学司司长,此前系人教社总编辑
  • 古龙逝世四十周年|中国武侠文学学会与多所高校联合发起学术纪念活动