1.本篇不是什么?
Java Logging API是sun公司于2002年5月正式发布的。它是自J2SE 1.4版本开始提供的一个新的应用程序接口。它能够很方便地控制和输出日志信息到文件,控制台或其它用户定义的地方,如数据库,电子邮件等。所以它是为最 终用户,系统管理员,软件服务工程师和开发人员提供的一种捕捉安全漏洞,检查配置正确性,跟踪调查系统运行瓶颈和调查系统运行错误的工具。 Java Logging API提供了七个级别用来控制输出。从高到底分别是:finest,finer,fine,config,info,warning,server
Log4j
LOGBack
Logback是由log4j创始人设计的又一个开源日记组件。logback当前分成三个模块:logback-core,logback- classic和logback-access。logback-core是其它两个模块的基础模块。logback-classic是log4j的一个 改良版本。此外logback-classic完整实现SLF4J API使你可以很方便地更换成其它日记系统如log4j或JDK14 Logging。logback-access访问模块与Servlet容器集成提供通过Http来访问日记的功能。配置文件logback.xml。
简单日记门面(Facade)SLF4J是为各种loging APIs提供一个简单统一的接口,从而使得最终用户能够在部署的时候配置自己希望的loging APIs实现。 Logging API实现既可以选择直接实现SLF4J接的loging APIs如: NLOG4J、SimpleLogger。也可以通过SLF4J提供的API实现来开发相应的适配器如Log4jLoggerAdapter、JDK14LoggerAdapter。
Log4j vs. java.util.Logging
从JDK 1.4.0开始,引入了java.util.logging包。虽然Log4J小组曾竭力游说JCP(Java Community Process)采用Log4J作为JDK 1.4的“标准”日志API,虽然最终因Sun的日志API规范的负责人Graham Hamilton的一句“Merlin的开发已经到了最后阶段,这时不允许再对主要API做出改变”而没有被采纳,但Log4J还是对新的日志API产生 了重要影响。那么,我们到底应该采用Log4J还是java.util.logging包呢?下面仅对两者做一简单的比较。
1. Log4J更加成熟,从1999年10月开始至今已经有3年的时间,并且已经在许多项目中有着成熟的应用。而JDK中的logging包是在1.4之后才 引入的,并且不能运行于JDK 1.3之前的版本。Log4J则可以良好地运行于JDK 1.1之后的所有版本。
2. Log4J已经被移植到多种环境下,包括log4c(C)、log4cpp(C++)、log4perl(Perl)、log4net(.net)等。在这些环境下,可以感受到几乎一致的配置和使用方式。这是JDK中的logging API所不能比拟的。
3. Log4J还具有更加强力的格式化系统,可以使记录输出时实现简单的模式。但是,它不会增加类而导致格式化工具的扩展。众多的附加程序和处理器使得Log4J数据包成为一个绝佳的选择,所有你所需要的都可能加以实现。
4. Log4J在性能上做了最大的优化。Logging API对于简单的使用是足够的,但它缺少了许多Log4J所具有的功能。所以,如果你需要一个强力的logging机制,就应坚持使用Log4J;而如果只是需要一些简单的控制或文件记录,那么可以使用已经内建在JDK之中的logging API。
日志组合 |
JCL+Log4j |
SLF4J+Logback |
优点 |
l使用的成熟 l案例丰富 |
l越来越多选择其作为日志方案,如Hibernate、iBatis l日志性能高,支持参数化的log字符串,避免了之前为了减少字符串拼接的性能损耗而不得不写的if(logger.isDebugEnable()),现在你可以直接写:logger.debug(“current user is: {}”, user)。 |
缺点 |
l不再被维护 l不适用OSGi开发 l日志记录性能不高 |
lLogback作为Log4j的继任者 lLogback兼容Log4j,但提供更多的扩展 |
static { // Is Log4J Available? try { if (null != Class.forName("org.apache.log4j.Logger")) { log4jIsAvailable = true; } else { log4jIsAvailable = false; } } catch (Throwable t) { log4jIsAvailable = false; } // Is JDK 1.4 Logging Available? try { if ((null != Class.forName("java.util.logging.Logger")) && (null != Class.forName("org.apache.commons.logging.impl.Jdk14Logger"))) { jdk14IsAvailable = true; } else { jdk14IsAvailable = false; } } catch (Throwable t) { jdk14IsAvailable = false; } // Set the default Log implementation String name = null; try { name = System.getProperty("org.apache.commons.logging.log"); if (name == null) { name = System.getProperty("org.apache.commons.logging.Log"); } } catch (Throwable t) { } if (name != null) { try { setLogImplementation(name); } catch (Throwable t) { try { setLogImplementation ("org.apache.commons.logging.impl.NoOpLog"); } catch (Throwable u) { ; } } } else { try { if (log4jIsAvailable) { setLogImplementation ("org.apache.commons.logging.impl.Log4JLogger"); } else if (jdk14IsAvailable) { setLogImplementation ("org.apache.commons.logging.impl.Jdk14Logger"); } else { setLogImplementation ("org.apache.commons.logging.impl.NoOpLog"); } } catch (Throwable t) { try { setLogImplementation ("org.apache.commons.logging.impl.NoOpLog"); } catch (Throwable u) { ; } } } }默认会先找Log4j,其次是JUL再次是JCL自己的,不过此时没有任何操作。该类的源码放在 : https://gist.github.com/yongchun/7595536
org.apache.commons.logging.Log public void warn(Object message); public void warn(Object message, Throwable t);其自身的实现为:
public void warn(Object message) { getLogger().log(FQCN, Priority.WARN, message, null ); } public void warn(Object message, Throwable t) { getLogger().log(FQCN, Priority.WARN, message, t ); }log4j对应的实现为:
org.apache.log4j.Logger public void warn(Object message) { if(repository.isDisabled( Level.WARN_INT)) return; if(Level.WARN.isGreaterOrEqual(this.getEffectiveLevel())) forcedLog(FQCN, Level.WARN, message, null); } public void warn(Object message, Throwable t) { if(repository.isDisabled(Level.WARN_INT)) return; if(Level.WARN.isGreaterOrEqual(this.getEffectiveLevel())) forcedLog(FQCN, Level.WARN, message, t); } }
public void warn(String msg); public void warn(String format, Object arg); public void warn(String format, Object... arguments); public void warn(String format, Object arg1, Object arg2); public void warn (String msg, Throwable t);
logback日志框架的实现
public void warn (String msg) { filterAndLog_0_Or3Plus(FQCN, null, Level. WARN, msg, null, null ); } public void warn(String msg, Throwable t) { filterAndLog_0_Or3Plus(FQCN, null, Level. WARN, msg, null, t); } public void warn(String format, Object arg) { filterAndLog_1(FQCN, null, Level. WARN, format, arg, null); } public void warn(String format, Object arg1, Object arg2) { filterAndLog_2(FQCN, null, Level. WARN, format, arg1, arg2, null); } public void warn(String format, Object[] argArray) { filterAndLog_0_Or3Plus(FQCN, null, Level. WARN, format, argArray, null); } public void warn(Marker marker, String msg) { filterAndLog_0_Or3Plus(FQCN, marker, Level. WARN, msg, null, null ); } public void warn(Marker marker, String format, Object arg) { filterAndLog_1(FQCN, marker, Level. WARN, format, arg, null); } public void warn(Marker marker, String format, Object[] argArray) { filterAndLog_0_Or3Plus(FQCN, marker, Level. WARN, format, argArray, null); } public void warn(Marker marker, String format, Object arg1, Object arg2) { filterAndLog_2(FQCN, marker, Level. WARN, format, arg1, arg2, null); } public void warn(Marker marker, String msg, Throwable t) { filterAndLog_0_Or3Plus(FQCN, marker, Level. WARN, msg, null, t); }
所以slf4j和logback是一套的,是接口和接口实现的关系。
再看下JCL-->slf4j 的转换 jcl-over-slf4j.jar
public void warn(Object message) { differentiatedLog(null, CATEGORY_FQCN, LocationAwareLogger.WARN_INT, message, null); } public void warn(Object message, Throwable t) { differentiatedLog(null, CATEGORY_FQCN, LocationAwareLogger.WARN_INT, message, t); } void differentiatedLog(Marker marker, String fqcn, int level, Object message, Throwable t) { String m = convertToString(message); if (locationAwareLogger != null) { locationAwareLogger.log(marker, fqcn, level, m, null, t); } else { switch (level) { case LocationAwareLogger.TRACE_INT: slf4jLogger.trace(marker, m); break; case LocationAwareLogger.DEBUG_INT: slf4jLogger.debug(marker, m); break; case LocationAwareLogger.INFO_INT: slf4jLogger.info(marker, m); break; case LocationAwareLogger.WARN_INT: slf4jLogger.warn(marker, m); break; case LocationAwareLogger.ERROR_INT: slf4jLogger.error(marker, m); break; } } }
其中:
locationAwareLogger.log(marker, fqcn, level, m, null, t);
public void log(Marker marker, String fqcn, int level, String message, Object[] argArray, Throwable t);
这个方法是slf4j的spi