log4j基础知识二 LoggingEvent类,性能

log4j基础知识2 LoggingEvent类,性能
LoggerEvent
当threshold和logger-level都通过后,会创建LoggingEvent对象。里面可以得到当前时间,线程信息。NDC, MDC and 本地信息。LocationInformation是log4j的内部信息,包括了文件名,代码行数,类的名字等信息。它是从执行堆栈信息取到的。LoggingEvent是可以序列化的对象。

性能
性能中的一个是在于计算成本。而对于日志的调用可能存在上千上万次得调用。
第一个如是在代码本身的可能造成的性能问题,如
x.debug("Entry number: " +i+" is "+entry[i]);
像这样的日志代码我们很常见吧。这里我们会把message拼装好,然后由log4j决定是否需要调用这个方法。那么如果debug级别是无效的话,这里的"Entry number: " +i+" is "+entry[i]字符串拼接代码将会成为无效的代码。因此更好的写法应该是:
if(x.isDebugEnabled() {
x.debug("Entry number: "+i+" is "+String.valueOf(entry[i]));
}
这里首先是判断是否开启了debug级别。如果没有开启,那么就不会执行if里面的代码,因此性能会更好。

测试

package com.cgodo.log4j.test;

import java.io.IOException;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggerRepository;

/**
* log4j测试
*
* @author liyixing liyixing1@yahoo.com.cn
* @version 1.0
* @since 2011-7-3 上午01:37:42
*/
public class Test {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
BasicConfigurator.configure();
Logger log = Logger.getLogger("a");
log.setLevel(Level.INFO);

long t1 = System.currentTimeMillis();

/*
注意,这里我只是为了方便测试,这更好的写法应该是在for之前写if (log.isDebugEnabled())
*/
for (int i = 0; i < 500; i++) {
if (log.isDebugEnabled()) {
log.info("调用中" + "i是" + i);
}
}

long t2 = System.currentTimeMillis();

System.out.println(t2 - t1);

t1 = System.currentTimeMillis();

for (int i = 0; i < 500; i++) {
log.info("调用中" + "i是" + i);
}

t2 = System.currentTimeMillis();

System.out.println(t2 - t1);
}
}

第一种写法只需要0毫秒
而第二种写法则耗费了15毫秒(注,if语句对于一般的pc机器来说是纳秒级别的)
Logger还有isInfoEnabled方法,isEnabledFor方法(用于查询指定级别是否开启)。对于error,fatal,WARN等级别,由于很少使用,所以不存在对应的isXXXEnabled方法,因为这些级别的记录很少存在,因此在性能上的提升很少。

在有些版本的java中,对于if(final常量或者直接常量的值为false)之类的语句,会把这样的if语句和if的体代码删除掉,来优化java的执行。

因此我们可以把debug级别是否开启,使用一个静态变量保存。然后当需要关闭的时候,只需要把这个变量设置为false,那么编译后,if语句和if的体内容会被删除掉,那么性能会更好。但是这样就无法做到可配置性。因此在实际项目中很少这么做。

另一个性能问题是在于祖先的问题。在创建logger对象的时候,正常情况下需要将其的祖先创建出来。但是这样的话,logger对象就可能存在很多个。那么,而log4j的处理是直接连到到最近的一个需要被创建的祖先,而不会把每一级别的祖先都创建出来。

实际记录(格式化和输出到设备上)的性能
log4j本身提供的几个设备appender和布局实现,一般时间是在100-300微秒(可能更长)