深入探索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>