解读Logback的配置文件

857 阅读5分钟

Logback会按照顺序在5个地方查找相关配置:

  • classpath下是否存在logback-test.xml文件,没有继续找;
  • classpath下是否存在logback.groovy文件,没有继续找;
  • classpath下是否存在logback.xml文件,没有继续找;
  • 通过java.util.ServiceLoader<S> 加载com.qos.logback.classic.spi.Configurator的实现,没有继续找;
  • 采用logback最基本的配置,在 ch.qos.logback.classic.BasicConfigurator,在logback-classic包内可以找到;

正常在项目中都会添加两个配置文件:logback-test.xml[src/test/resources]和logback.xml[src/resources],用于测试和生产环境。

小尝试

新建logback.xml文件,放在/src/resource目录下,内容:

<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

在启动项目看下效果,该配置文件已经生效,而且该配置文件和logback默认的配置是一样的哦。

如何实现配置文件自动刷新?

当我们修改了日志配置后,是否可以不重新运行就生效?答案是可以的,而且在生产环境也有可能会调整日志参数,如何实现热加载?

<configuration scan="true" scanPeriod="30 seconds" > 
  ...
</configuration> 

scan:添加scan="true"即可实现logback配置文件热加载。

scanPeriod:配置热加载的频率,需要带单位,默认ms。

  • 添加scan后,会启动一个定时器:ReconfigureOnChangeTask,用于检查配置文件;
  • 如何不添加scanPeriod,默认1m加载一次,配置了但是没有写单位,默认是ms,但生产环境完全没必要这么高的频率
  • 吻心提示:为什么你的例子不生效?因为要修改/target目录下的logback.xml才可以,这才是你正在运行的配置,不要去修改src/resource的配置,那是源文件!!!!

如何在日志中记录堆栈跟踪行所在的类和版本信息?

这里对应官网Enabling packaging data in stack traces章节,很多人不明白什么是packing data,先给出一个例子: 首先我们编写一个异常代码:

int i=10;
int j=9/(i-10);
return String.valueOf(j);

不出意外,得到了以下异常:

java.lang.ArithmeticException: / by zero
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.41.jar:9.0.41]

大家看到最后有一个标记:[tomcat-embed-core-9.0.41.jar:9.0.41],这就是packing data,如何才能在日志中打印该内容呢? 在配置中添加packagingData="true"就可以了。

<configuration packagingData="true">
</configuration>

packing data对于识别软件版本问题非常有用。但是,它的计算成本相当高,尤其是在经常抛出异常的应用程序中,慎用!!!

正文开始的地方:Logback的配置文件构成

写在前面

修改contextName

在常用的配置节之前,还有一个配置节<contextName>,用于修改日志记录器的上下文名称(默认default),如果有多个应用程序都在记录日志,使用默认的名称不容易区分,建议把该配置节修改为当前应用程序的名称,如<contextName>idodo-cloud-idp</contextName>

使用变量property

<!--定义变量-->
<property name="USER_HOME" value="/home/idodo" />
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<!--使用变量-->
    <file>${USER_HOME}/cloud-idp.log</file>
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
</appender>

有三种方式定义变量(优先级由高到低):

  • 使用系统变量,如Java -DUser_HOME="/home/idodo" idodo-cloud-idp
  • 在xml中定义变量,如
  • 在单独文件中定义变量,如:在idp.properties文件中定义内容USER_HOME=/home/idodo

针对第1、2种方式,在配置文件中直接使用即可,但针对第3种,却有2种使用方式:

  • 在配置文件中引入文件
  • 如果该文件位于classpath下,可使用resource导入

默认值

在使用变量时,如果变量并不存在,可指定默认值(使用符合:-):${aName:-golden}的默认值是 golden;另外变量和变量的值,都可以引用其他变量,如<property name="USER_${home:-HOME}" value="/home/${app_name:-idodo}" />

其他快捷方式:使用contextname可以获取上下文名称,使用{context_name}可以获取上下文名称,使用{HOSTNAME}可以获取主机名。 另外,还可以定义颜色(如define 配置节)或作用域(如scope设置),甚至编写逻辑(如if-then等),基本不常用,感兴趣可以通过官网研究。

第一节、 :配置logger

<logger name="chapters.configuration" level="info" additivity="false">
  <!--可以包括 0个 或 多个 -->
  <appender-ref></appender-ref>
</logger>
属性必须备注
name必须java包或者类名影响package chapters.configuration下的日志行为
level可选inherited、null、trace, debug, info, warn, error, all或off如何设为inherited或null,会默认继承的level属性(下面有介绍)
additivity可选true、false是否附加父级的logger,详见:logger的继承关系

