深入探索Logback日志框架的原理分析和开发实战技术指南(下篇)
- 根节点configuration包含的属性
- 基本参数详解
- 子节点介绍
- 设置上下文名称`<contextName>`
- 使用案例
 
- 设置变量属性值`<property>`
- 获取时间戳字符串`<timestamp>`
- 设置logger
- root根节点
- additivity的继承传递模式
 
- 常用配置详解 `<appender>`
- ConsoleAppender
- 例如:
 
- FileAppender
- 例如:
 
- RollingFileAppender
- **rollingPolicy**
- fileNamePattern
- maxHistory
- 配置案例
 
- **FixedWindowRollingPolicy**
- triggeringPolicy
 
- 其他的Appender
- 案例分析
- 每天生成一个日志文件,保存30天的日志文件
- 按照固定窗口模式生成日志文件
 
 
- 常用配置详解 `<encoder>`
- <pattern>里面的转换符说明:
- 输出logger名称
- 输出Class类全限定名
- 输出上下文名称
- 日志的打印日期时间
- 输出信息深度
- 案例分析
 
- F / file 输出源文件名
- 其他格式符号
 
- 格式修饰符
- 配置详解 `<filter>`
- LevelFilter(级别过滤器):
- ThresholdFilter(临界值过滤器)
- EvaluatorFilter(求值过滤器):
- `<evaluator>`(鉴别器):
 
- 过滤掉所有日志消息中不包含“billing”字符串的日志
 
 
 
 
根节点configuration包含的属性

基本参数详解
- 当scan属性设置为true时,配置文件有改变时将会被重新加载,默认为true。
- scanPeriod设置监测配置文件是否有修改的时间间隔。如果未指定时间单位,将默认为毫秒。只有当- scan为- true时才生效。默认间隔为1分钟。
- debug属性设置为- true时将会打印出logback的内部日志信息,方便实时查看logback运行状态。默认为- false。
 <configuration scan="true" scanPeriod="60 seconds" debug="false">  
     <!-- 其他配置省略-->  
 </configuration>  
子节点介绍
设置上下文名称<contextName>
 
每个logger都默认关联到logger上下文,上下文名称默认为“default”。但是可以通过设置来将其设置为其他名称,以便于区分不同应用程序的记录。一旦设置,就无法修改。
使用案例
  <configuration scan="true" scanPeriod="60 seconds" debug="false">  
       <contextName>myApplication</contextName>  
       <!-- 其他配置省略-->  
  </configuration>  
设置变量属性值<property>
 
使用标签定义变量值,该标签有两个属性,分别是name和value。name表示变量名,value则是变量所需的值,在通过该标签定义的变量会被插入到logger上下文中。定义好变量后,可以在后续的程序中使用“${}”来引用这些变量。
使用<property>标签定义一个名属性,并在<contextName>标签中使用该属性的值,即可为logger设置上下文名称。
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <property name="APP_Name" value="myAppName" />
    <contextName>${APP_Name}</contextName>
    <!-- 其他配置省略-->
</configuration>
举个例子,使用标签定义一个用于设置logger上下文的名称,然后在标签中使用该名称即可。
获取时间戳字符串<timestamp>
 
在标签内,使用属性来定义一个名称,为项目使用当前日期时间命名,设置属性来定义日期时间格式。示例代码如下:
<timestamp key="name" datePattern="yyyyMMddHHmm">
其中,key属性指定用于identifier的名称;datePattern属性定义将当前时间转换为字符串的模式。
您可以根据自己项目的需要修改日期时间格式。
例如将解析配置文件的时间作为上下文名称:
     <configuration scan="true" scanPeriod="60 seconds" debug="false">  
          <timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>   
          <contextName>${bySecond}</contextName>  
          <!-- 其他配置省略-->  
    </configuration>   
设置logger
在Java应用程序的日志配置中,使用<logger>元素来设置某个包或具体的类的日志打印级别,并且可以指定日志输出的目的地(<appender>)。
 
