市面上的日志框架

日志抽象层 日志实现
JCL(Jakarta Commons Logging)、SLF4J(Simple Logging Facade For Java)、JBoss-Logging Log4j、JUL(java.util.logging)、Log4j2、Logback

日志抽象层

JBoss-Logging 不适合平常开发使用。JCL 最后一次更新版本时间为 2014 年,有些过时。所以 SpringBoot 选中的日志抽象层为 SLF4J。

日志实现

日志实现 LogBack、Log4j 和抽象层 SLF4J 的作者是同一个人,且 LogBack 是后期针对 Log4j 的升级版,而 Log4j2 是 Apache 旗下开发的日志框架。所以 SpringBoot 的日志实现使用的是 Logback。

SLF4J使用

编码

导入 slf4j 和 logback 的依赖,使用如下。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HelloWorld {
  public static void main(String[] args) {
    Logger logger = LoggerFactory.getLogger(HelloWorld.class);
    logger.info("Hello World");
  }
}

原理图

统一使用SLF4J

如何让系统中所有的日志都统一到 sfl4j?

  1. 将系统中其它日志框架排除。
  2. 用中间包替换原有的日志框架。
  3. 导入 sl4j 的其它实现。

SpringBoot日志关系

我们已经知道一个基本的 SpringBoot  web 项目会包含如下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

而在 spring-boot-starter-web 依赖又依赖于 spring-boot-stater , spring-boot-stater 就有日志相关依赖,如下:

总结:

  1. SpringBoot 底层也是使用 slf4j+logback 的方式进行日志记录。
  2. SpringBoot 使用中间包将其它的日志包都间接替换成了 slf4j,而 slf4j 的实现为 logback,所以 call 其它日志包 api 的时候实际上调用的是 logback,统一了日志实现。
  3. 如果我们要引入其它框架,一定要把这个框架的默认日志依赖排除。

SpringBoot日志使用

默认配置

日志级别

现有如下示例:

package com.springboot.logging;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class LoggingApplicationTests {

    @Test
    public void test() {
        Logger logger = LoggerFactory.getLogger(this.getClass());
     // 如下日志级别由低到高
     // 指定一个日志级别,就会在指定的级别之后的高级别生效
        logger.trace("trace info");
        logger.debug("debug info");
        logger.info("info info");
        logger.warn("warn info");
        logger.error("error info");
    }
}

运行该测试代码,输出如下:

2018-03-16 17:08:34.913  INFO 16228 --- [           main] c.s.logging.LoggingApplicationTests      : info info
2018-03-16 17:08:34.913  WARN 16228 --- [           main] c.s.logging.LoggingApplicationTests      : warn info
2018-03-16 17:08:34.913 ERROR 16228 --- [           main] c.s.logging.LoggingApplicationTests      : error info

得出结论,SpringBoot 程序中我们使用的日志输出默认是 info 级别。

我们可以通过配置文件修改指定包下的日志输出级别,例:

logging.level.com.springboot.logging=trace  # 指定 com.springboot.logging 包下的日志输出级别为 trace

此时运行上面测试程序,输出内容为:

2018-03-16 17:13:06.451 TRACE 2836 --- [           main] c.s.logging.LoggingApplicationTests      : trace info
2018-03-16 17:13:06.451 DEBUG 2836 --- [           main] c.s.logging.LoggingApplicationTests      : debug info
2018-03-16 17:13:06.452  INFO 2836 --- [           main] c.s.logging.LoggingApplicationTests      : info info
2018-03-16 17:13:06.452  WARN 2836 --- [           main] c.s.logging.LoggingApplicationTests      : warn info
2018-03-16 17:13:06.452 ERROR 2836 --- [           main] c.s.logging.LoggingApplicationTests      : error info

如果直接指定整个项目日志输出级别,那么只需要把包路径位置替换为 root ,如下:

logging.level.root=trace

输出到文件

日志不仅可输出到控制台,还可以配置输出到指定文件,如下:

logging.file=springboot.log

此时项目中的日志就会输出到项目根路径下的 springboot.log 文件中。

上面这种方式是使用相对项目路径,也可以使用完整的绝对路径,如下:

logging.file=D://springboot.log

也可以只指定日志存放目录:

logging.path=/springboot/log

此时就会在项目所在磁盘的根目录的 /springboot/log 文件夹下生成一个 spring.log 文件。

输出格式

我们可以改变日志的输出格式,比如在配置文件中修改在控制台的日志输出格式:

logging.path=/log
# 控制台日志输出格式
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} ---> %msg%n
# 文件中日志输出格式
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} ---> %msg%n

# %d : 日期时间
# %thread : 线程名
# %-5level : 级别,从左显示 5 个字符宽度
# %logger{50} : logger 名称最长为 50 个字符,否则按照句点分割
# %msg : 日志消息
# %n : 换行符

此时运行上面测试程序,输出结果如下:

