--- title: 细说 Java 主流日志工具库 date: 2016/10/14 categories: - javalib tags: - java - javalib - log --- # 细说 Java 主流日志工具库 - [概述](#概述) - [java.util.logging (JUL)](#javautillogging-jul) - [Log4j](#log4j) - [Logback](#logback) - [Log4j vs Logback](#log4j-vs-logback) - [common-logging](#common-logging) - [slf4j](#slf4j) - [common-logging vs slf4j](#common-logging-vs-slf4j) - [总结](#总结) - [实施日志解决方案](#实施日志解决方案) - [引入 jar 包](#引入-jar-包) - [使用 API](#使用-api) - [logback 配置](#logback-配置) - [``](#configuration) - [``](#appender) - [``](#logger) - [``](#root) - [完整的 logback.xml 参考示例](#完整的-logbackxml-参考示例) - [log4j 配置](#log4j-配置) - [完整的 log4j.xml 参考示例](#完整的-log4jxml-参考示例) - [logback 配置参数说明](#logback-配置参数说明) - [参考](#参考) ## 概述 在项目开发中,为了跟踪代码的运行情况,常常要使用日志来记录信息。 在 Java 世界,有很多的日志工具库来实现日志功能,避免了我们重复造轮子。 我们先来逐一了解一下主流日志工具。 ### java.util.logging (JUL) JDK1.4 开始,通过 `java.util.logging` 提供日志功能。 它能满足基本的日志需要,但是功能没有 Log4j 强大,而且使用范围也没有 Log4j 广泛。 ### Log4j Log4j 是 apache 的一个开源项目,创始人 Ceki Gulcu。 Log4j 应该说是 Java 领域资格最老,应用最广的日志工具。从诞生之日到现在一直广受业界欢迎。 Log4j 是高度可配置的,并可通过在运行时的外部文件配置。它根据记录的优先级别,并提供机制,以指示记录信息到许多的目的地,诸如:数据库,文件,控制台,UNIX 系统日志等。 Log4j 中有三个主要组成部分: * **loggers:**  负责捕获记录信息。 * **appenders :**  负责发布日志信息,以不同的首选目的地。 * **layouts:**  负责格式化不同风格的日志信息。 [官网地址](http://logging.apache.org/log4j/2.x/) ### 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 来访问日记的功能。 [官网地址](http://logback.qos.ch/) ### Log4j vs Logback Logback 相比 Log4j 具有许多好处: **性能提升** logback 在 log4j 基础上做了优化,使性能提高了近 10 倍。此外,内存开销也减少了。 **更充足的测试** 尽管 log4j 也做了测试,但是 logback 的测试更加充分。所以,logback 应该更加稳定。 **天然支持 slf4j** 因为 Logback-classic 完全实现了 slf4j 的接口,所以天然支持 slf4j。使用 slf4j,有利于你切换日志工具库,减少工作量。 **自动重载配置文件** Logback-classic 可以自动重载更新过的配置文件。 **自动移除旧日志** 通过配置文件最大数和过期时间,Logback 可以控制日志文件数并自动清除过期的日志。 **更灵活、更精细的配置** Logback 在配置中提供更加丰富的功能来帮助你更加精细的去定制你的日志组件: ``提供比 log4j 更丰富的过滤条件; 增加``, `` 和 ``这样的条件控制; **打印异常的调用栈信息** Logback 在打印异常时,会打印调用栈的包装数据。 **Logback-access** Logback-access 支持 Logback-classic 的所有特性,并且它可以提供丰富的 HTTP-access 日志功能。 **总结** 以上优点摘自官方推荐理由:[Reasons to prefer logback over log4j](http://logback.qos.ch/reasonsToSwitch.html)。 由于 Logback 的作者也是 Log4j 的作者,所有推荐理由应该比较靠谱。 总之,相比于 Log4j,好处多多,你心动了没? ### common-logging common-logging 是 apache 的一个开源项目。也称**Jakarta Commons Logging,缩写 JCL**。 common-logging 的功能是提供日志功能的 API 接口,本身并不提供日志的具体实现(当然,common-logging 内部有一个 Simple logger 的简单实现,但是功能很弱,直接忽略),而是在**运行时**动态的绑定日志实现组件来工作(如 log4j、java.util.loggin)。 [官网地址](http://commons.apache.org/proper/commons-logging/) ### slf4j 全称为 Simple Logging Facade for Java,即 java 简单日志门面。 什么,作者又是 Ceki Gulcu!这位大神写了 Log4j、Logback 和 slf4j,专注日志组件开发五百年,一直只能超越自己。 类似于 Common-Logging,slf4j 是对不同日志框架提供的一个 API 封装,可以在部署的时候不修改任何配置即可接入一种日志实现方案。但是,slf4j 在**编译时**静态绑定真正的 Log 库。使用 SLF4J 时,如果你需要使用某一种日志实现,那么你必须选择正确的 SLF4J 的 jar 包的集合(各种桥接包)。 [官网地址](http://www.slf4j.org/) ![slf4j工作模型](http://oyz7npk35.bkt.clouddn.com//image/java/libs/log/slf4j-to-other-log.png) ### common-logging vs slf4j slf4j 库类似于 Apache Common-Logging。但是,他在编译时静态绑定真正的日志库。这点似乎很麻烦,其实也不过是导入桥接 jar 包而已。 slf4j 一大亮点是提供了更方便的日志记录方式: 不需要使用`logger.isDebugEnabled()`来解决日志因为字符拼接产生的性能问题。slf4j 的方式是使用`{}`作为字符串替换符,形式如下: ``` logger.debug("id: {}, name: {} ", id, name); ``` ### 总结 综上所述,使用 slf4j + Logback 可谓是目前最理想的日志解决方案了。 接下来,就是如何在项目中实施了。 ## 实施日志解决方案 使用日志解决方案基本可分为三步: 1. 引入 jar 包 2. 配置 3. 使用 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* 也添加到你的项目中。 ```xml   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* 也添加到你的项目中。 ```xml   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*  也添加到你的项目中。 ```xml   org.slf4j   slf4j-jdk14   1.7.21 ``` #### slf4j 兼容非 slf4j 日志组件 在介绍解决方案前,先提一个概念——桥接 **什么是桥接呢** 假如你正在开发应用程序所调用的组件当中已经使用了 common-logging,这时你需要 jcl-over-slf4j.jar 把日志信息输出重定向到 slf4j-api,slf4j-api 再去调用 slf4j 实际依赖的日志组件。这个过程称为桥接。下图是官方的 slf4j 桥接策略图: ![slf4j桥接策略](http://oyz7npk35.bkt.clouddn.com//image/java/libs/log/slf4j-bind-strategy.png) 从图中应该可以看出,无论你的老项目中使用的是 common-logging 或是直接使用 log4j、java.util.logging,都可以使用对应的桥接 jar 包来解决兼容问题。 **slf4j 兼容 common-logging** ```xml org.slf4j jcl-over-slf4j 1.7.12 ``` **slf4j 兼容 log4j** ```xml org.slf4j log4j-over-slf4j 1.7.12 ``` **slf4j 兼容 java.util.logging** ```xml org.slf4j jul-to-slf4j 1.7.12 ``` #### spring 集成 slf4j 做 java web 开发,基本离不开 spring 框架。很遗憾,spring 使用的日志解决方案是 common-logging + log4j。 所以,你需要一个桥接 jar 包:_logback-ext-spring_。 ```xml 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 中即可。 ```xml commons-logging commons-logging 1.2 log4j log4j 1.2.17 ``` ### 使用 API #### slf4j 用法 使用 slf4j 的 API 很简单。使用`LoggerFactory`初始化一个`Logger`实例,然后调用 Logger 对应的打印等级函数就行了。 ```java import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class App { private static final Logger log = LoggerFactory.getLogger(App.class); public static void main(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 不支持`{}`替换参数,你只能选择拼接字符串这种方式了。 ```java import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class JclTest { private static final Log log = LogFactory.getLog(JclTest.class); public static void main(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"); } } ``` ## logback 配置 ### `` * 作用:`` 是 logback 配置文件的根元素。 * 要点 * 它有 ``、``、`` 三个子元素。