- <logger>元素只有一个必须的属性 name,用于指定要设置日志级别的包名或类名,可以包含通配符。
- <logger>元素还可以包含可选的 level 属性,用于指定日志输出的级别,包括 TRACE、DEBUG、INFO、WARN、ERROR 和 OFF。
- <logger>元素还可以包含可选的 additivity 属性,用于指定是否将日志事件发送给该Logger的父级Logger。
可以在
<logger>中添加多个<appender-ref>元素来指定用于添加到该logger的各个appender。
<logger name="com.campus.o2o" level="${log.level}" additivity="true">
    <appender-ref ref="debugAppender" />
    <appender-ref ref="infoAppender" />
    <appender-ref ref="errorAppender" />
</logger>
 <!-- 特殊的logger,根logger -->
 <root lever="info">
    <!-- 指定默认的日志输出 -->
    <appender-ref ref="consoleAppender" />
 </root>
root根节点
根logger是一个<logger>元素,它只有一个level属性,应为已经被命名为"root"。level属性用来设置打印级别,大小写无关,可选的级别有:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,不能设置为INHERITED或者同义词NULL。它的默认级别是DEBUG。
 
 <!-- 特殊的logger,根logger -->
 <root lever="info">
     <!-- 指定默认的日志输出 -->
     <appender-ref ref="consoleAppender" />
 </root>
<root>可以包含零个或多个<appender-ref>元素,标识这个appender将会添加到这个logger。
additivity的继承传递模式
appender配置表示将日志打印到控制台。<logger name="logback" />控制logback包下所有类的日志打印,未设置打印级别,继承自上级的DEBUG级别。additivity未设置,默认为true,将此logger的打印信息向上传递。未设置appender,此logger本身不打印任何信息。
<root level="DEBUG">将root的打印级别设置为DEBUG并指定名为"STDOUT"的appender。
常用配置详解 <appender>
 
<appender>是<configuration>的子节点,用于写日志的组件。

 <appender>必须包含两个属性:name和class。name用于指定appender的名称,class用于指定appender的全限定名。

ConsoleAppender
要将日志输出到控制台,您可以使用以下子节点:
-  <encoder>:用于对日志进行格式化。
-  <target>:使用字符串 “System.out” 或 “System.err”,默认为 “System.out”。
例如:
     <configuration>  
      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">  
        <encoder>  
          <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>  
        </encoder>  
      </appender>     
      <root level="DEBUG">  
        <appender-ref ref="STDOUT" />  
      </root>  
    </configuration>
FileAppender
将日志写入文件时,可以使用以下子节点进行配置:
- <file>: 指定要写入的文件名,可以是相对或绝对路径。如果上级目录不存在,系统会自动创建。如果没有指定,默认为空。(提示:可以根据需要指定文件名和路径)
- <append>: 如果设置为 true,则日志会追加到文件末尾;如果设置为 false,则会清空现有文件内容。默认为 true。(提示:可以选择是否追加日志或覆盖文件内容)
- <encoder>: 用于对记录的事件进行格式化的编码器参数。(提示:可以根据需要设置适当的编码器参数)
- <prudent>: 如果设置为 true,即使其他 FileAppender 正在向该文件写入,日志也会被安全写入文件,但效率会较低。默认为 false。 (提示:可以选择是否启用安全写入模式)
例如:
<configuration>
  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>/path/to/testFile.log</file>
    <append>true</append>
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender>
  <root level="DEBUG">
    <appender-ref ref="FILE"/>
  </root>
</configuration>
RollingFileAppender

 这个配置使用RollingFileAppender,满足以下要求:
- <file>:指定主日志文件的路径,这里使用- /path/to/logFile.log作为示例,请替换为你实际需要的路径。
- <append>:设置为- true,表示日志会追加到文件的结尾。
- <encoder>:使用给定的模式对日志事件进行格式化。
- <rollingPolicy>:使用- TimeBasedRollingPolicy进行滚动记录,这里的- fileNamePattern用于指定滚动后生成的文件名模式。
- <triggeringPolicy>:使用- SizeBasedTriggeringPolicy设置日志文件的最大大小为10MB,当日志文件大小达到上限时会触发滚动记录。
<configuration>
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>/path/to/logFile.log</file>
    <append>true</append>
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender>
  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>
