###1. level规则
logj42会先匹配是否符合Logger/Root的level,如果符合的话,再一一匹配Logger/Root下的AppenderRef的level是否匹配。
<Configuration status="DEBUG" updateCheck="false">
<Appenders>
<Console name="Console1" target="SYSTEM_OUT">
<PatternLayout pattern="[%d] [%t] [%c\:%L] [%p] [%X{RequestID}] %m%n" charset="UTF-8"/>
<ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
</Console>
<Console name="Console2" target="SYSTEM_OUT">
<PatternLayout pattern="[%d] [%t] [%c\:%L] [%p] [%X{RequestID}] %m%n" charset="UTF-8"/>
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
</Console>
</Appenders>
<Loggers>
<Root level="DEBUG">
<AppenderRef ref="Console1" />
<AppenderRef ref="Console2"/>
</Root>
</Loggers>
</Configuration>
复制代码
log4j2会先匹配日志级别是否符合Root
的level级别,如果是,则一一匹配是否符合Console1
和Console2
的level级别。
以上配置,logger.debug
只会在Console1
里打印出来,logger.info
则会Console1
和Console2
两个都打印出来。
###2. additivity
log4j2会优先查找最优匹配的name
,然后将日志一级级往上抛,每一个name
匹配的Logger/Root都会再打印一次日志。
<Loggers>
<Logger name="com.test" level="DEBUG">
<AppenderRef ref="Console1"/>
</Logger>
<Logger name="org" level="DEBUG">
<AppenderRef ref="Console1"/>
</Logger>
<Logger name="com" level="DEBUG">
<AppenderRef ref="Console1"/>
</Logger>
<Root level="DEBUG">
<AppenderRef ref="Console1"/>
</Root>
</Loggers>
复制代码
以上配置,如果在com.test
包下调用logger.debug
,会打印三次,因为log4j2优先匹配到com.test
,然后往上抛再匹配到com
,继续往上抛又匹配到Root
,所以打印了三次。
可以通过配置additivity="false"
阻止上抛,additivity
默认为true
。
<Loggers>
<Logger name="org.test" level="DEBUG">
<AppenderRef ref="Console1"/>
</Logger>
<Logger name="my.test" level="DEBUG">
<AppenderRef ref="Console1"/>
</Logger>
<Logger name="com.test" level="DEBUG" additivity="false">
<AppenderRef ref="Console1"/>
</Logger>
<Logger name="org" level="DEBUG" additivity="false">
<AppenderRef ref="Console1"/>
</Logger>
<Logger name="my" level="DEBUG">
<AppenderRef ref="Console1"/>
</Logger>
<Logger name="com" level="DEBUG">
<AppenderRef ref="Console1"/>
</Logger>
<Root level="DEBUG">
<AppenderRef ref="Console1"/>
</Root>
</Loggers>
复制代码
以上配置,如果在com.test
包下调用logger.debug
,只会打印一次;如果在org.test
包下调用logger.debug
,会打印两次;如果在my.test
包下调用logger.debug
,会打印三次。
###3. 继承 Logger如果没有配置AppenderRef,会默认继承“有配置AppenderRef”的上一级的配置。
<Loggers>
<Logger name="com.test" level="ERROR"/>
<Root level="DEBUG">
<AppenderRef ref="Console1"/>
</Root>
</Loggers>
复制代码
以上配置,最终的效果是,com.test
包下level级别为ERROR
,其他包的级别为DEBUG
,但是只会打印一次日志,类似于 :
<Loggers>
<Root if(name="com.test") { level="ERROR" } else { level="DEBUG" }>
<AppenderRef ref="Console1"/>
</Root>
</Loggers>
复制代码
注:log4j2没有if-else
这种写法,这里只是表达最终的效果类似是这样的。
<Loggers>
<Logger name="com.test.test2" level="INFO"/>
<Logger name="com.test" level="INFO"/>
<Logger name="com" level="INFO" additivity="false">
<AppenderRef ref="Console1"/>
</Logger>
<Root level="DEBUG">
<AppenderRef ref="Console1"/>
<AppenderRef ref="Console2"/>
</Root>
</Loggers>
复制代码
以上配置,com.test.test2
包下打印日志,最终会继承name为com
的Logger的配置,因为com
是“有配置AppenderRef”中最优匹配com.test.test2
的Logger。
###4. 继承+additivity
<Loggers>
<Logger name="com.test" level="INFO"/>
<Logger name="org.test" level="INFO"/>
<Logger name="com" level="INFO">
<AppenderRef ref="Console1"/>
</Logger>
<Logger name="org" level="INFO" additivity="false">
<AppenderRef ref="Console1"/>
</Logger>
<Root level="DEBUG">
<AppenderRef ref="Console1"/>
</Root>
</Loggers>
复制代码
以上配置,com.test
包下打印日志,会打印两次,因为com.test
继承了com
Logger打印了一次,然后com
上抛到Root
又打印了一次;org.test
包下打印日志,只会打印一次,因为org.test
继承了org
Logger打印了一次,而org
上配置了additivity="false"
。