导读:随着互联网和大数据的蓬勃发展,分布式日志系统以及日志分析系统得到了广泛地应用。目前,几乎在所有应用程序中,都会用到各种各样的日志框架来记录程序的运行信息。鉴于此,工程师十分有必要熟悉主流的日志记录框架。

作者 | 书澜

来源 | 凌云时刻(微信号:linuxpk)

前言

本篇为《进阶之路:Java 日志框架全画传》系列下篇,将结合具体案例介绍日志使用示例及常见报错。

上篇解读了日志使用中需要遵循的规范及注意事项,今日进入推送的第三篇阅读,也是终篇。

日志使用示例及常见报错

承接前面两部份,本部份将介绍几种主流日志框架的使用示例和常见的报错。为了便于读者理解,文中的报错案例力求信息完整,并给出了测试代码,感兴趣的读者,可以通过示例快速实践。

  • 日志框架使用示例

· Log4j 使用示例

maven 依赖:

<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>

配置文件:log4j.properties

### 设置
log4j.rootLogger = debug,stdout,INFO
### 输出信息到控制台,测试的时候便于观察,实际应用中不配置 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 输出 INFO 级别以上的日志到指定文件
log4j.appender.INFO = org.apache.log4j.DailyRollingFileAppender
log4j.appender.INFO.File = ~/Code/logs/log4j.log
log4j.appender.INFO.Append = true
log4j.appender.INFO.Threshold = info
log4j.appender.INFO.layout = org.apache.log4j.PatternLayout
log4j.appender.INFO.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

测试代码:

public class Log4jTest {private static final Logger LOGGER = Logger.getLogger(Log4jTest.class);public static void main(String[] args) {LOGGER.info("log test");try {((Object) null).toString();} catch (Exception e) {LOGGER.info("exception info", e);}LOGGER.info("This is log4j. Thread=" + Thread.currentThread().getName());}
}

日志输出:

2019-10-31 21:05:36  [ main:0 ] - [ INFO ]  log test
2019-10-31 21:05:36  [ main:5 ] - [ INFO ]  exception info
java.lang.NullPointerExceptionat Log4jTest.main(Log4jTest.java:18)
2019-10-31 21:05:36  [ main:9 ] - [ INFO ]  This is log4j. Thread=main

· commons-logging 使用示例

本例中,使用 Commons-Logging (也称为 JCL) 作为日志门面提供统一的日志接口,Log4j 作为具体的日志实现。

maven 依赖:

<

配置文件:

1. commons-logging.properties

org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger

2. log4j.properties

### 设置
log4j.rootLogger = debug,stdout,INFO
### 输出信息到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 输出 INFO 级别以上的日志到指定文件
log4j.appender.INFO = org.apache.log4j.DailyRollingFileAppender
log4j.appender.INFO.File = ~/Code/logs/jcllog4j.log
log4j.appender.INFO.Append = true
log4j.appender.INFO.Threshold = info
log4j.appender.INFO.layout = org.apache.log4j.PatternLayout
log4j.appender.INFO.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

测试代码:

public class JclTest {private static final Log LOGGER = LogFactory.getLog(JclTest.class);public static void main(String[] args) {LOGGER.info("log test");try {((Object) null).toString();} catch (Exception e) {LOGGER.info("exception info", e);}LOGGER.info("This is jcl log. Thread=" + Thread.currentThread().getName());}
}

日志输出:

2019-10-31 21:30:42  [ main:0 ] - [ INFO ]  log test
2019-10-31 21:30:42  [ main:4 ] - [ INFO ]  exception info
java.lang.NullPointerExceptionat JclTest.main(JclTest.java:19)
2019-10-31 21:30:42  [ main:6 ] - [ INFO ]  This is jcl log. Thread=main

· slf4j 使用示例

本例中,使用 Slf4j 作为日志门面提供统一的日志接口,Logback 作为具体的日志实现。

maven 依赖:

<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.28</version>
</dependency>
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version>
</dependency>
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-core</artifactId><version>1.2.3</version>
</dependency>

配置文件:

logback.xml
<configuration debug="true" scan="true" scanPeriod="1 seconds"><contextName>logback</contextName><property name="app.name" value="~/Code"/><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>DEBUG</level></filter><encoder><pattern>%d [%thread] %-5level %logger{36} [%file : %line] - %msg%n</pattern></encoder></appender><appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${app.name}/logs/slf4jlogback.log</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${app.name}/logs/slf4jlogback.%d{yyyy-MM-dd.HH}.log.gz</fileNamePattern><maxHistory>60</maxHistory><totalSizeCap>20GB</totalSizeCap></rollingPolicy><triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"><maxFileSize>100MB</maxFileSize></triggeringPolicy><encoder><pattern>%d [%thread] %-5level %logger{36} [%file : %line] - %msg%n</pattern></encoder></appender><root level="info"><appender-ref ref="stdout"/><appender-ref ref="file"/></root>
</configuration>