请确保将/path/to/logFile.log和/path/to/logFile-%d{yyyy-MM-dd}.log替换为适合你的实际文件路径和命名模式。如有需要,请进行其他配置调整。如果你有任何其他问题,请随时向我提问。
RollingFileAppender的file节点是可选项,它用于设置活动文件和归档文件的位置。如果通过设置file节点,可以将当前日志记录到指定的活动文件,而活动文件的名称不会改变。如果未设置file节点,活动文件的名称将根据fileNamePattern的值,每隔一段时间变化一次。目录分隔符可使用"/“或”"来表示。
rollingPolicy

fileNamePattern
该内容包含文件名及"%d"转换符,其中"%d"可以包含java.text.SimpleDateFormat指定的时间格式,例如:%d{yyyy-MM}。如果未直接使用"%d",则默认的时间格式为yyyy-MM-dd。
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <fileNamePattern>/path/to/logFile-%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
maxHistory
可选节点用于控制归档文件的最大保留数量。如果设置每月滚动,并且设置<maxHistory>为6,那么只会保留最近的6个月的文件,并删除之前的旧文件。需要注意的是,删除旧文件时,与归档相关的目录也会被删除。
配置案例
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <fileNamePattern>/path/to/logFile-%d{yyyy-MM-dd}.log</fileNamePattern>
    <maxHistory>30</maxHistory>    
</rollingPolicy>
FixedWindowRollingPolicy
该策略基于固定窗口算法对文件进行重命名,具有以下子节点:
- <minIndex>: 窗口索引的最小值。
- <maxIndex>: 窗口索引的最大值。如果用户指定的窗口大小超过该值,系统会自动将窗口大小设置为12。
- <fileNamePattern>: 文件名的模式。
命名模式必须包含 “%i”,例如,假设最小值和最大值分别为 1 和 2,文件名模式可以是 “mylog%i.log”。这样将会生成归档文件 “mylog1.log” 和 “mylog2.log”。另外,您还可以选择文件的压缩选项,例如 “mylog%i.log.gz” 或 “mylog%i.log.zip”。
   
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
   <maxFileSize>10MB</maxFileSize>
</triggeringPolicy>
    
triggeringPolicy
SizeBasedTriggeringPolicy:该策略会监视当前活动文件的大小,如果其大小超过指定值,将触发 RollingFileAppender 执行文件滚动操作。此策略只适用于单一节点的情况。
<maxFileSize>:这是指定的活动文件大小,默认值为10MB。
其他的Appender
-  SocketAppender:SocketAppender用于将日志消息通过网络传输到远程的Socket服务器。它可以将日志发送到指定的远程Socket地址,并将日志消息传递给服务器进行处理和存储。 
-  SMTPAppender:SMTPAppender用于通过邮件将日志消息发送给指定的收件人。它可以将日志消息作为邮件附件发送,并支持邮件服务器的配置,如SMTP服务器地址、认证信息等。 
-  DBAppender:DBAppender用于将日志消息保存到数据库中。它可以将日志消息插入到指定的数据库表中,并支持各种数据库连接和配置选项。 
-  SyslogAppender:SyslogAppender用于将日志消息发送到Syslog服务器。它可以将日志消息转发到指定的Syslog服务器,并支持Syslog协议的各种配置选项。 
-  SiftingAppender:SiftingAppender用于根据不同的条件将日志消息路由到不同的目标Appender。它可以根据指定的条件(如日志级别、日志标签等)将日志消息发送到不同的Appender进行处理和存储。 
案例分析
每天生成一个日志文件,保存30天的日志文件
     <configuration>   
      <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">   
          
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">   
          <fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>   
          <maxHistory>30</maxHistory>    
        </rollingPolicy>   
       
        <encoder>   
          <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>   
        </encoder>   
      </appender>    
       
      <root level="DEBUG">   
        <appender-ref ref="FILE" />   
      </root>   
    </configuration>  
