0%

logback

logback

configuration

logback_configuration_01

appender

类名 描述
ConsoleAppender 将日志通过 System.out 或者 System.err 来进行输出,即输出到控制台。
FileAppender 将日志输出到文件中。
RollingFileAppender 继承自 FileAppender,也是将日志输出到文件,但文件具有轮转功能。
DBAppender 将日志输出到数据库
SocketAppender 将日志以明文方式输出到远程机器
SSLSocketAppender 将日志以加密方式输出到远程机器
SMTPAppender 将日志输出到邮件

Filter

image-20211026212759209

EvaluatorFilter

1
2
3
4
5
6
<!-- groovy -->
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>3.0.0-rc-3</version>
</dependency>

GEventEvaluator

ch.qos.logback.classic.boolex.GEventEvaluator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<configuration scan="true" scanPeriod="10 seconds" debug="true">
<!-- 定义变量 -->
<property scope="system" name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<target>system.err</target>
<encoder charset="utf-8">
<pattern>${LOG_PATTERN}</pattern>
</encoder>
<!-- 设置过滤器 -->
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator class="ch.qos.logback.classic.boolex.GEventEvaluator">
<expression>
e.level.toInt() >= ERROR.toInt() &amp;&amp;
!(e.mdc?.get("req.userAgent") =~ /Googlebot|msnbot|Yahoo/ )
</expression>
</evaluator>
<OnMismatch>DENY</OnMismatch>
<OnMatch>NEUTRAL</OnMatch>
</filter>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>

JaninoEventEvalutor

JaninoEventEvaluator

Logback-classic 附带了另一个名为JaninoEventEvaluator的具体EventEvaluator实现,它采用任意 Java 语言块返回布尔值作为评估标准。我们将此类 Java 语言布尔表达式称为“ * evaluation expressions *”。评估表达式为事件过滤提供了极大的灵 Active。 JaninoEventEvaluator要求Janino library。请参阅安装文档的corresponding section。与JaninoEventEvaluator相比,借助 Groovy 语言,GEventEvaluator更加方便使用,但是JaninoEventEvaluator通常对于等效表达式运行(快得多)。

评估表达式是在配置文件的解释过程中即时编译的。作为用户,您不必担心实际的管道问题。但是,您有责任确保 Java 语言表达式返回一个布尔值,即它的计算结果为 true 或 false。

评估表达式是在当前日志记录事件上评估的。 Logback-classic 自动将日志记录事件的各个字段导出为可从评估表达式访问的变量。下面列出了这些导出变量的区分大小写的名称。

Name Type Description
event LoggingEvent 与日志记录请求关联的原始日志记录事件。事件中还提供以下所有变量。例如,event.getMessage()返回与下面描述的* message *变量相同的 String 值。
message String 日志记录请求的原始消息。对于某些 Logger* l *,当您编写 l.info(“ Hello{}”,name);其中为名称分配了值“ Alice”,则消息为“ Hello{}”。
formattedMessage String 日志记录请求中的格式化消息。对于某些 Logger* l *,当您编写 l.info(“ Hello{}”,name);其中为名称分配了值“ Alice”,则“ Hello Alice”是格式化的消息。
logger String Logger 的名称。
loggerContext LoggerContextVO 记录事件所属的 Logger 上下文的受限(值对象)视图。
level int 对应于级别的 int 值。为了帮助轻松创建涉及级别的表达式,还提供了默认值* DEBUG INFO WARN ERROR 。因此,使用 level> INFO *是正确的表达式。
timeStamp long 与记录事件的创建相对应的时间戳。
marker Marker 与日志记录请求关联的Marker对象。请注意,标记可以为 null,您有责任检查此条件以避免NullPointerException
mdc Map 在创建日志记录事件时包含所有 MDC 值的 Map。可以使用以下表达式访问值:* mdc.get(“ myKey”)*。从经典 logback 版本 0.9.30 开始,“ mdc”变量将永远不会为 null。java.util.Map类型是非参数化的,因为 Janino 不支持泛型。因此,由mdc.get()返回的类型是Object而不是String。要对返回的值调用String方法,必须将其强制转换为String。例如((String) mdc.get("k")).contains("val")
throwable java.lang.Throwable 如果没有异常与事件关联,则“ throwable”变量的值将为 null。不幸的是,“ throwable”无法在序列化中幸免。因此,在远程系统上,其值将始终为 null。对于位置无关的表达式,请使用下面描述的throwableProxy变量。
throwableProxy IThrowableProxy 与日志记录事件关联的异常的代理。如果没有异常与事件关联,则“ throwableProxy”变量的值将为 null。与“ throwable”相反,当异常与事件相关联时,即使在远程系统上(即在序列化之后),“ throwableProxy”的值也不会为空。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<configuration scan="true" scanPeriod="10 seconds" debug="true">
<!-- 定义变量 -->
<property scope="system" name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<target>system.err</target>
<encoder charset="utf-8">
<pattern>${LOG_PATTERN}</pattern>
</encoder>
<!-- 设置过滤器 -->
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<expression>return message.contains("ERROR");</expression>
</evaluator>
<OnMismatch>DENY</OnMismatch>
<OnMatch>NEUTRAL</OnMatch>
</filter>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>

源码解析

初始化

slf4j 通过 StaticLoggerBinder 类与具体日志实现进行关联,从而实现门面模式

加载StaticLoggerBinder

image-20211026205834511

LoggerFactory.performInitialization(),会执行初始化,所谓的初始化就是查找 StaticLoggerBinder 这个类是不是存在,如果存在会将该类绑定到当前应用,同时,根据不同情况修改INITIALIZATION_STATE。代码比较多,我概括下执行的步骤:

  1. 如果 StaticLoggerBinder 存在且唯一,修改初始化状态为 SUCCESSFUL_INITIALIZATION;
  2. 如果 StaticLoggerBinder 存在但为多个,由 JVM 决定绑定哪个 StaticLoggerBinder,修改初始化状态为 SUCCESSFUL_INITIALIZATION,同时,会在控制台打印存在哪几个 StaticLoggerBinder,并提醒用户最终选择了哪一个 ;
  3. 如果 StaticLoggerBinder 不存在,打印提醒,并修改初始化状态为 NOP_FALLBACK_INITIALIZATION;
  4. 如果 StaticLoggerBinder 存在但 getSingleton() 方法不存在,打印提醒,并修改初始化状态为 FAILED_INITIALIZATION;

加载配置

支持采用 xml、grovy 和 SPI 的方式配置文件

Joran(一个成熟的,灵活的并且强大的配置框架 )

logback_joran

获取logger

LoggerContext.getLogger(String)

JaninoEventEvaluator

https://github.com/qos-ch/logback/blob/master/logback-core/src/main/java/ch/qos/logback/core/boolex/JaninoEventEvaluatorBase.java