:配置root logger

<root level="debug">
   <!--可以包括 0-n 个 -->
   <appender-ref></appender-ref>
</root>
属性必须备注
level必须trace, debug, info, warn, error, all或off不能设置为inherited和null,没意义

只有level属性,因为默认name=root,而且root没有设置additivity的意义。
特别强调:一定要留意《第二节》聊一聊日志系统 Logback#Appender的继承方式,否则会发生日志重复记录的问题

再来一个完整的例子

<configuration>
  <contextName>idodo-cloud-idp</contextName>
  <appender name="STDOUT"
    class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <logger name="idodo.cloud.idp.configuration" level="INFO" />
  <logger name="idodo.cloud.idp.configuration.security" level="DEBUG" />

  <root level="DEBUG">
    <appender-ref ref="STDOUT" />
  </root>

</configuration>

第二节、:配置详解

<appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>myApp.log</file>
    <encoder>
      <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
    </encoder>
</appender>
属性必须备注
name必须字符串用于被其他配置节引用
class必须ch.qos.logback.core.FileAppender、ConsoleAppender输出到哪里的Appender实现类
layout可选配置节内容可包含0-n个
encoder可选配置节内容可包含0-n个
filter可选配置节内容可包含0-n个

除了以上属性之外,还可以包含class指定appender类的属性,如FileAppender的文件属性。

Appender 支持哪些 class

  • ch.qos.logback.core.ConsoleAppender:输出到控制台,主要属性包括target和encoder
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!--把 target修改为 System.err,默认是System.out-->
    <target>System.err</target>
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
    </encoder>
  </appender>

  <root level="DEBUG">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
  • ch.qos.logback.core.FileAppender:输出到文件,主要属性包括append、file和encoder
<configuration>
  <!--定义时间片,timeReference表示以日志上下文创建时间为参考-->
  <timestamp key="byMin" datePattern="yyyy-MMdd_HHmm" timeReference="contextBirth"/>
  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <!--日志文件位置,可以是绝对路径或相对路径(运行jar所在为根目录)-->
    <!--使用时间片:每次重启项目时都会创建一个新日志文件-->
    <file>[${byMin}]_testFile.log</file>
    <!--true:表示会在原来日志内容后面追加日志;false:每次重启项目都会清空日志文件-->
    <!--无论是否使用时间片作为文件名,只要重启项目时文件名存在就会被清空-->
    <append>true</append>
    <!-- true:表示立即刷新输出流,保证日志不丢失;false:不会立即刷新,可以提高日志吞吐量 -->
    <!--这个属性所有日志类型都有-->
    <immediateFlush>true</immediateFlush>
    
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender>
        
  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>
  • ch.qos.logback.core.rolling.RollingFileAppender:根据策略把日志写到不同的日志文件中(常用),主要属性包括append、file、encoder、rollingPolicy和triggeringPolicy
<configuration>
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>logFile.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- daily rollover -->
      <fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>

      <!-- keep 30 days' worth of history capped at 3GB total size -->
      <maxHistory>30</maxHistory>
      <totalSizeCap>3GB</totalSizeCap>

    </rollingPolicy>

    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender> 

  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>

比FileAppender多了两个属性:rollingPolicy和triggeringPolicy

另外,还有很多网络、安全和邮件相关的Appender。

  • ch.qos.logback.classic.net.SocketAppender :允许应用程序通过网络连接到远程日志服务器,以便将日志事件发送到服务器
  • ch.qos.logback.classic.net.server.ServerSocketAppender:允许客户端通过网络链接到应用程序,以便将日志事件发送到客户端
  • ch.qos.logback.classic.net.SMTPAppender:将日志事件累积到一个或多个固定大小的缓冲区中,并在用户指定的事件发生后将适当缓冲区的内容发送到电子邮件中
  • ch.qos.logback.classic.db.DBAppender:将日志事件插入到三个数据库表中
  • ch.qos.logback.classic.net.SyslogAppender:向远程syslog守护进程发送消息
  • ch.qos.logback.classic.sift.SiftingAppender:根据用户会话分离日志事件,以便不同用户生成的日志进入不同的日志文件,每个用户一个日志文件
  • ch.qos.logback.classic.AsyncAppender:仅仅充当一个事件分派器,因此必须引用另一个appender才能执行任何有用的操作

Appender encoder 格式

目前PatternLayoutEncoder 是唯一有用的且默认的 ,有一个节点,用来设置日志的输入格式。使用“%”加“转换符”方式配置。

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>