按照固定窗口模式生成日志文件
在文件大小超过20MB时,我们需要生成一个新的日志文件。同时,我们需要确保窗口大小在1到3之间。当我们保存了3个归档文件后,最早的日志将被覆盖。
此外,我们还有两个主要任务需要完成。首先,我们需要将日志信息转换成字节数组的形式。其次,我们需要将这些字节数组写入输出流中。
     <configuration>   
      <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">   
        <file>test.log</file>   
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">   
          <fileNamePattern>tests.%i.log.zip</fileNamePattern>   
          <minIndex>1</minIndex>   
          <maxIndex>3</maxIndex>   
        </rollingPolicy>   
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">   
          <maxFileSize>5MB</maxFileSize>   
        </triggeringPolicy>   
        <encoder>   
          <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>   
        </encoder>   
      </appender>   
               
      <root level="DEBUG">   
        <appender-ref ref="FILE" />   
      </root>   
    </configuration>  
常用配置详解 <encoder>
 
目前,我们使用的是PatternLayoutEncoder作为唯一有用且默认的编码器。在配置文件中,我们可以通过<pattern>节点来设置日志的输入格式。使用“%”加上转换符的方式,我们可以定义不同的日志输出格式。如果我们想要输出一个百分号“%”,那么我们需要使用反斜杠“\”对“%”进行转义。
     <encoder>   
       <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>   
    </encoder>  
里面的转换符说明:
输出logger名称
输出日志的logger名,可有一个整形参数,功能是缩短logger名,设置为0表示只输入logger最右边点符号之后的字符串。
| 转移符号 | Logger name | Result | 
|---|---|---|
| %logger | mainPackage.sub.sample.Bar | mainPackage.sub.sample.Bar | 
| %logger{0} | mainPackage.sub.sample.Bar | Bar | 
| %logger{5} | mainPackage.sub.sample.Bar | m.s.s.Bar | 
| %logger{10} | mainPackage.sub.sample.Bar | m.s.s.Bar | 
| %logger{15} | mainPackage.sub.sample.Bar | m.s.sample.Bar | 
| %logger{16} | mainPackage.sub.sample.Bar | m.sub.sample.Bar | 
| %logger{26} | mainPackage.sub.sample.Bar | mainPackage.sub.sample.Bar | 
输出Class类全限定名
输出执行记录请求的调用者的全限定名。参数与上面的一样。尽量避免使用,除非执行速度不造成任何问题。
 
输出上下文名称
在Logback中,可以通过contextName属性来获取Logger的上下文名称,通过cn来获取调用者的全限定名。这两个属性可以在Logback的配置文件中进行配置。
要获取contextName属性,可以使用以下方式:
<property name="contextName" value="${logback.contextName}" />
然后,在日志输出中使用${contextName}占位符来获取上下文名称。要获取调用者的全限定名,可以使用以下方式:
<encoder>
    <pattern>%X{cn} - %msg%n</pattern>
</encoder>
在这种情况下,会将调用者的全限定名存储在MDC(Mapped Diagnostic Context)的cn键中,然后在日志输出模式中使用%X{cn}来获取。
日志的打印日期时间
在Logback中,可以使用%d{pattern}来指定日期的格式化模式,其中pattern与SimpleDateFormat中的模式语法相同。
 
 以下是一些常用的日期格式化模式示例:
