β

log(二) - java中log体系再讨论

Never's Blog 549 阅读

虽然之前已经介绍过Java中的log,但是目前使用的过程中依然傻傻分不清,决定再次整理和介绍一下。

各种log框架

实际项目中我们经常可以看到log4j、logback、slf4j等框架的身影,对于这些乱七八糟的log框架大致可以分为两个种类:

日志框架 :jdk自带的logging(jul),log4j1、log4j2、logback

用于实现日志统一的框架 : apache的commons-logging(jcl)、slf4j

log4j1和log4j2

log4j2与log4j1发生了很大的变化,不兼容。log4j1仅仅作为一个实际的日志框架,slf4j、commons-logging作为门面,统一各种日志框架的混乱格局,现在log4j2也想跳出来充当门面了,也想统一大家了。

log4j2分成2个部分:

  1. log4j-api: 作为日志接口层,用于统一底层日志系统
  2. log4j-core : 作为上述日志接口的实现,是一个实际的日志框架

各种jar包总结

log4j1 :

  1. log4j:log4j1的全部内容

log4j2 :

  1. log4j-api:log4j2定义的API
  2. log4j-core:log4j2上述API的实现

logback :

  1. logback-core:logback的核心包
  2. logback-classic:logback实现了slf4j的API

commons-logging :

  1. commons-logging:commons-logging的原生全部内容
  2. log4j-jcl:commons-logging到log4j2的桥梁
  3. jcl-over-slf4j:commons-logging到slf4j的桥梁

slf4j转向某个实际的日志框架 :

场景介绍:如 使用slf4j的API进行编程,底层想使用log4j1来进行实际的日志输出,这就是slf4j-log4j12干的事。

  1. slf4j-jdk14:slf4j到jdk-logging的桥梁
  2. slf4j-log4j12:slf4j到log4j1的桥梁
  3. log4j-slf4j-impl:slf4j到log4j2的桥梁
  4. logback-classic:slf4j到logback的桥梁
  5. slf4j-jcl:slf4j到commons-logging的桥梁

某个实际的日志框架转向slf4j

场景介绍:如 使用log4j1的API进行编程,但是想最终通过logback来进行输出,所以就需要先将log4j1的日志输出转交给slf4j来输出,slf4j再交给logback来输出。将log4j1的输出转给slf4j,这就是log4j-over-slf4j做的事。这一部分主要用来进行实际的日志框架之间的切换。

  1. jul-to-slf4j:jdk-logging到slf4j的桥梁
  2. log4j-over-slf4j:log4j1到slf4j的桥梁
  3. jcl-over-slf4j:commons-logging到slf4j的桥梁

jcl与日志框架的集成

private static Log logger=LogFactory.getLog(Test.class);

jul

需要jar包

  1. commons-logging

log4j1

需要jar包

  1. commons-logging
  2. log4j

log4j2

需要jar包

  1. commons-logging
  2. log4j-api (log4j2的API包)
  3. log4j-core (log4j2的API实现包)
  4. log4j-jcl (log4j2与commons-logging的集成包)

logback

需要jar包

  1. jcl-over-slf4j (替代了commons-logging)
  2. slf4j-api
  3. logback-core
  4. logback-classic

logback本身的使用其实就和slf4j绑定了起来,现在要想指定commons-logging的底层log实现是logback,则需要2步走

  1. 先将commons-logging底层的log实现转向slf4j (jcl-over-slf4j干的事)
  2. 再根据slf4j的选择底层日志原理,我们使之选择上logback

slf4j与日志框架的集成

private static Logger logger=LoggerFactory.getLogger(Test.class);

jul

需要jar包

  1. slf4j-api
  2. slf4j-jdk14

log4j1

需要jar包

  1. slf4j-api
  2. slf4j-log4j12
  3. log4j

log4j2

需要jar包

  1. slf4j-api
  2. log4j-api
  3. log4j-core
  4. log4j-slf4j-impl (用于log4j2与slf4j集成)

logback

需要jar包

  1. slf4j-api
  2. logback-core
  3. logback-classic(已含有对slf4j的集成包)

总结

由上面我们可以发现一个完整的Log日志主要包括如下三个部分:

  1. 接口:sfl4j-api-xxx.jar
  2. 实现,也就是具体的日志框架:log4-xxx.jar、logback等
  3. 适配层:slf4j-log4j12-xxx.jar

问题

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

如果启动应用/程序的时候,报这样的错。那说明上面提到的sfl4j-log4j12没有依赖。需要在pom.xml显式的引入。

日志最佳实践

  1. 检查日志是否可以被记录

     if (LOGGER.isDebugEnabled()) { 
            LOGGER.debug("This is a message."); 
        }
    作用在于避免了构造日志记录消息所带来的开销。日志消息中通常包含与当前上下文相关的信息。为了获取这些信息并构造相应的消息文本,不可避免会产生额外的开销。因此在记录 INFO、DEBUG 和 TRACE 级别的日志时,首先进行相应的检查是一个好的实践。而 WARN 及其以上级别的日志则一般不需要进行检查。
    
  2. 日志中包含充分的信息。保证可读性,需记录现场信息,如当前处理id等

  3. 绝不要打印没有用的日志,防止无用日志淹没重要信息
  4. 日志格式要统一规范
  5. 用log.error表示系统级错误(不可预测);用log.warn表示应用级错误(可预测);服务初始化或结束用log.info;用log.warn(“”,e)替代e.printstack

参考

  1. jdk-logging、log4j、logback日志介绍及原理
  2. java日志系统指南
  3. Java 日志管理最佳实践
  4. 王健:最佳日志实践

虽然之前已经介绍过Java中的log,但是目前使用的过程中依然傻傻分不清,决定再次整理和介绍一下。

作者:Never's Blog
原文地址:log(二) - java中log体系再讨论, 感谢原作者分享。