Log4j的应用说明与原理
public void trace(Object message);public void trace(Object message, Throwable t);
public void debug(Object message);
public void debug(Object message, Throwable t);
public void error(Object message);
public void error(Object message, Throwable t);
public void fatal(Object message);
public void fatal(Object message, Throwable t);
public void info(Object message);
public void info(Object message, Throwable t);
public void warn(Object message);
public void warn(Object message, Throwable t);
// 下面两个是更通用的打印方法
public void log(Priority priority, Object message);
public void log(Priority priority, Object message, Throwable t);
这些方法的名字体现了日志请求的级别,Log4j规定:
只有日志请求的级别高于或者等于logger的级别时,日志请求才会生效。这意味着log4j中的日志级别是按照顺序排列的,默认的级别顺序是:ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL。
例如假设loggerA的日志级别是WARN,则“loggerA.info(“...”)”的日志打印则不会生效,因为请求级别INFO低于loggerA的日志级别WARN。
Appender,Layout
我们希望可以把日志打印到不同的地方,例如有时候把日志打印到控制台就可以了,另一些时候需要打印到文件中,有时为了性能可能又需要把日志先记录到一个异步队列中,在log4j中,日志具体输出的目的地就是用Appender来表示的,log4j提供了不同类型的appender可用,例如ConsoleAppender,FileAppender,SocketAppender,JdbcAppender,我们也可以实现自己需要的appender。
Appender是通过Logger的addAppender(appender)方法来关联的,一个logger可以关联多个appender对象。
appender additivity性质
“appender additivity”表示的意思就是:
生效的日志请求会被输出到此logger关联的所有appender中,也会被输出到所有上层logger关联的所有appender中,一直到root logger的所有appender。例如 “x.y” 关联一个SocketAppender,”x“ 关联一个FileAppender和一个ConsoleAppender,root关联一个ConsoleAppender,那么”x.y“请求的日志消息会同时被输出到SocketAppender,ConsoleAppender和FileAppender。
上述这个规则是log4j默认的。
我们可以通过设置Logger的“additivity”属性值为false来禁止这个规则,对于上述例子如果我们在“x.y”这个logger对象上设置为false,那么“x.y”请求的日志消息只会输出到SocketAppender中。
可以给appender对象关联一个layout对象,layout和appender各自的功能不同,layout是控制日志消息输出格式的,而appender是控制日志输出目的地的。同样的,layout也有多种实现,我们最常用的是PatternLayout,PatternPayout用来控制格式时功能强大,它采用模式占位符来描述最终日志的打印格式,类似C语言的printf函数,例如这个模式描述符“
%r [%t] %-5p %c - %m%n”控制的输出结果为:
176 [main] INFO org.foo.Bar - Located nearest gas station.
其中“%r”表示的是程序运行的时间,“%t”表示当前线程名字,“%-5p”表示日志请求级别,此字段占5个字符宽度并使用左对齐,“%c”表示logger的名字,“%m”表示日志消息内容。
Log4j还提供一个SimpleLayout,它控制简单的日志格式打印,其输出结果格式仅仅包含日志请求级别和日志消息内容:
DEBUG - Hello world
SimpleLayout显然功能不如PatternLayout强大,但是它性能高,在只需要简单记录日志的情况下也不错。
Filter链
Appender中还维护了一个Filter链,它提供了addFilter(filter)和getFilter()方法,如名字所示,Filter作用于日志请求内容并起过滤作用。
Filter采用责任链的设计思想,其核心方法是decide(LogEvent ),filter链中的所有decide方法按顺序处理日志事件并决定日志事件是被丢弃还是保留,此方法返回一个枚举整数值,取直包括:
- DENY
NUETRAL
ACCEPT
如果返回DENY,则表示不再需要咨询下一个filter了,直接丢弃日志事件。
如果返回NUETRAL,则表示还需要咨询下一个filter来决定如何处理日志事件,如果当前已经是最后一个filter,则日志会被输出到目的地。
如果返回ACCEPT,则表示不需要在咨询下一个filter了,日志会被输出到目的地。
Filter的实现细节在Appender的基本实现类AppenderSkeleton中,详细可以参考
AppenderSkeleton的代码。
threshold值
在AppenderSkeleton中还有一个比较重要的属性:threshold,所有具体的Appender都会通过继承获得这个属性,threshold的值表示此appender的日志级别,如果请求的日志事件的级别低于threshold表示的日志级别,则日志事件被此appender丢弃。
在配置文件中,通过“Threshold”属性来指定值,例如:log4j.appender.file.Threshold=WARN。
配置文件写法
大多数情况下我们一般使用两种类型的配置文件:properties文件格xml文件。
Log4j内部使用Configurator组件来配置系统,Configurator可以从流对象中加载配置信息,也可以从一个URL表示的资源处加载配置信息。PropertiesConfigurator支持解析properties配置文件,DOMConfigurator支持解析xml配置文件。
这里的配置示例说明采用properties形式。
全局范围的配置
log4j.threshold=[level]
repository范围的threshold属性定义全局的日志级别,指定此属性后所有logger的日志级别将被忽略,然后所有的日志请求级别只要低于此级别就会被丢弃,默认此threshold的日志级别是ALL,因此默认它不会影响任何日志请求。
log4j.reset=true
配置上述属性后,log4j会在配置日志系统之前清理已经存在logger层级关系。
log4j.debug=true
配置此属性后,log4j的加载配置日志系统的细节信息将会打印在控制台。
Logger配置
配置root logger:
log4j.rootLogger=[level], appenderName, appenderName, …
level值是可选的,可以设置log4j内建的ALL,TRACE,DEBUG,INFO,WARN,ERROR,FATAL,OFF或者自定义级别,自定义级别的写法为“level/custom-level-classname”。
rootLogger的level值是可以省略的,如果省略的话则采用的是系统默认值。
配置其他logger:
log4j.logger.loggerName=[level | INHERITED | NULL], appenderName, appenderName, …
INHERITED值指定此logger的日志级别应该从上层logger继承获得,NULL值和INHERITEd意思相同。
配置additivity:
log4j.additivity.loggerName=false
Appender配置
配置appender:
# appender名字可以包含“.”字符
log4j.appender.appenderName=fully.qualified.name.of.appender.class
设置appender的属性:
log4j.appender.appenderName.option1=value1
log4j.appender.appenderName.option2=value2
设置appender的layout及属性:
log4j.appender.appenderName.layout=fully.qualified.name.of.layout.class
log4j.appender.appenderName.layout.option1=value1
log4j.appender.appenderName.layout.option2=value2
设置appender的filter及属性:
# ID是唯一的名字用来标识filter
# 多个filter按照ID的字母排序添加到appender中
log4j.appender.appenderName.filter.ID=fully.qualified.name.of.filter.class
log4j.appender.appenderName.filter.ID.option1=value1
log4j.appender.appenderName.filter.ID.option2=value2
设置appender的ErrorHandler:
log4j.appender.appenderName.errorhandler=fully.qualified.name.of.errorhandler.class
log4j.appender.appenderName.errorhandler.root-ref=[true|false]
log4j.appender.appenderName.errorhandler.logger-ref=loggerName
log4j.appender.appenderName.errorhandler.appender-ref=appenderName
log4j.appender.appenderName.errorhandler.option1=value1
log4j.appender.appenderName.errorhandler.option2=value2
Filter和ErrorHandler配置一般使用的少些,很多情况下直接配置logger和appender就可以了。
Log4j的初始化
Log4j的初始化相当直接,当我们调用任意一种“Logger.getLogger()”的重载形式时,Log4j就会自动初始化自己,因为在LogManager类中有一个静态初始化器,JVM加载LogManager时log4j就会获得初始化配置。
LogManager中的初始化算法描述如下:
首先要检查jvm系统属性“log4j.defaultInitOverride”是否存在,如果不存在活着存在并且属性值为false,那么就会进行初始化配置,否则跳过初始化配置过程,不进行下面的过程了。
确定log4j初始化所需要的配置,首先检查jvm系统属性“log4j.configuration”,我们可以通过此属性指定log4j的配置文件,如果没有指定“log4j.configuration”属性,那么尝试使用“log4j.xml”作为配置文件,如果不存在“log4j.xml”,最后尝试使用“log4j.properties”作为配置。注意要把“log4j.xml”或者“log4j.properties”文件放在classpath下,因为最终log4j采用system classloader来加载这个文件。
log4j尝试把配置资源转换成一个URL对象,如果能够转换成一个URL对象,接下来就开始解析配置资源并配置log4j系统。
实际配置日志系统的工作是通过Configurator组件来完成的,如果配置资源是xml形式的,则采用DOMConfigurator,否则采用PropertyConfigurator,我们也可以通过“log4j.configuratorClass”系统属性来指定具体要使用的Configurator的类名。
以上是 Log4j的应用说明与原理 的全部内容, 来源链接: utcz.com/z/513886.html