- %d{yyyy-MM-dd HH:mm:ss}:输出格式为年-月-日 时:分:秒
- %d{yyyy/MM/dd HH:mm:ss}:输出格式为年/月/日 时:分:秒
- %d{yyyy-MM-dd HH:mm:ss.SSS}:输出格式为年-月-日 时:分:秒.毫秒
- %d{EEE MMM dd HH:mm:ss Z}:输出格式为星期几 月份 日 时:分:秒 时区
- %d{HH:mm:ss.SSS}:输出格式为时:分:秒.毫秒
你可以根据需要选择合适的日期格式化模式,然后将其放置在Logback配置文件中的适当位置来格式化打印的日志信息中的日期。
| Conversion Pattern | Result | 
|---|---|
| %d | 2006-10-20 14:06:49,812 | 
| %date | 2006-10-20 14:06:49,812 | 
| %date{ISO8601} | 2006-10-20 14:06:49,812 | 
| %date{HH:mm:ss.SSS} | 14:06:49.812 | 
| %date{dd MMM yyyy ;HH:mm:ss.SSS} | 20 oct. 2006;14:06:49.812 | 
输出信息深度
输出生成日志的调用者的位置信息,整数选项表示输出信息深度。
caller{depth}caller{depth, evaluator-1, ... evaluator-n}
案例分析
%caller{2}
0 [main] DEBUG - logging statement
Caller+0 at mainPackage.sub.sample.Bar.sampleMethodName(Bar.java:22)
Caller+1 at mainPackage.sub.sample.Bar.createLoggingRequest(Bar.java:17)
%caller{3}
16 [main] DEBUG - logging statement
Caller+0 at mainPackage.sub.sample.Bar.sampleMethodName(Bar.java:22)
Caller+1 at mainPackage.sub.sample.Bar.createLoggingRequest(Bar.java:17)
Caller+2 at mainPackage.ConfigTester.main(ConfigTester.java:38)
F / file 输出源文件名
| Conversion Pattern | Result | 
|---|---|
| %F | 输出执行记录请求的Java源文件名。请谨慎使用,可能会影响执行速度。 | 
其他格式符号
| Conversion Pattern | Result | 
|---|---|
| %L | 输出执行日志请求的行号。请谨慎使用,可能会影响执行速度。 | 
| %m / %msg / %message | 输出应用程序提供的信息。 | 
| %M | 输出执行日志请求的方法名。请谨慎使用,可能会影响执行速度。 | 
| %n | 输出平台相关的分行符“\n”或者“\r\n”。 | 
| %p / %le / %level | 输出日志级别。 | 
| %r / %relative | 输出从程序启动到创建日志记录的时间,单位是毫秒。 | 
| %t / %thread | 输出产生日志的线程名。 | 
| %replace(%p, {r, t}) | p 为日志内容,r 是正则表达式,将p 中符合r 的内容替换为t。 | 
格式修饰符
格式修饰符与转换符共同使用,可用于对输出进行格式修饰和优化。
第一个可选的修饰符是左对齐标志,用减号“-”表示。接下来是可选的最小宽度修饰符,用十进制数表示。如果字符数小于最小宽度,则会进行左填充或右填充,默认为左填充(即右对齐),使用空格作为填充符。
如果字符数大于最小宽度,则字符永远不会被截断。最大宽度修饰符由点号"."后跟十进制数表示。如果字符数大于最大宽度,则会从头部开始截断。点号后面加上减号“-”和数字表示从尾部截断。
例如,%-4relative 表示将输出从程序启动到创建日志记录的时间进行左对齐,并且最小宽度为4。
配置详解 <filter>
 
过滤器(<filter>)用于对日志进行过滤。

执行过滤器会返回一个枚举值,即DENY、NEUTRAL或ACCEPT中的其中一个。
- 如果返回DENY,则日志将立即被抛弃,不再经过其他过滤器的处理;
- 如果返回NEUTRAL,则下一个在有序列表中的过滤器会继续处理日志;
- 如果返回ACCEPT,则日志会立即被处理,不再经过剩余的过滤器。
过滤器可以被添加到<Appender>(日志处理器)中。当为<Appender>添加一个或多个过滤器时,可以使用任意条件对日志进行过滤。如果<Appender>中存在多个过滤器,那么过滤器会按照配置顺序依次执行。
LevelFilter(级别过滤器):
级别过滤器是一种根据日志级别进行过滤的机制。当日志级别与配置的级别相等时,过滤器会根据onMatch和onMismatch进行相应的操作。该过滤器包含以下子节点:
- <level>:用于设置过滤级别。
- <onMatch>:用于配置符合过滤条件的操作。
- <onMismatch>:用于配置不符合过滤条件的操作。
例如,将过滤器的日志级别配置为INFO,那么所有INFO级别的日志都会被交给适当的appender进行处理,而非INFO级别的日志则会被过滤掉。
     <configuration>   
      <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">   
        <filter class="ch.qos.logback.classic.filter.LevelFilter">   
          <level>INFO</level>   
          <onMatch>ACCEPT</onMatch>   
          <onMismatch>DENY</onMismatch>   
        </filter>   
        <encoder>   
          <pattern>   
            %-4relative [%thread] %-5level %logger{30} - %msg%n   
          </pattern>   
        </encoder>   
      </appender>   
      <root level="DEBUG">   
        <appender-ref ref="CONSOLE" />   
      </root>   
    </configuration>  