测试代码:

public class Slf4jTest {private static final Logger LOGGER = LoggerFactory.getLogger(Slf4jTest.class);public static void main(String[] args) {LOGGER.info("log test");try {((Object) null).toString();} catch (Exception e) {LOGGER.info("exception info", e);}LOGGER.info("This is slf4jLogback log. Thread=" + Thread.currentThread().getName());}
}

日志输出:

2019-10-31 21:26:17,806 [main] INFO  Slf4jTest [Slf4jTest.java : 17] - log test
2019-10-31 21:26:17,811 [main] INFO  Slf4jTest [Slf4jTest.java : 22] - exception info
java.lang.NullPointerException: nullat Slf4jTest.main(Slf4jTest.java:19)
2019-10-31 21:26:17,811 [main] INFO  Slf4jTest [Slf4jTest.java : 24] - This is slf4jLogback log. Thread=main

  • 常见报错案例

· 找不到绑定器

如下图所示,应用使用的是 Slf4j 标准接口,目标日志框架为 Log4j,但是没有引入绑定器(slf4j-log4j12)。

maven 依赖:

<dependencies><!-- slf4j --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.28</version></dependency><!-- Log4j2 --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><!-- binder --><!--<dependency>--><!--<groupId>org.slf4j</groupId>--><!--<artifactId>slf4j-log4j12</artifactId>--><!--<version>1.7.28</version>--><!--</dependency>-->
</dependencies>

运行测试代码将会报错,提示加载绑定器失败,具体内容如下:

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.

· 配置了多个绑定器

如下图所示,应用使用的是 Slf4j 标准接口,目标日志框架为 Log4j,但是同时引入了两个日志绑定器。

存在问题的 maven 依赖如下所示:

<!-- slf4j -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.28</version>
</dependency>
<!-- Log4j2 -->
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
<!-- binder -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.28</version>
</dependency>
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.12.1</version>
</dependency>

这种情况下,将无法按照预期打印日志,应用会加载默认的日志配置,将日志打印到控制台,详细的错误信息如下:

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/Users/test/.m2/repository/org/slf4j/slf4j-log4j12/1.7.28/slf4j-log4j12-1.7.28.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/Users/test/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.12.1/log4j-slf4j-impl-2.12.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]

· 循环依赖

如下图,应用使用的是 Slf4j 标准接口,目标日志框架为 Log4j,但是同时引入了两个日志绑定器: log4j-over-slf4j 和 slf4j-log4j12,如此将会出现循环依赖。2

存在循环依赖问题的 maven 配置如下:

<!-- slf4j -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.28</version>
</dependency>
<!-- Log4j2 -->
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
<!-- binder -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.28</version>
</dependency>
<dependency><groupId>org.slf4j</groupId><artifactId>log4j-over-slf4j</artifactId><version>1.7.28</version>
</dependency>

出现循环依赖问题时,日志系统将无法正常启动,进而导致应用无法启动,详细的错误信息如下:

SLF4J: Detected both log4j-over-slf4j.jar AND bound slf4j-log4j12.jar on the class path, preempting StackOverflowError.
SLF4J: See also http://www.slf4j.org/codes.html#log4jDelegationLoop for more details.
Exception in thread "main" java.lang.ExceptionInInitializerErrorat org.slf4j.impl.StaticLoggerBinder.<init>(StaticLoggerBinder.java:72)at org.slf4j.impl.StaticLoggerBinder.<clinit>(StaticLoggerBinder.java:45)at org.slf4j.LoggerFactory.bind(LoggerFactory.java:150)at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:124)at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:412)at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:357)at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:383)at Log4jTest.<clinit>(Log4jTest.java:13)
Caused by: java.lang.IllegalStateException: Detected both log4j-over-slf4j.jar AND bound slf4j-log4j12.jar on the class path, preempting StackOverflowError. See also http://www.slf4j.org/codes.html#log4jDelegationLoop for more details.at org.slf4j.impl.Log4jLoggerFactory.<clinit>(Log4jLoggerFactory.java:54)... 8 more