2019-03-16 17:41:23.432 [main] INFO  com.springboot.logging.LoggingApplicationTests ---> Started LoggingApplicationTests in 2.355 seconds (JVM running for 3.052)
2019-03-16 17:41:23.486 [main] INFO  com.springboot.logging.LoggingApplicationTests ---> info info
2019-03-16 17:41:23.486 [main] WARN  com.springboot.logging.LoggingApplicationTests ---> warn info
2019-03-16 17:41:23.486 [main] ERROR com.springboot.logging.LoggingApplicationTests ---> error info

指定配置文件

要使用自定义的日志配置文件,只需要在类路径下放上对应日志框架自己的配置文件即可,SpringBoot 就不使用它的默认配置了。而对应日志框架的配置文件命名也是有限制的,如下:

日志框架 可使用配置文件名
Logback logback-spring.xml、logback-spring.groovy、logback.xml、logback.groovy
log4j2 log4j2-spring.xml、log4j2.xml
JDK(Java Util Logging) logging.properties

我们此时使用的是 SpringBoot 默认使用的 logback,所以可以在类路径下放入“logback.xml”:

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <property name="LOG_HOME" value="log"/>
    <!--定义日志文件名称-->
    <property name="FILE_NAME" value="testLog"/>
    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--
            格式化输出:
                %d 表示日期
                %thread 表示线程名
                %-5level 级别从左显示 5 个字符宽度
                %msg 日志消息
                %n 是换行符
            -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>
    <!-- 按照每天生成日志文件 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/${FILE_NAME}.%d{yyyy-MM-dd}.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <!--格式化输出:%d 表示日期,%thread 表示线程名,%-5level 表示级别从左显示 5 个字符宽度 %msg 表示日志消息,%n 是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
        <!--日志文件最大的大小-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10MB</MaxFileSize>
        </triggeringPolicy>
    </appender>
    <!-- 日志输出级别 -->
    <root level="INFO">
        <appender-ref ref="STDOUT"/> <!--启用控制台输出-->
        <appender-ref ref="FILE"/> <!--启用文件输出-->
    </root>
</configuration>

此时“logback.xml”就可以直接被日志框架读取配置。

高级功能

在 SpringBoot 项目中,SpringBoot 是推荐我们使用文件名为“logback-spring.xml”的配置文件,因为使用“logback-spring.xml”文件名时该配置文件就不是直接被日志框架读取,而是先被 SpringBoot 读取,此时 SpringBoot 就给我们提供了日志框架以外的功能,可以定制不同 Profile 环境下来生效日志的不同配置,使用如下:

<root level="INFO">
    <!--仅在非 prod 环境下启用控制台输出-->
    <springProfile name="!prod">
        <appender-ref ref="STDOUT"/> <!--启用控制台输出-->
    </springProfile>
    <!--仅在 prod 环境下启用文件输出-->
    <springProfile name="prod">
        <appender-ref ref="FILE"/> <!--启用文件输出-->
    </springProfile>
</root>

切换日志框架

切换到log4j

SpringBoot 默认使用 logback 作为日志实现,而我们如果想要切换到其它日志实现该怎么做呢?下面以切换到 log4j 为例:

我们可以先分析 SpringBoot 的日志关系 和 SLF4J 的日志适配图

因为默认使用的是 logback 实现,所以现在 SpringBoot 有导入 jcl-over-slf4j.jar 、 log4j-over-slf4j.jar 、 jul-to-slf4j.jar 这三个日志替换包,而我们要切换成 log4j 实现,首先我们要排除 log4j 的日志替换包即 log4j-over-slf4j.jar 和 logback 的实现包:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
<exclusions>
    <exclusion>
        <artifactId>log4j-over-slf4j</artifactId>
        <groupId>org.slf4j</groupId>
    </exclusion>
    <exclusion>
        <artifactId>logback-classic</artifactId>
        <groupId>ch.qos.logback</groupId>
    </exclusion>
</exclusions>
</dependency>

接着看下图:

可以看到要将 log4j 切换为 slf4j 的实现需要两个替换包,这两个替换包 SpringBoot 默认已经使用了,所以还需要添加一个适配包:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
</dependency>

此时可以添加 log4j 的配置文件“log4j.properties”:

log4j.rootLogger = info,stdout

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

运行项目,会发现日志实现已经切换到 log4j。

log4j2场景启动器

上面演示的是如何切换 SpringBoot 的日志实现为 log4j,看起来有些麻烦,下面再看一个示例,将 SpringBoot 的日志实现切换为 log4j2。

切换为 log4j2 就很简单了,因为 SpringBoot 给我们提供了 log4j2 的场景启动器,通过之前的分析我们已经知道 SpringBoot 默认日志场景启动器为 spring-boot-starter-logging ,下面我们直接排除这个场景启动器的依赖,添加 log4j2 的场景启动器:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <artifactId>spring-boot-starter-logging</artifactId>
                <groupId>org.springframework.boot</groupId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j2</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

此时 SpringBoot 项目的日志实现就已经切换为 log4j2 了,同 logback,要使用 Profile 功能时,需修改 log4j2 的配置文件名为 log4j2-spring.xml 。

