注意:本 Spring Boot 系列文章基于 Spring Boot 版本 v2.1.1.RELEASE 进行学习分析,版本不同可能会有细微差别。

前言

Spring 框架选择使用了 JCL 作为默认日志输出。而 Spring Boot 默认选择了 SLF4J 结合 LogBack。那我们在项目中该使用哪种日志框架呢?在对于不同的第三方 jar 使用了不同的日志框架的时候,我们该怎么处理呢?

1. 日志框架介绍

日志对于应用程序的重要性不言而喻,不管是记录运行情况还是追踪线上问题,都离不开对日志的分析,在 Java 领域里存在着多种日志框架,如 JUL, Log4j, Log4j2, Commons Loggin, Slf4j, Logback 等。关于 Log4j, Log4j2 和 Slf4j 直接的故事这里不做介绍,有兴趣可以自行百度。

2. SLF4 的使用

在开发的时候不应该直接使用日志实现类,应该使用日志的抽象层。具体参考 SLF4J 官方

下图是 SLF4J 结合各种日志框架的官方示例,从图中可以清晰的看出 SLF4J API 永远作为日志的门面,直接应用与应用程序中。

同时 SLF4 官方给出了简单示例。

  1. import org.slf4j.Logger;
  2. import org.slf4j.LoggerFactory;
  3. public class HelloWorld {
  4. public static void main(String[] args) {
  5. Logger logger = LoggerFactory.getLogger(HelloWorld.class);
  6. logger.info("Hello World");
  7. }
  8. }

需要注意的是,要为系统导入 SLF4J 的 jar 和 日志框架的实现 jar. 由于每一个日志的实现框架都有自己的配置文件,所以在使用 SLF4 之后,配置文件还是要使用实现日志框架的配置文件。

3. 统一日志框架的使用

一般情况下,在项目中存在着各种不同的第三方 jar ,且它们的日志选择也可能不尽相同,显然这样是不利于我们使用的,那么如果我们想为项目设置统一的日志框架该怎么办呢?

SLF4J 官方,也给了我们参考的例子。

从图中我们得到一种统一日志框架使用的方式,可以使用一种和要替换的日志框架类完全一样的 jar 进行替换,这样不至于原来的第三方 jar 报错,而这个替换的 jar 其实使用了 SLF4J API. 这样项目中的日志就都可以通过 SLF4J API 结合自己选择的框架进行日志输出。

统一日志框架使用步骤归纳如下

  1. 排除系统中的其他日志框架。
  2. 使用中间包替换要替换的日志框架。
  3. 导入我们选择的 SLF4J 实现。

4. Spring Boot 的日志关系

4.1. 排除其他日志框架

根据上面总结的要统一日志框架的使用,第一步要排除其他的日志框架,在 Spring Boot 的 Maven 依赖里可以清楚的看到 Spring Boot 排除了其他日志框架。



我们自行排除依赖时也只需要按照图中的方式就好了。

4.2. 统一框架引入替换包

其实 Spring Boot 也是使用了 SLF4J+logback 的日志框架组合,查看 Spring Boot 项目的 Maven 依赖关系可以看到 Spring Boot 的核心启动器 spring-boot-starter 引入了 spring-boot-starter-logging.

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-logging</artifactId>
  4. <version>2.1.1.RELEASE</version>
  5. <scope>compile</scope>
  6. </dependency>

而 spring-boot-starter-logging 的 Maven 依赖主要引入了 logback-classic (包含了日志框架 Logback 的实现),log4j-to-slf4j (在 log4j 日志框架作者开发此框架的时候还没有想到使用日志抽象层进行开发,因此出现了 log4j 向 slf4j 转换的工具),jul-to-slf4j ( Java 自带的日志框架转换为 slf4j).

  1. <dependencies>
  2. <dependency>
  3. <groupId>ch.qos.logback</groupId>
  4. <artifactId>logback-classic</artifactId>
  5. <version>1.2.3</version>
  6. <scope>compile</scope>
  7. </dependency>
  8. <dependency>
  9. <groupId>org.apache.logging.log4j</groupId>
  10. <artifactId>log4j-to-slf4j</artifactId>
  11. <version>2.11.1</version>
  12. <scope>compile</scope>
  13. </dependency>
  14. <dependency>
  15. <groupId>org.slf4j</groupId>
  16. <artifactId>jul-to-slf4j</artifactId>
  17. <version>1.7.25</version>
  18. <scope>compile</scope>
  19. </dependency>
  20. </dependencies>

