一、日志实例
log4j核心类图
创建Logger实例:
使用log4j
的日志功能时,首先需要创建一个Logger
类的实例,才能使用打印日志的功能:
Logger logger = Logger.getLogger(Test.class);
Logger
类中getLogger()
方法的实现是:
static public Logger getLogger(Class clazz) {
return LogManager.getLogger(clazz.getName());
}
实际上使用 LogManager.getLogger(Test.class)
获取Logger
实例
通过实现方式可以看到最后还是使用了Test
类的全限定类名去获取Logger
实例,实际上,完全可以直接传递Test
类的全限定类名,这里是com.xgd.Test
,来构建一个Logger
实例:
Logger logger = Logger.getLogger("com.xgd.Test");
com.xgd.Test
就是这个日志实例的实例名。
日志实例指定appender:
创建好了日志实例,还需要给该实例关联一个Appender
(如上类图),才能将通过该实例打印的日志输出到制定Appender
中。
在log4j
的properties
配置中,可以使用log4j.logger
后加上日志实例名来指定一个日志实例,并进行输出配置,如:
log4j.logger.com.xgd.Test=debug, console #console是名为console的appender
给名为com.xgd.Test
的日志实例指定了输出目的地appender
; 在log4j的xml配置中,可以使用以下方式配置日志实例的输出:
<logger name="实例名"> <!--com.xgd.Test-->
<level value=""/>
<appender-ref ref="AppenderName" />
</logger>
二、继承与覆盖
继承性:
log4j
的配置中有一个根logger
:rootLogger/root
,其配置为:
log4j.rootLogger=DEBUG,consoleAppender
或者是:
<root>
<priority value="debug" />
<appender-ref ref="CONSOLE" />
</root>
隐式继承:
root
配置决定了所有日志实例打印日志都必须遵守的规则——日志级别以及输出目的地,也即是说所有的日志实例继承了rootLogger/<root>
的输出配置,即appender
和输出级别。root
配置就像java
中的Object
类一样,任何日志实例都默认“继承”于root
,以使得所有日志实例具有root
的特性。
显式继承:
日志实例名或配置logger
时使用了英文句号 .
作为分隔名称,那么日志实例的世界就精彩了起来,“.”
的出现使日志实例具有了显示继承性,通过使用“.”
,我们可以理解为显示继承了其他日志实例,如下配置:
log4j.logger.parent = Console, debug (实例名parent)
那么,
private static final Logger logger= Logger.getLogger("parent.child");
实例名为parent.child
的日志实例,其打印出来的日志具有名为parent
的日志实例的特性,日志级别为debug
,输出目的地为console
。子日志实例(parent.child
)继承了父日志实例(parent
)。
日志实例的继承有以下特性:
1)输出级别的覆盖:
如下配置:
log4j.rootLogger=DEBUG, Console
# 以下子logger实例的日志输出级别覆盖了父logger实例
log4j.logger.parent=INFO
那么:
private static final Logger logger= Logger.getLogger("parent");
名为parent
的日志实例,打印出来的日志具有info
级别而不是debug
级别,缩减了日志的级别范围。
同样,扩大了父logger
实例的日志级别的子logger
实例也会造成覆盖
log4j.rootLogger=INFO, Console
#以下配置的logger,重写了日志输出级别
log4j.logger.parent=DEBUG
无论子logger
实例扩大还是缩减了父logger
实例的日志级别,都会造成对父logger
实例日志级别的覆盖。
2)输出目的地的追加:
如下配置:
<logger name="third">
<level value="info" />
<appender-ref ref="Console" />
</logger>
<root>
<level value= "trace" />
<appender-ref ref= "Console" />
</root>
那么继承自名为third
的日志实例会输出两次的info
级别以上的日志信息
不同于子logger
实例对父logger
实例输出日志级别的覆盖,子logger
实例 的appender
配置会在父logger
实例的基础上追加。
就像这样:
3)放弃追加
additivity
,添加的意思。
additivity
属性用于屏蔽对父logger
实例appender
的追加,通过设置子实例logger
的additivity
属性为false
,使子logger
屏蔽掉父logger
的appender
。
如下配置:
<logger name="third" additivity="false" >
<level value="info" />
<appender-ref ref="fileappende" />
</logger>
<root>
<level value= "trace" />
<appender-ref ref= "Console" />
</root>
则继承自名为third
的日志实例打印的日志不会输出到父日志实例中指定的appender(Console)
,只输出到fileappender
中。
当然,若子logger
实例没有指定appender
,并且指定了additivity
为false
,那么在打印日志时,会找不到输出目的地appender
,从而产生异常。
如以下third
没有指定appender
,且放弃追加root实例的appender
<logger name="third" additivity="false" >
<level value="info" />
</logger>
<root>
<level value= "trace" />
<appender-ref ref= "Console" />
</root>
使用继承自third
的日志实例输出日志,会报错:
log4j:WARN No appenders could be found for logger (third.log.CommonsLogTest).