java log4j logback jcl_进阶之路:Java 日志框架全画传(下)相关推荐

  1. 获取日志的等级_进阶之路:Java 日志框架全画传(中)

    导读:随着互联网和大数据的蓬勃发展,分布式日志系统以及日志分析系统得到了广泛地应用.目前,几乎在所有应用程序中,都会用到各种各样的日志框架来记录程序的运行信息.鉴于此,工程师十分有必要熟悉主流的日志记 ...

  2. java log4j logback jcl_知识总结-Java日志框架Log4j、Log4j2、logback、slf4j、简介

    功能简介 上一篇介绍了为什么打印日志.什么时候打印日志以及怎么打印日志.本篇介绍下在项目开发中常见的日志组件以及关系. 先看一张图 接口:将所有日志实现适配到了一起,用统一的接口调用. 实现:目前主流 ...

  3. java log4j logback jcl_内部分享:如何解决Java日志框架冲突问题。

    来源:https://urlify.cn/E7zEfq # 前言 Java 有很多的日志框架可以选择,当同一个项目中出现多种日志框架时就很容易出现日志框架冲突的问题,导致日志打印不出来.本文将以一次典 ...

  4. java log4j logback jcl_Java 日志二三事

    前言 Java 拥有功能和性能都非常强大的日志库,但另一方面,Java 日志库依赖看起来丰富的让人眼花缭乱.相信大家或多或少都有这样的疑问,Log4j,SLF4J,Logback,Log4j2 这些日 ...

  5. JUC进阶之路-Java的内存模型JMM

    本文源自转载:JUC进阶之路-Java的内存模型JMM 目录 一.大厂常见的JMM面试题 二.什么是JAVA内存模型JMM(Java Memory Model) 三.JMM的三大特性 3.1 可见性 ...

  6. java thread等特,进阶之路|奇妙的Thread之旅

    学习导图: 一.为什么要学习Thread? 在Android中,几乎完全采用了Java中的线程机制.线程是最小的调度单位,在很多情况下为了使APP更加流程地运行,我们不可能将很多事情都放在主线程上执行 ...

  7. Java 学习总结(187)—— 轻量级开源日志框架 tinylog 简介

    前言 前段时间,日志框架各种漏洞爆雷,包括:Log4j 1.x, Log4j 2.x, Logback 等都有爆雷,几乎是团灭.Log4j, Logback 都是主流的日志框架,功能也非常强大,不仅仅 ...

  8. 《Java Web开发实战》Java工程师推荐的进阶之路

    <Java Web开发实战>一书更加趋于实战性.此教材由浅入深.循序渐进,在语法阐述时尽量避免术语和公式,使初学者能够快速入门,全面掌握实战技能.它既可以作为高等院校本.专科计算机相关专业 ...

  9. java自适应table_【进阶之路】包罗万象——JAVA中的锁

    导言 大家好,我是练习java两年半时间的南橘,下面是我的微信,需要之前的导图或者想互相交流经验的小伙伴可以一起互相交流哦. 在Java中,我们能接触到各种各样的锁,而每种锁因其特性的不同,在不同的的 ...

最新文章

  1. Java并发编程题库
  2. /dev/null 位桶
  3. 初始化资源管理器 winform
  4. ASP.NET Form Authentication安全漏洞及对策
  5. 框架源码专题:Spring声明式事务Transactional的原理
  6. 游戏服务器维护启动需要多久,游戏服务器开机需要多长时间
  7. 【codevs1867】【Tyvj3508】【BZOJ1041】圆上的整点,数学乱搞
  8. 基于matlab的车牌定位算法设计与实现,matlab车牌定位系统设计(源码+文档)
  9. 给Lisp程序员的Python简介
  10. 一个非常有用的辅助类 -- 阈值类的实现
  11. 【FlexSim2019】自学笔记:一个实例看何为A连接?何为S连接?其意义的深入探讨
  12. 05月08日 学习列表
  13. 安卓开发之ListView优化方案
  14. 如何查看文件md5值
  15. 测试opencl软件,我该如何测试OpenCL的可兼容性?
  16. LSH(Locality Sensitive Hashing)原理与实现
  17. vue 父组件与子组件直接的相互传值(愚见)
  18. android自定义相机打开闪光灯,Android 照相机(闪光灯,切换摄像头)
  19. 【无监督】自编码器(Autoencoder)
  20. 【Microsoft Azure 的1024种玩法】六十.通过Azure Virtual Machines快速搭建个人Ghost博客系统

热门文章

  1. 最新公布,“中国开发者大调查”第四批中奖名单来啦
  2. 邹欣对话图灵奖得主Jeffrey Ullman:数据库不会进入周期性的坏循环|《新程序员》...
  3. 任正非就注册姚安娜商标道歉;人人影视字幕组因盗版被查;JIRA、Confluence 等产品本月停售本地化版本 | 极客头条...
  4. 按照这个步骤来刷题,迷茫的你两个月亦能成为王者
  5. 第十一届中国开源黑客松+中国程序员节重磅来袭,这里将有你不能错过的精彩。...
  6. B 站 Up 主自制秃头生成器,圆你秃头梦想可好?
  7. 微软为一人收购一公司?破解索尼程序、写黑客小说,看他彪悍的程序人生!...
  8. 程序员又迎一利器,联想 LeapIOT 工业互联网平台大曝光
  9. 富士康员工涉嫌盗卖 iPhone 零件遭调查;风行网接手暴风;IntelliJ IDEA 2019.3.1 发布| 极客头条...
  10. 高级工程师究竟比你“高”在哪?