从上面的分析,Spring Boot 对日志框架的使用已经是清晰明了了,我们使用 IDEA 工具查看 Maven 依赖关系,可以清晰的看到日志框架的引用。如果没有 IDEA 工具,也可以使用 Maven 命令查看依赖关系。

  1. mvn dependency:tree

由此可见,Spring Boot 可以自动的适配日志框架,而且底层使用 SLF4 + LogBack 记录日志,如果我们自行引入其他框架,需要排除其日志框架。

5. Spring Boot 的日志使用

5.1. 日志级别和格式

从上面的分析,发现 Spring Boot 默认已经使用了 SLF4J + LogBack . 所以我们在不进行任何额外操作的情况下就可以使用 SLF4J + Logback 进行日志输出。

编写 Java 测试类进行测试。

  1. import org.junit.Test;
  2. import org.junit.runner.RunWith;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.boot.test.context.SpringBootTest;
  6. import org.springframework.test.context.junit4.SpringRunner;
  7. /**
  8. * <p>
  9. * 测试日志输出,
  10. * SLF4J 日志级别从小到大trace,debug,info,warn,error
  11. *
  12. * @Author niujinpeng
  13. * @Date 2018/12/11 21:12
  14. */
  15. @RunWith(SpringRunner.class)
  16. @SpringBootTest
  17. public class LogbackTest {
  18. Logger logger = LoggerFactory.getLogger(getClass());
  19. @Test
  20. public void testLog() {
  21. logger.trace("Trace 日志...");
  22. logger.debug("Debug 日志...");
  23. logger.info("Info 日志...");
  24. logger.warn("Warn 日志...");
  25. logger.error("Error 日志...");
  26. }
  27. }

已知日志级别从小到大为 trace < debug < info < warn < error . 运行得到输出如下。由此可见 Spring Boot 默认日志级别为 INFO.

  1. 2018-12-11 23:02:58.028 [main] INFO n.c.boot.LogbackTest - Info 日志...
  2. 2018-12-11 23:02:58.029 [main] WARN n.c.boot.LogbackTest - Warn 日志...
  3. 2018-12-11 23:02:58.029 [main] ERROR n.c.boot.LogbackTest - Error 日志...

从上面的日志结合 Logback 日志格式可以知道 Spring Boot 默认日志格式是。

  1. %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
  2. # %d{yyyy-MM-dd HH:mm:ss.SSS} 时间
  3. # %thread 线程名称
  4. # %-5level 日志级别从左显示5个字符宽度
  5. # %logger{50} 类名
  6. # %msg%n 日志信息加换行

至于为什么 Spring Boot 的默认日志输出格式是这样?



我们可以在 Spring Boot 的源码里找到答案。

5.2 自定义日志输出

可以直接在配置文件编写日志相关配置。

  1. # 日志配置
  2. # 指定具体包的日志级别
  3. logging.level.net.codingme=debug
  4. # 控制台和日志文件输出格式
  5. logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
  6. logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
  7. # 日志文件大小
  8. logging.file.max-size=10MB
  9. # 保留的日志时间
  10. logging.file.max-history=10
  11. # 日志输出路径,默认文件spring.log
  12. logging.path=systemlog
  13. #logging.file=log.log

关于日志的输出路径,可以使用 logging.file 或者 logging.path 进行定义,两者存在关系如下表。

logging.file logging.path 例子 描述
(没有) (没有) 仅控制台记录。
具体文件 (没有) my.log 写入指定的日志文件,名称可以是精确位置或相对于当前目录。
(没有) 具体目录 /var/log 写入spring.log指定的目录,名称可以是精确位置或相对于当前目录。

6. 替换日志框架

因为 Log4j 日志框架已经年久失修,原作者都觉得写的不好,所以下面演示替换日志框架为 Log4j2 的方式。根据官网我们 Log4j2 与 logging 需要二选一,因此修改 pom如下。

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. <exclusions>
  5. <exclusion>
  6. <artifactId>spring-boot-starter-logging</artifactId>
  7. <groupId>org.springframework.boot</groupId>
  8. </exclusion>
  9. </exclusions>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.springframework.boot</groupId>
  13. <artifactId>spring-boot-starter-log4j2</artifactId>
  14. </dependency>

文章代码已经上传到 GitHub Spring Boot 日志系统

<完>

本文原发于个人博客:https://www.codingme.net 转载请注明出处