java框架之SpringBoot(3)-日志的更多相关文章

  1. 【java框架】SpringBoot(5)--SpringBoot整合分布式Dubbo+Zookeeper

    1.理论概述 1.1.分布式 分布式系统是若干独立计算机的集合,这些计算机对于用户来讲就像单个系统. 由多个系统集成成一个整体,提供多个功能,组合成一个板块,用户在使用上看起来是一个服务.(比如淘宝网 ...

  2. java框架之SpringBoot(1)-入门

    简介 Spring Boot 用来简化 Spring 应用开发,约定大于配置,去繁从简,just run 就能创建一个独立的.产品级别的应用. 背景: J2EE 笨重的开发.繁多的配置.低下的开发效率 ...

  3. java框架之SpringBoot(4)-资源映射&thymeleaf

    资源映射 静态资源映射 查看 SpringMVC 的自动配置类,里面有一个配置静态资源映射的方法: @Override public void addResourceHandlers(Resource ...

  4. java框架之SpringBoot(5)-SpringMVC的自动配置

    本篇文章内容详细可参考官方文档第 29 节. SpringMVC介绍 SpringBoot 非常适合 Web 应用程序开发.可以使用嵌入式 Tomcat,Jetty,Undertow 或 Netty ...

  5. java框架之SpringBoot(14)-任务

    使用 maven 创建 SpringBoot 项目,引入 Web 场景启动器. 异步任务 1.编写异步服务类,注册到 IoC 容器: package zze.springboot.task.servi ...

  6. java框架之SpringBoot(15)-安全及整合SpringSecurity

    SpringSecurity介绍 Spring Security 是针对 Spring 项目的安全框架,也是 Spring Boot 底层安全模块默认的技术选型.它可以实现强大的 Web 安全控制.对 ...

  7. java框架之SpringBoot(16)-分布式及整合Dubbo

    前言 分布式应用 在分布式系统中,国内常用 Zookeeper + Dubbo 组合,而 SpringBoot 推荐使用 Spring 提供的分布式一站式解决方案 Spring + SpringBoo ...

  8. java框架之SpringBoot(2)-配置

    规范 SpringBoot 使用一个全局的配置文件,配置文件名固定为 application.properties 或 application.yml .比如我们要配置程序启动使用的端口号,如下: s ...

  9. java框架之SpringBoot(6)-Restful风格的CRUD示例

    准备 环境 IDE:Idea SpringBoot版本:1.5.19 UI:BootStrap 4 模板引擎:thymeleaf 3 效果:Restful 风格 CRUD 功能的 Demo 依赖 &l ...

随机推荐

  1. Spring Boot 2.x 学习专栏

    Spring Boot 2.0 入门指南 Spring Boot 2.0 返回JSP页面实战 Spring Boot 2.0 热部署指南 Spring Boot 2.0 整合FreeMarker模板引 ...

  2. Atitit 酷奇的押金危机 遇到资金链断裂作为创始人应该怎么办

    Atitit 酷奇的押金危机  遇到资金链断裂作为创始人应该怎么办 遇到对方确实经营不善,资产已经还不了用户的押金怎么办?? 1. 一些重要原则 1 1.1. 二次分配原则  公平原则 1 1.2. ...

  3. 如何在你的Vue项目配置vux

    做移动端项目的话vue现在是首要的选择,足够轻便,文档足够全,当然用的人多,项目中遇到的坑别人可能也遇到过,解决起来也比较方便,至于在开发中做需要的移动端组件库,个人比较推崇vux. 其实项目里组件库 ...

  4. 【ML入门系列】(三)监督学习和无监督学习

    概述 在机器学习领域,主要有三类不同的学习方法: 监督学习(Supervised learning) 非监督学习(Unsupervised learning) 半监督学习(Semi-supervise ...

  5. AOP 技术原理——代理模式全面总结

    前言 非常重要的一个设计模式,也很常见,很多框架都有它的影子.定义就不多说了.两点: 1.为其它对象提供一个代理服务,间接控制对这个对象的访问,联想 Spring 事务机制,在合适的方法上加个 tra ...

  6. kotlin语法使用笔记

    kotlin中文文档:http://www.kotlindoc.cn/ClassesAndObjects/Classes-and-Inheritance.html 1. 声明类的构造方法 例如继承Fr ...

  7. VMware vCenter Server 6.5安装

    实验环境: 数据中心操作系统 :  Windows server 2008 R2(建议配置8G内存) 数据中心安装包版本: VMware vCenter Server 6.5 数据中心数据库:     ...

  8. 获取mssqlserver数据库表的字段名称,字段说明,数据类型,主键等表的信息

    sql脚本: SELECT TableName then d.name else '' end,---表名 TableShowsThat then isnull(f.value,'') else '' ...

  9. 按位与(&)和按位或(|)

    /** * 按位与 : & * 按位或 : | */ public class Demo { /** * 按位与: 为什么(5 & 9)的值等于1 * 按位或: 为什么(5 | 9)的 ...

  10. Kafka集群管理工具kafka-manager的安装使用

    一.kafka-manager简介 kafka-manager是目前最受欢迎的kafka集群管理工具,最早由雅虎开源,用户可以在Web界面执行一些简单的集群管理操作.具体支持以下内容: 管理多个集群 ...