1、java.util.logging (JUL):

JDK1.4开始,通过 java.util.logging 提供日志功能。它能满足基本的日志需要,但是功能没有Log4j强大,而且使用范围也没有Log4j广泛。

2、Log4j:

Log4j是apache的一个开源项目,创始人Ceki Gulcu。

Log4j应该说是Java领域资格最老,应用最广的日志工具。从诞生之日到现在一直广受业界欢迎。

Log4j是高度可配置的,并可通过在运行时的外部文件配置。它根据记录的优先级别,并提供机制,以指示记录信息到许多的目的地,诸如:数据库,文件,控制台,UNIX系统日志等。

Log4j中有三个主要组成部分:

loggers: 负责捕获记录信息。

appenders : 负责发布日志信息,以不同的首选目的地。

layouts: 负责格式化不同风格的日志信息。

3、Logback:

Logback是由log4j创始人Ceki Gulcu设计的又一个开源日记组件,目标是替代log4j。

logback当前分成三个模块:logback-core, logback- classic和 logback-access。

logback-core是其它两个模块的基础模块。

logback-classic是log4j的一个 改良版本。此外logback-classic完整实现SLF4J API使你可以很方便地更换成其它日记系统如log4j或JDK14 Logging。

logback-access访问模块与Servlet容器集成提供通过Http来访问日记的功能。

Log4j vs Logback

Logback相比Log4j具有许多好处:

1、性能提升:logback在log4j基础上做了优化,使性能提高了近10倍。此外,内存开销也减少了。

2、更充足的测试:尽管log4j也做了测试,但是logback的测试更加充分。所以,logback应该更加稳定。

3、天然支持slf4j:因为Logback-classic完全实现了slf4j的接口,所以天然支持slf4j。使用slf4j,有利于你切换日志工具库,减少工作量。

4、自动重载配置文件:Logback-classic可以自动重载更新过的配置文件。

5、自动移除旧日志:通过配置文件最大数和过期时间,Logback可以控制日志文件数并自动清除过期的日志。

6、更灵活、更精细的配置:

Logback在配置中提供更加丰富的功能来帮助你更加精细的去定制你的日志组件:

提供比log4j更丰富的过滤条件;

增加, 和 这样的条件控制;

打印异常的调用栈信息

Logback在打印异常时,会打印调用栈的包装数据。

Logback-access:

Logback-access支持Logback-classic的所有特性,并且它可以提供丰富的HTTP-access日志功能。

总结:

以上优点摘自官方推荐理由:Reasons to prefer logback over log4j。

由于Logback的作者也是Log4j的作者,所有推荐理由应该比较靠谱。

总之,相比于Log4j,好处多多,你心动了没?

4、common-logging:

common-logging是apache的一个开源项目。也称Jakarta Commons Logging,缩写JCL。

common-logging的功能是提供日志功能的API接口,本身并不提供日志的具体实现(当然,common-logging内部有一个Simple logger的简单实现,但是功能很弱,直接忽略),而是在运行时动态的绑定日志实现组件来工作(如log4j、java.util.loggin)。

官网地址

5、slf4j:

全称为Simple Logging Facade for Java,即java简单日志门面。

什么,作者又是Ceki Gulcu!这位大神写了Log4j、Logback和slf4j,专注日志组件开发五百年,一直只能超越自己。

类似于Common-Logging,slf4j是对不同日志框架提供的一个API封装,可以在部署的时候不修改任何配置即可接入一种日志实现方案。但是,slf4j在编译时静态绑定真正的Log库。

使用SLF4J时,如果你需要使用某一种日志实现,那么你必须选择正确的SLF4J的jar包的集合(各种桥接包)。

common-logging vs slf4j:

slf4j库类似于Apache Common-Logging。但是,他在编译时静态绑定真正的日志库。这点似乎很麻烦,其实也不过是导入桥接jar包而已。

slf4j一大亮点是提供了更方便的日志记录方式:

不需要使用logger.isDebugEnabled()来解决日志因为字符拼接产生的性能问题。slf4j的方式是使用{}作为字符串替换符,形式如下:

logger.debug("id: {}, name: {} ", id, name);

总结:

综上所述,使用slf4j + Logback可谓是目前最理想的日志解决方案了。

接下来,就是如何在项目中实施了。

实施日志解决方案

使用日志解决方案基本可分为三步:

引入jar包

配置

使用API

常见的各种日志解决方案的第2步和第3步基本一样,实施上的差别主要在第1步,也就是使用不同的库。

引入jar包

这里首选推荐使用slf4j + logback 的组合。

如果你习惯了common-logging,可以选择common-logging+log4j。

强烈建议不要直接使用日志实现组件(logback、log4j、java.util.logging),理由前面也说过,就是无法灵活替换日志库。

还有一种情况:你的老项目使用了common-logging,或是直接使用日志实现组件。如果修改老的代码,工作量太大,需要兼容处理。在下文,都将看到各种应对方法。

注:据我所知,当前仍没有方法可以将slf4j桥接到common-logging。如果我孤陋寡闻了,请不吝赐教。

slf4j直接绑定日志组件