### `` * 作用:将记录日志的任务委托给名为 appender 的组件。 * 要点 * 可以配置零个或多个。 * 它有 ``、``、``、`` 四个子元素。 * 属性 * name:设置 appender 名称。 * class:设置具体的实例化类。 #### `` * 作用:设置日志文件路径。 #### `` * 作用:设置过滤器。 * 要点 * 可以配置零个或多个。 #### `` * 作用:设置 appender。 * 要点 * 可以配置零个或一个。 * 属性 * class:设置具体的实例化类。 #### `` * 作用:设置编码。 * 要点 * 可以配置零个或多个。 * 属性 * class:设置具体的实例化类。

### `` * 作用:设置 logger。 * 要点 * 可以配置零个或多个。 * 属性 * name * level:设置日志级别。不区分大小写。可选值:TRACE、DEBUG、INFO、WARN、ERROR、ALL、OFF。 * additivity:可选值:true 或 false。 #### `` * 作用:appender 引用。 * 要点 * 可以配置零个或多个。 ### `` * 作用:设置根 logger。 * 要点 * 只能配置一个。 * 除了 level,不支持任何属性。level 属性和 `` 中的相同。 * 有一个子元素 ``,与 `` 中的相同。 ### 完整的 logback.xml 参考示例 在下面的配置文件中,我为自己的项目代码(根目录:org.zp.notes.spring)设置了五种等级: TRACE、DEBUG、INFO、WARN、ERROR,优先级依次从低到高。 因为关注 spring 框架本身的一些信息,我增加了专门打印 spring WARN 及以上等级的日志。 ```xml %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 配置 ### 完整的 log4j.xml 参考示例 log4j 的配置文件一般有 xml 格式或 properties 格式。这里为了和 logback.xml 做个对比,就不介绍 properties 了,其实也没太大差别。 ```xml ``` ### logback 配置参数说明 logback 基本兼容 log4j 的配置,并提供更多的功能。 这里奉献一张本人整理的 logback 配置思维导图,高清无码。 ![logback配置](http://oyz7npk35.bkt.clouddn.com//image/java/libs/log/popular-logs-mind.png) ## 参考 * [slf4 官方文档](http://www.slf4j.org/manual.html) * [logback 官方文档](http://logback.qos.ch/) * [log4j 官方文档](http://logging.apache.org/log4j/1.2/) * [commons-logging 官方文档](http://commons.apache.org/proper/commons-logging/) * http://blog.csdn.net/yycdaizi/article/details/8276265