目录
In symbols one observes an advantage in discovery which is greatest when they express the exact nature of a thing briefly and, as it were, picture it; then indeed the labor of thought is wonderfully diminished.
—GOTTFRIED WILHELM LEIBNIZ
大致意思是:使用符号的最大优势,就是符号可以非常清晰、简洁的描绘一个事务的本质,从而可以极大的减少思想劳动的支出。
//我把这段文字贴在这里,因为它阐释了配置文件的本质
Logback 的配置依赖于 Joran 配置框架,这个框架后边如果有时间我会扒一下源码后再进行分享,此处,重点探讨 Logback 配置文件的相关内容。
首先让我们来看一下 logback 尝试加载配置时所遵循的初始化步骤:
(1)查找自定义的 Configurator
Logback 会优先加载自定义的配置器(Configurator),所谓自定义配置器,就是实现了 ch.qos.logback.classic.spi.Configurator 接口的类。
Logback 中提供了两个 Configurator 接口的实现类,一个是 DefaultJoranConfigurator(加载logback.xml文件的配置器),另一个是 BasicConfigurator(默认配置器)。
(2)实例化 SerializedModelConfigurator 配置器
如果在 Logback 没有找到用户提供的自定义配置器,logback 将实例化一个 SerializedModelConfigurator。这是一个序列化模型文件的加载器,加载的文件名称为:"logback-test.scmo" 或 "logback.scmo"。
序列化模型文件的配置执行速度更快,并且不需要任何 XML 库。与 GraalVM 结合使用,可以产生更小的可执行文件,启动速度更快。这个加载器我在 Logback 的核心包中没有找到对应的类,所以暂时不深入分析,了解即可。
如果找不到序列化配置模型文件,SerializedModelConfigurator 将返回一个执行状态,要求调用下一个可用的配置器,即创建并调用 DefaultJoranConfigurator 的实例。
(3)执行 DefaultJoranConfigurator 配置器(重点步骤)
首先,DefaultJoranConfigurator 会尝试查找 “logback.configurationFile” 系统属性上指定的文件。如果可以找到该文件,则会读取并解释该文件,然后进行配置。
如果没有找到上述文件,DefaultJoranConfigurator 将尝试在类路径上查找配置文件 “logback-test.xml” 。如果可以找到该文件,则会读取并解释该文件,然后进行配置。
如果没有找到上述文件,配置器将继续尝试在类路径中查找配置文件 “logback.xml” 。如果可以找到该文件,则会读取并解释该文件,然后进行配置。
如果找不到配置文件,DefaultJoranConfigurator 将返回一个执行状态,要求调用下一个可用的配置器,即创建并调用 BasicConfigurator 的实例。
//从这里可以看出,“logback-test.xml” 文件优先于 “logback.xml” 文件生效。
(4)执行 BasicConfigurator 配置器(使用默认配置)
如果上述配置文件查找均不成功,logback-classic 将使用 BasicConfigurator 进行自身配置,默认配置会使日志定向输出到控制台。执行 BasicConfigurator 配置器,是为了在没有配置文件的情况下,logback 能够正常使用日志记录功能。//默认配置的作用
//从 logback 配置文件加载过程来看,就是使用了一串配置器链(责任链模式)
之前在《如何在项目中快速引入Logback日志?》这篇文章中提到过如何打印 logback 的内部状态信息, 这些信息在对 logback 相关的问题进行诊断时非常有用。文章中,我们使用程序代码的方式对状态信息进行打印,除此之外,还可以使用配置文件的方式。
使用配置文件,本质上就是在配置文件中配置一个状态监听器(StatusListener),如果我们只是想把内部信息打印在控制台上,那么就可以配置一个 OnConsoleStatusListener,配置信息如下:
- <configuration>
-
- <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
-
-
-
- configuration>
为什么建议将状态侦听器置于配置文件的顶部呢?
这是因为,已注册的状态侦听器将仅接收其注册后的状态事件。它不会接收之前的消息。因此,最好将状态侦听器注册指令放置在配置文件顶部的其他指令之前。
此外,配置 OnConsoleStatusListener 还有一种更简洁的方式,直接在
- <configuration debug="true">
-
-
-
- configuration>
logback 的配置文件非常灵活,且不需要使用 DTD 文件或 XML 模式指定的语法。其配置文件的基本结构可以描述为:
logback.xml 配置文件的一般格式内容如下:
- <configuration debug="true">
-
-
- <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
- <encoder>
- <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%npattern>
- encoder>
- appender>
-
-
- <logger name="self4.Example" level="INFO" additivity="false">
-
-
- <appender-ref ref="STDOUT" />
- logger>
-
-
- <root level="debug">
- <appender-ref ref="STDOUT"/>
- root>
-
- configuration>
顾名思义,
其配置示例,可以参考上边 logback.xml 配置文件的一般格式的内容。
使用
有关 logger 继承的详细内容,我在这篇文章《Logback 日志框架的架构》中有介绍,可做参考。
因为根记录器是最顶层的记录器,所以它没有可追加属性(additivity),同时,根记录器已经被命名为 “ROOT”,因此它也不允许使用名称属性(name)。此外,
下图说明了
简要的示例配置内容如下所示:
- <configuration>
-
- <appender name="FILE" class="ch.qos.logback.core.FileAppender">
- <file>myApp.log</file>
-
- <encoder>
- <pattern>%date %level [%thread] %logger{10} [%file:%line] -%kvp- %msg%n</pattern>
- </encoder>
- </appender>
-
- <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
- <encoder>
- <pattern>%kvp %msg%n</pattern>
- </encoder>
- </appender>
-
- <root level="debug">
- <appender-ref ref="FILE" />
- <appender-ref ref="STDOUT" />
- </root>
- </configuration>
与许多脚本语言一样,logback 配置文件也支持对变量进行定义和引用。变量可以定义在配置文件的内部,也可以定义在配置文件的外部(不推荐),甚至还可以动态的进行计算和定义。
引用一个变量,可以使用 "${name}" 这种格式,"${name}" 会被解释为对 name 的属性值的引用。
由于历史原因,在配置文件中定义一个变量,logback 1.0.7 版本之前使用
在配置文件中定义变量的内容如下:
- <configuration>
-
- <!--定义一个变量,变量名称为USER_HOME -->
- <variable name="USER_HOME" value="/home/sebastien" />
-
- <appender name="FILE" class="ch.qos.logback.core.FileAppender">
- <!--引用定义的变量-->
- <file>${USER_HOME}/myApp.log</file>
- <encoder>
- <pattern>%kvp %msg%n</pattern>
- </encoder>
- </appender>
-
- <root level="debug">
- <appender-ref ref="FILE" />
- </root>
- </configuration>
如果想将变量定义在外部文件中,可以使用如下配置:
- <configuration>
-
- <!--引入外部文件-->
- <variable file="src/main/java/chapters/configuration/variables1.properties" />
-
- <appender name="FILE" class="ch.qos.logback.core.FileAppender">
- <file>${USER_HOME}/myApp.log</file> <!--引入外部文件中的USER_HOME变量值-->
- <encoder>
- <pattern>%kvp %msg%n</pattern>
- </encoder>
- </appender>
-
- <root level="debug">
- <appender-ref ref="FILE" />
- </root>
- </configuration>
外部文件 variables1.properties 中的内容如下://键值对
USER_HOME=/home/sebastien
在某些情况下,如果变量未被声明或者它的值为 null 时,则可能希望变量具有默认值。在 logback 配置中,可以使用 " :- " 运算符来指定默认值,比如,名为 name 的变量没有被定义,那么 "{name:-golden}" 将被解释为 "golden"。
logback 的配置完全支持变量的嵌套。变量的名称、默认值和值的定义都可以引用其他变量。
变量值的定义可以包含对其他变量的引用,比如:
- #定义的变量
- USER_HOME=/home/sebastien
- fileName=myApp.log
-
- #该变量值的定义可以引用其他变量
- destination=${USER_HOME}/${fileName}
变量名称的定义也可以包含对其他变量的引用,比如,如果为名为 "userid" 的变量的值为:"swadian",则 "${${userid}.password}" 引用是变量名为 "swadian.password" 的值。
变量默认值的定义同样也可以包含对其他变量的引用,例如,如果变量 "id" 未被分配值,并且变量 "userid" 的值为 "swadian",则表达式 "${id:-${userid}}" 将返回 "swadian"。
当然,logback 配置中还有许多值得探讨的内容,但因为时间和篇幅有限,我们只探讨了一些常用的配置项,其他详细内容可以点击此处查阅官方文档。
至此,全文结束。