slf4j + logback

添加依赖到pom.xml中即可。

logback-classic-1.0.13.jar 会自动将 slf4j-api-1.7.21.jar 和 logback-core-1.0.13.jar 也添加到你的项目中。

ch.qos.logback
logback-classic
1.0.13
slf4j + log4j

添加依赖到pom.xml中即可。

slf4j-log4j12-1.7.21.jar 会自动将 slf4j-api-1.7.21.jar 和 log4j-1.2.17.jar 也添加到你的项目中。

org.slf4j
slf4j-log4j12
1.7.21
slf4j + java.util.logging

添加依赖到pom.xml中即可。

slf4j-jdk14-1.7.21.jar 会自动将 slf4j-api-1.7.21.jar 也添加到你的项目中。

org.slf4j

slf4j-jdk14

1.7.21

slf4j兼容非slf4j日志组件

在介绍解决方案前,先提一个概念——桥接

什么是桥接呢

假如你正在开发应用程序所调用的组件当中已经使用了common-logging,这时你需要 jcl-over-slf4j.jar把日志信息输出重定向到 slf4j-api,slf4j-api再去调用slf4j实际依赖的日志组件。这个过程称为桥接。

从图中应该可以看出,无论你的老项目中使用的是common-logging或是直接使用log4j、java.util.logging,都可以使用对应的桥接jar包来解决兼容问题。

slf4j兼容common-logging

org.slf4j
jcl-over-slf4j
1.7.12
slf4j兼容log4j
org.slf4j
log4j-over-slf4j
1.7.12
slf4j兼容java.util.logging
org.slf4j
jul-to-slf4j
1.7.12
spring 集成 slf4j
做java web开发,基本离不开spring框架。很遗憾,spring使用的日志解决方案是common-logging + log4j。
所以,你需要一个桥接jar包:logback-ext-spring。
ch.qos.logback
logback-classic
1.1.3
org.logback-extensions
logback-ext-spring
0.1.2
org.slf4j
jcl-over-slf4j
1.7.12
common-logging绑定日志组件
common-logging + log4j
添加依赖到pom.xml中即可。
commons-logging
commons-logging

1.2

log4j

log4j

1.2.17

配置

日志配置文件大同小异,需要注意的是:logback.xml和log4j.xml都需要放在classpath路径下。

完整的logback.xml参考示例

在下面的配置文件中,我为自己的项目代码(根目录:org.zp.notes.spring)设置了五种等级:

TRACE、DEBUG、INFO、WARN、ERROR,优先级依次从低到高。

因为关注spring框架本身的一些信息,我增加了专门打印spring WARN及以上等级的日志。

%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n
${user.dir}/logs/${DIR_NAME}/all.%d{yyyy-MM-dd}.log
30
30MB
%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n
${user.dir}/logs/${DIR_NAME}/error.%d{yyyy-MM-dd}.log
30
10MB
ERROR
ACCEPT
DENY
%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n
${user.dir}/logs/${DIR_NAME}/warn.%d{yyyy-MM-dd}.log
30
10MB
WARN
ACCEPT
DENY
%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n
${user.dir}/logs/${DIR_NAME}/info.%d{yyyy-MM-dd}.log
30
10MB
INFO
ACCEPT
DENY
%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n
${user.dir}/logs/${DIR_NAME}/debug.%d{yyyy-MM-dd}.log
30
10MB
DEBUG
ACCEPT
DENY
%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n
${user.dir}/logs/${DIR_NAME}/trace.%d{yyyy-MM-dd}.log
30
10MB
TRACE
ACCEPT
DENY
%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n
${user.dir}/logs/${DIR_NAME}/springframework.%d{yyyy-MM-dd}.log
30
10MB
%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n

完整的log4j.xml参考示例

log4j的配置文件一般有xml格式或properties格式。这里为了和logback.xml做个对比,就不介绍properties了,其实也没太大差别。

logback配置参数说明

logback基本兼容log4j的配置,并提供更多的功能。

使用API

slf4j用法

使用slf4j的API很简单。使用LoggerFactory初始化一个Logger实例,然后调用Logger对应的打印等级函数就行了。

importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;public classApp {private static final Logger log = LoggerFactory.getLogger(App.class);public static voidmain(String[] args) {
String msg= "print log, current level: {}";
log.trace(msg,"trace");
log.debug(msg,"debug");
log.info(msg,"info");
log.warn(msg,"warn");
log.error(msg,"error");
}
}

common-logging用法

common-logging用法和slf4j几乎一样,但是支持的打印等级多了一个更高级别的:fatal。

此外,common-logging不支持{}替换参数,你只能选择拼接字符串这种方式了。

importorg.apache.commons.logging.Log;importorg.apache.commons.logging.LogFactory;public classJclTest {private static final Log log = LogFactory.getLog(JclTest.class);public static voidmain(String[] args) {
String msg= "print log, current level: ";
log.trace(msg+ "trace");
log.debug(msg+ "debug");
log.info(msg+ "info");
log.warn(msg+ "warn");
log.error(msg+ "error");
log.fatal(msg+ "fatal");
}
}