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中的初始化算法描述如下:

  1. 首先要检查jvm系统属性“log4j.defaultInitOverride”是否存在,如果不存在活着存在并且属性值为false,那么就会进行初始化配置,否则跳过初始化配置过程,不进行下面的过程了。

  2. 确定log4j初始化所需要的配置,首先检查jvm系统属性“log4j.configuration”,我们可以通过此属性指定log4j的配置文件,如果没有指定“log4j.configuration”属性,那么尝试使用“log4j.xml”作为配置文件,如果不存在“log4j.xml”,最后尝试使用“log4j.properties”作为配置。注意要把“log4j.xml”或者“log4j.properties”文件放在classpath下,因为最终log4j采用system classloader来加载这个文件。

  3. log4j尝试把配置资源转换成一个URL对象,如果能够转换成一个URL对象,接下来就开始解析配置资源并配置log4j系统。

 

实际配置日志系统的工作是通过Configurator组件来完成的,如果配置资源是xml形式的,则采用DOMConfigurator,否则采用PropertyConfigurator,我们也可以通过“log4j.configuratorClass”系统属性来指定具体要使用的Configurator的类名。

以上是 Log4j的应用说明与原理 的全部内容, 来源链接: utcz.com/z/513886.html

回到顶部