凌云时刻 · 技术

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

作者 | 书澜

来源 | 凌云时刻(微信号: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.ConsoleAppenderlog4j.appender.stdout.Target = System.outlog4j.appender.stdout.layout = org.apache.log4j.PatternLayoutlog4j.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.DailyRollingFileAppenderlog4j.appender.INFO.File = ~/Code/logs/log4j.loglog4j.appender.INFO.Append = truelog4j.appender.INFO.Threshold = infolog4j.appender.INFO.layout = org.apache.log4j.PatternLayoutlog4j.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 依赖:

<dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version>
</dependency>
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
  • 配置文件

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());}
}
  • 日志输出:

019-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,如此将会出现循环依赖。

存在循环依赖问题的 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

END

往期精彩文章回顾

进阶之路:Java 日志框架全画传(中)

进阶之路:Java 日志框架全画传(上)

一款云迁移产品的成长史

情感分析技术:让智能客服更懂人类情感

电子书免费下载!1天上手的蓝牙Mesh应用解决方案来袭

语雀的技术架构演进之路

下一代异步 IO 技术解密

io_uring 新异步 IO 机制,性能提升超 150%,堪比 SPDK

如何写好代码?

如何解决大规模高性能存储可靠性问题?

长按扫描二维码关注凌云时刻

每日收获前沿技术与科技洞见

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

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

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

  2. java log4j logback jcl_进阶之路:Java 日志框架全画传(下)

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

  3. 多种java 日志框架【超详细图文】

    一.目标 日志的作用和目的 日志的框架 JUL的使用 LOG4J的使用 JCL的使用 二.日志的概念 2.1 日志文件 日志文件是用于记录系统操作事件的文件集合,可分为事件日志和消息日志.具有处理历史 ...

  4. Java日志框架——Logback

    Java日志框架--Logback 简介 1.1 Logback概述 1.2 日志级别 1.3 组件 1.4 配置文件 1.5 日志输出格式 项目中应用步骤 2.1 依赖 2.2 日志输出到控制台 2 ...

  5. java日志框架JUL、JCL、Slf4j、Log4j、Log4j2、Logback 一网打尽

    为什么程序需要记录日志 我们不可能实时的24小时对系统进行人工监控,那么如果程序出现异常错误时要如何排查呢?并且系统在运行时做了哪些事情我们又从何得知呢?这个时候日志这个概念就出现了,日志的出现对系统 ...

  6. Java日志框架 -- 日志框架介绍、日志门面技术、JUL日志(JUL架构、JUL入门示例、JUL日志级别、JUL日志的配置文件)

    1. 日志的概念 日志文件是用于记录系统操作事件的文件集合,可分为事件日志和消息日志.具有处理历史数据.诊断问题的追踪以及理解系统的活动等重要作用. 2. Java日志框架 问题: 控制日志输出的内容 ...

  7. Java日志框架学习--JUL和Log4j--上

    Java日志框架学习--JUL和Log4j--上 引言 日志框架 市面流行的日志框架 日志门面和日志框架的区别 JUL JUL简介 JUL组件介绍 实际使用 Logger之间的父子关系 默认配置文件位 ...

  8. 最牛逼的 Java 日志框架

    Logback 算是JAVA 里一个老牌的日志框架,从06年开始第一个版本,迭代至今也十几年了.不过logback最近一个稳定版本还停留在 2017 年,好几年都没有更新:logback的兄弟 slf ...

  9. 最牛逼的 Java 日志框架,性能无敌,横扫所有对手

    Logback 算是JAVA 里一个老牌的日志框架,从06年开始第一个版本,迭代至今也十几年了.不过logback最近一个稳定版本还停留在 2017 年,好几年都没有更新:logback的兄弟 slf ...

  10. 最牛逼的 Java 日志框架,还不学习。。。

    最牛逼的 Java 日志框架,性能无敌,横扫所有对手- Logback 算是JAVA 里一个老牌的日志框架,从06年开始第一个版本,迭代至今也十几年了.不过logback最近一个稳定版本还停留在 20 ...

最新文章

  1. android应用内存分析,Android应用程序内存分析-Memory Analysis for Android Applications
  2. python如何在手机上下载模块-Python 下载文件的 11 种方式
  3. GoldenGate 配置extract,replicat进程自启动
  4. sparkstreaming监听hdfs目录如何终止_Spark笔试题:Spark Streaming 反压机制
  5. 南柯服务器压力,性能测试的数据解释及分析 - Mr.南柯 - 51Testing软件测试网 51Testing软件测试网-软件测试人的精神家园...
  6. centos6.4 卸载mysql_彻底删除MYSQL-CENTOS
  7. 使用pip安装virtualenv时出现问题
  8. 鸿蒙OS代码正式开源!!!
  9. UITableViewCell高度自适应变化
  10. Win10安装Eclipse教程
  11. adb shell 操作
  12. OverFeat 阅读笔记
  13. 时间管理——帕累托法则(二八定律)
  14. 采用python语言对csv文件写入、最可能采用的字符串方法_2020尔雅无人机原理与构造答案章节答案...
  15. vue使用echarts图表渲染异常本地正常,线上时有时无的渲染
  16. 关注智能眼镜:tooz Devkit 20
  17. 【课程全解】-UML软件建模设计
  18. Esp32 TCA9555 基于Arduino基于 microByte
  19. 微信小程序 - 获取用户信息
  20. django传值给模板, 再用JS接收并进行操作

热门文章

  1. 获取datagrid中编辑列combobox的value值与text值
  2. jsp----Session
  3. Maya Mesh Relaxation Deformer
  4. Python学习---Python数据类型1206
  5. 构建手机apk的过程
  6. Prism初研究之使用Prism 5.0开发模块化应用
  7. Linux学习私人笔记-Vim
  8. WAP开发环境的设置[IIS, APACHE, HTTPD]
  9. unity 将虚拟相机的视角局部放大,显示在一个平面上
  10. Atitit layout art 布局的艺术目录1. SpringLayout 类 弹簧布局管理器 12. BoxLayout( html默认布局) 11.SpringLayout