ThresholdFilter(临界值过滤器)
临界值过滤器根据指定的临界值来过滤低于该临界值的日志。当日志级别等于或高于临界值时,过滤器返回NEUTRAL(中性);当日志级别低于临界值时,日志会被拒绝。
例如,如果希望过滤掉所有低于INFO级别的日志,则可以将临界值设置为INFO。如果还有其他需要帮助的地方,请随时告诉我。
     <configuration>   
      <appender name="CONSOLE"   
        class="ch.qos.logback.core.ConsoleAppender">   
        <!-- 过滤掉 TRACE 和 DEBUG 级别的日志-->   
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">   
          <level>INFO</level>   
        </filter>   
        <encoder>   
          <pattern>   
            %-4relative [%thread] %-5level %logger{30} - %msg%n   
          </pattern>   
        </encoder>   
      </appender>   
      <root level="DEBUG">   
        <appender-ref ref="CONSOLE" />   
      </root>   
    </configuration>  
EvaluatorFilter(求值过滤器):
求值过滤器用于评估和鉴别日志是否符合指定条件。
<evaluator>(鉴别器):
 
鉴别器是常用的求值器,其中最常用的是JaninoEventEvaluator(Janino事件评估器),也是默认的鉴别器。它接受一个任意的 Java 布尔值表达式作为求值条件,并在配置文件解释过程中动态编译这个布尔值表达式。如果布尔值表达式返回 true,则表示符合过滤条件。evaluator 还包含一个子标签 <expression>,用于配置求值条件。
求值表达式作用于当前日志,logback向求值表达式暴露日志的各种字段:
| Name | Type | Description | 
|---|---|---|
| event | LoggingEvent | 与记录请求相关联的原始记录事件,下面所有变量都来自 event,例如,event.getMessage() 返回下面 “message” 相同的字符串 | 
| message | String | 日志的原始消息,例如,设有 logger mylogger,“name” 的值是 “AUB”,对于 mylogger.info(“Hello {}”,name); “Hello {}” 就是原始消息 | 
| formattedMessage | String | 日志被格式化的消息,例如,设有 logger mylogger,“name” 的值是 “AUB”,对于 mylogger.info(“Hello {}”,name); “Hello Aub” 就是格式化后的消息 | 
| logger | String | logger 名 | 
| loggerContext | LoggerContextVO | 日志所属的 logger 上下文 | 
| level | int | 级别对应的整数值,所以 level > INFO 是正确的表达式 | 
| timeStamp | long | 创建日志的时间戳 | 
| marker | Marker | 与日志请求相关联的 Marker 对象,注意 “Marker” 有可能为 null,所以你要确保它不能是 null | 
| mdc | Map | 包含创建日志期间的 MDC 所有值的 map。访问方法是:mdc.get(“myKey”) 。mdc.get() 返回的是 Object 不是 String,要想调用 String 的方法就要强转 | 
| throwable | java.lang.Throwable | 如果没有异常与日志关联,“throwable” 变量为 null。不幸的是,“throwable” 不能被序列化。在远程系统上永远为 null。对于与位置无关的表达式请使用下面的变量 throwableProxy | 
| throwableProxy | IThrowableProxy | 与日志事件关联的异常代理。如果没有异常与日志事件关联,则变量 “throwableProxy” 为 null。当异常被关联到日志事件时,“throwableProxy” 在远程系统上不会为 null | 
过滤掉所有日志消息中不包含“billing”字符串的日志
     <configuration>   
       
      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">   
        <filter class="ch.qos.logback.core.filter.EvaluatorFilter">         
          <evaluator> <!-- 默认为 ch.qos.logback.classic.boolex.JaninoEventEvaluator -->   
            <expression>return message.contains("billing");</expression>   
          </evaluator>   
          <OnMatch>ACCEPT </OnMatch>  
          <OnMismatch>DENY</OnMismatch>  
        </filter>   
        <encoder>   
          <pattern>   
            %-4relative [%thread] %-5level %logger - %msg%n   
          </pattern>   
        </encoder>   
      </appender>   
       
      <root level="INFO">   
        <appender-ref ref="STDOUT" />   
      </root>   
    </configuration>  



















