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()里自定义。