【slf+log4j】基础+不同级别日志分别打到不同文件

通常日志都是基于slf4j+log4j或slf4j+logback来打印。slf4j作为门面,只是提供接口,实际的打印还是使用log4j或logback提供的功能。本文以log4j为例。

1. log4j的基础http://www.cnblogs.com/Fskjb/archive/2011/01/29/1947592.html
要点:Log4J中总是存在一个rootLogger,logger可以继承,可以自定义logger名称,这个名称跟Logger.getLogger("name")的name相关。

Logger.getLogger()还是LogFactory.getLog()
Logger来自log4j自己的包。如果用Logger.getLogger,需要一个log4j的jar包,用此方式你只能依log4j:

LogFactory来自common-logging包。如果用LogFactory.getLog,你可以用任何实现了通用日志接口的日志记录器替换log4j,而程序不受影响。apache的common-logging包是通用日志接口,通过这个中间层,你可以随便指定到底用哪个日志系统。增加系统的灵活性。若log4j它不存在, commons-logging 会另行选择其它的日志实现类。 这样保证了程序中不一定要使用log4j这个日志文件了。
http://www.jb51.net/article/41291.htm

2. slf4j的优点及jar包引用可以参考: http://www.importnew.com/7450.html
要点
(1) slf4j是独立与具体打印日志框架的,可以与log4j结合,也可以方便切换到logback。
(2) 相比log4j,slf4j可以使用占位符,比如log4j的写法:
logger.debug("Processing trade with id: " + id + " symbol: " + symbol);

使用slf4j可以:
logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);

注意:不能{1},{2},{3}这种形式。
这样会在运行时被某个提供的实际字符串所替换。这不仅降低了你代码中字符串连接次数,而且还节省了新建的String对象。
(3) 省去了isDebugEnabled()、isInfoEnabled()的判断,slf4j自动提供了判断。

3. slf4j打印异常
需要打印带有可变参数的日志同时要打印异常信息,用slf4j不能直接把exception放在参数最后,也就是不能:
logger.error("error info {}#{}",new Object[]{a, b}, e);// e 是exception类型

只能:
logger.error("error info {}#{}",new Object[]{a, b, e});// e 是exception类型

把e放到可变对象数组的最后,需要两个参数的时候,把e当做第三个元素即可。 第一种写法会把e当做普通Object,调用e.toString()方法打印,无法打印出异常的堆栈信息。

注意:关于这一点,资料上说slf4j 1.7.*以上版本可以按照第一种写法,1.7.*以下必须按照第二种写法。但本人测试1.7.*也只能按照第二种写法。

4. 关于如何把 不同级别的日志输出到不同文件里,已经有不少文章描述了,完全可以参考。比如:
http://blog.csdn.net/wangchsh2008/article/details/8812857
http://www.cprogramdevelop.com/4496123/

这里有一点需要解释下,如果自定义了logger,比如:log4j.logger.A.B.C=info,ferror,finfo,fdebug
并且分别对为ferror,finfo,fdebug定义了3个文件。
##  error  appender
log4j.appender.ferror.Threshold = error
log4j.appender.ferror = A.B.C.common.util.MyDailyRollingFileAppender
log4j.appender.ferror.File = ${log.root}/error.log
log4j.appender.ferror.Append = true
log4j.appender.ferror.DatePattern = '.'yyyy-MM-dd'.log'
log4j.appender.ferror.layout = org.apache.log4j.PatternLayout
log4j.appender.ferror.layout.ConversionPattern = %-d{yyyy-MM-dd HH\:mm\:ss} [%p] %X{requestID} [%c-%L]- %m%n

##  info  appender
log4j.appender.finfo.Threshold = info
log4j.appender.finfo = A.B.C.common.util.MyDailyRollingFileAppender
log4j.appender.finfo.File = ${log.root}/info.log
log4j.appender.finfo.Append = true
log4j.appender.finfo.DatePattern = '.'yyyy-MM-dd'.log'
log4j.appender.finfo.layout = org.apache.log4j.PatternLayout
log4j.appender.finfo.layout.ConversionPattern = %-d{yyyy-MM-dd HH\:mm\:ss} [%p] %X{requestID} [%c-%L]- %m%n

##  debug  appender
log4j.appender.fdebug.Threshold = debug
log4j.appender.fdebug = A.B.C.common.util.MyDailyRollingFileAppender
log4j.appender.fdebug.File = ${log.root}/debug.log
log4j.appender.fdebug.Append = true
log4j.appender.fdebug.DatePattern = '.'yyyy-MM-dd'.log'
log4j.appender.fdebug.layout = org.apache.log4j.PatternLayout
log4j.appender.fdebug.layout.ConversionPattern = %-d{yyyy-MM-dd HH\:mm\:ss} [%p] %X{requestID} [%c-%L]- %m%n

###root log
log4j.rootLogger = ${log.level},finfo

## my log
log4j.logger.A.B.C=info,ferror,finfo,fdebug

那最后哪些级别的日志会打出来取决于log4j.logger.A.B.C定义的级别。如上配置则debug日志不会打印。
原因:
log4j会自动调用log4jLoggerAdapter的isDebugEnabled()方法:
public boolean isDebugEnabled() {
    return this.logger.isDebugEnabled();
}
public boolean isDebugEnabled() {
    return this.repository.isDisabled(10000)?false:Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel());
}

这里的getEffectiveLevel()就会返回log4j.logger.A.B.C定义的级别info,debug小于这个级别就直接忽略不打了。

如果这里配置成debug级别,则可以验证通过,后面再打印时会调用自己重写的继承DailyRollingFileAppender类实现的public boolean isAsSevereAsThreshold(Priority priority)方法,这个方法的参数priority就是实际打印日志时调用的方法,比如调用logger.debug(“这是日志”);则priority= Level.DEBUG。然后拿这个级别跟分别配置的ferror,finfo,fdebug的Threshold值比,比较的规则在isAsSevereAsThreshold()里自定义。

猜你喜欢

转载自zoroeye.iteye.com/blog/2229605
今日推荐