Springboot 系列(四)Spring Boot 日志框架的更多相关文章

  1. SpringBoot系列之切换log4j日志框架

    SpringBoot系列之使用切换log4j日志框架 ok,在pom文件右键->Diagrams->show Dependencies....,如图,找到spring-boot-start ...

  2. 【串线篇】spring boot日志框架

    一.日志框架 小张:开发一个大型系统: 1.System.out.println(""):将关键数据打印在控制台:去掉?写在一个文件? 2.框架来记录系统的一些运行时信息:日志框架 ...

  3. SpringBoot系列:Spring Boot使用模板引擎FreeMarker

    一.Java模板引擎 模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档. 在jav ...

  4. SpringBoot系列:Spring Boot使用模板引擎Thymeleaf

    一.Java模板引擎 模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档. 在jav ...

  5. SpringBoot系列:Spring Boot使用模板引擎JSP

    一.Java模板引擎 模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档. 在jav ...

  6. SpringBoot系列:Spring Boot集成Spring Cache,使用EhCache

    前面的章节,讲解了Spring Boot集成Spring Cache,Spring Cache已经完成了多种Cache的实现,包括EhCache.RedisCache.ConcurrentMapCac ...

  7. SpringBoot系列:Spring Boot集成Spring Cache,使用RedisCache

    前面的章节,讲解了Spring Boot集成Spring Cache,Spring Cache已经完成了多种Cache的实现,包括EhCache.RedisCache.ConcurrentMapCac ...

  8. Spring Boot系列(四) Spring Boot 之验证

    这节没有高深的东西, 但有一些学习思路值得借鉴. JSR 303 (Bean Validation) Maven依赖 <dependency> <groupId>org.spr ...

  9. SpringBoot系列:Spring Boot集成定时任务Quartz

    一.关于Quartz Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用.在java企业级应用中,Q ...

随机推荐

  1. 遥远的国度 bzoj3083

    分析: 这个题一看就是裸的树剖... 唯一值得考虑的就是它的根一直在变化,我们可以这样想,如果假根在这个点的子树外,那么直接将这个点的子树作为答案区间,如果在子树内,则相对复杂,我们假设son为roo ...

  2. 使用NOOBS给树莓派安装系统Raspbian

    使用NOOBS给树莓派安装系统Raspbian --英文原版教程:https://www.raspberrypi.org/learning/software-guide/quickstart/ 1.原 ...

  3. Bug的严重等级和优先级别与分类

    一. Bug的严重等级定义: 1. Blocker 即系统无法执行.崩溃或严重资源不足.应用模块无法启动或异常退出.无法测试.造成系统不稳定. 严重花屏 内存泄漏 用户数据丢失或破坏 系统崩溃/死机/ ...

  4. Python集成开发环境

    目录 为什么用IDE(了解) Pycharm(掌握) Jupyter(掌握) 为什么用IDE(了解) 到现在为止,我们也是写过代码的人啦,但你有没有发现,每次写代码要新建文件.写完保存时还要选择存放地 ...

  5. cannot be cast to java.lang.Comparable

    Exception in thread "main" java.lang.ClassCastException: com.myradio.People cannot be cast ...

  6. Python-炫酷二维码

    一.环境 首先是安装python环境,如果没有安装python环境看此处 二.myqr     myqr 其实是一个 python 的脚本,可以生产二维码图片,作者也对python脚本进行了打包,在 ...

  7. asp.net core系列 54 IS4用客户端凭据保护API

    一. 概述 本篇开始进入IS4实战学习,从第一个示例开始,该示例是 “使用客户端凭据保护API”,这是使用IdentityServer保护api的最基本场景.该示例涉及到三个项目包括:Identity ...

  8. Linux三剑客-grep || awk || sed

    grep是一个强大的文本搜索工具 命令格式: grep [option] pattren file -a  将二进制文档以文本方式处理 -c  计算找到的符合行的次数 -i  忽略大小写 -n  顺便 ...

  9. JS异步操作新体验之 async函数

    1.初识 async 函数   ES6中提供了两个很好的解决异步操作的方案 Promise 和 Generator,ES2017标准中引入的 async 函数就是建立在 Promise 和 Gener ...

  10. @Controller和@RestController源码解析

    2018年不知不觉已经走到了尾声,你还在为分不清@Controller和@Restcontroller而烦恼吗?这篇博文从源码层面分析这两个注解,值得一读. 首先贴一张源码的图,对比一下,左边是@Co ...