Springboot日志系统

164 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 15 天,点击查看活动详情

日志系统

SpringBoot为我们提供了丰富的日志系统,它几乎是开箱即用的。

日志门面和日志实现

我们首先要区分一下,什么是日志门面(Facade)什么是日志实现,我们之前学习的JUL实际上就是一种日志实现,我们可以直接使用JUL为我们提供的日志框架来规范化打印日志,而日志门面,如Slf4j,是把不同的日志系统的实现进行了具体的抽象化,只提供了统一的日志使用接口,使用时只需要按照其提供的接口方法进行调用即可,由于它只是一个接口,并不是一个具体的可以直接单独使用的日志框架,所以最终日志的格式、记录级别、输出方式等都要通过接口绑定的具体的日志系统来实现,这些具体的日志系统就有log4j、logback、java.util.logging等,它们才实现了具体的日志系统的功能。

日志门面和日志实现就像JDBC和数据库驱动一样,一个是画大饼的,一个是真的去做饼的。

但是现在有一个问题就是,不同的框架可能使用了不同的日志框架,如果这个时候出现众多日志框架并存的情况,我们现在希望的是所有的框架一律使用日志门面(Slf4j)进行日志打印,这时该怎么去解决?我们不可能将其他框架依赖的日志框架替换掉,直接更换为Slf4j吧,这样显然不现实。

这时,可以采取类似于偷梁换柱的做法,只保留不同日志框架的接口和类定义等关键信息,而将实现全部定向为Slf4j调用。相当于有着和原有日志框架一样的外壳,对于其他框架来说依然可以使用对应的类进行操作,而具体如何执行,真正的内心已经是Slf4j的了。

所以,SpringBoot为了统一日志框架的使用,做了这些事情:

  • 直接将其他依赖以前的日志框架剔除
  • 导入对应日志框架的Slf4j中间包
  • 导入自己官方指定的日志实现,并作为Slf4j的日志实现层

在SpringBoot中打印日志信息

SpringBoot使用的是Slf4j作为日志门面,Logback(Logback 是log4j 框架的作者开发的新一代日志框架,它效率更高、能够适应诸多的运行环境,同时天然支持SLF4J)作为日志实现,对应的依赖为:

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

此依赖已经被包含了,所以我们如果需要打印日志,可以像这样:

@RequestMapping("/login")
public String login(){
    Logger logger = LoggerFactory.getLogger(MainController.class);
    logger.info("用户访问了一次登陆界面");
    return "login";
}

因为我们使用了Lombok,所以直接一个注解也可以搞定哦:

@Slf4j
@Controller
public class MainController {

    @RequestMapping("/login")
    public String login(){
        log.info("用户访问了一次登陆界面");
        return "login";
    }

日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,SpringBoot默认只会打印INFO以上级别的信息。

配置Logback日志

说明

  1. 默认情况下,springboot项目使用logback来记录日志,并输出到控制台。实际开发中我们不需要直接添加logback日志依赖。 你会发现spring-boot-starter 其中包含了spring-boot-starter-logging,该依赖内容就是 springboot 默认的日志框架logback。

第一步,自定义logback-custom.xml配置文件,并且放在 src/main/resources下

提示:根据不同的日志系统,你可以按如下规则组织配置文件名,就能被正确加载,本文直接自定义名字了,需要在application.yml文件中指定一下,后面会说到:

  1. Logback:logback-spring.xml, logback-spring.groovy, logback.xml, logback.groovy
  2. Log4j:log4j-spring.properties, log4j-spring.xml, log4j.properties, log4j.xml
  3. Log4j2:log4j2-spring.xml, log4j2.xml
  4. JDK (Java Util Logging):logging.properties

springboot官方推荐优先使用带有 -spring 的文件名作为你的日志配置(如比使用 logback-spring.xml ,而不是logback.xml),命名为logback-spring.xml的日志配置文件,spring boot可以为它添加一些spring boot特有的配置项。

logback-custom.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 此xml在spring-boot-1.5.3.RELEASE.jar里 -->
<!--    <include resource="org/springframework/boot/logging/logback/defaults.xml" />-->
<!--    <include resource="org/springframework/boot/logging/logback/console-appender.xml" />-->
    <!-- 开启后可以通过jmx动态控制日志级别(springboot Admin的功能) -->
    <!--<jmxConfigurator/>-->
    <contextName>logback-custom</contextName>
    <!-- 定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径 -->
    <springProperty scope="context" name="LOG_HOME" source="log.file"/>

    <!-- 输出到控制台 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        encoders are assigned the type
        ch.qos.logback.classic.encoder.PatternLayoutEncoder by default
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- error日志 -->
    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <prudent>true</prudent>
        <append>true</append>
        <encoder>
            <pattern>%date [%level] [%thread] %logger{60} [%file : %line] %msg%n</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 添加.gz 历史日志会启用压缩 大大缩小日志文件所占空间 -->
            <!--<fileNamePattern>/home/hfw-client/hfw_log/stdout.log.%d{yyyy-MM-dd}.log</fileNamePattern>-->
            <fileNamePattern>${LOG_HOME}/error/error-%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>7</maxHistory><!--  保留7天日志 -->
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- file日志 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <prudent>true</prudent>
        <append>true</append>
        <encoder>
            <pattern>%date [%level] [%thread] %logger{60} [%file : %line] %msg%n</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 添加.gz 历史日志会启用压缩 大大缩小日志文件所占空间 -->
            <!--<fileNamePattern>/home/hfw-client/hfw_log/stdout.log.%d{yyyy-MM-dd}.log</fileNamePattern>-->
            <fileNamePattern>${LOG_HOME}/file/file-%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>7</maxHistory><!--  保留7天日志 -->
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <logger name= "fileLog" level="INFO" additivity="false">
        <appender-ref ref="FILE"/>
        <appender-ref ref="ERROR"/>
    </logger>

<!--    &lt;!&ndash; 设置包打印日志级别,例如把所有mapper文件的sql都出到控制台,还可以精确到某个类 &ndash;&gt;-->
<!--    <logger name= "com.luoyu.mapper.applymapper" level="TRACE" />-->
<!--    <logger name= "com.luoyu.mapper.shiromapper" level="TRACE" />-->

    <root level="info">
        <appender-ref ref="ERROR"/>
        <appender-ref ref="STDOUT"/>
    </root>

</configuration>
解释:
  1. 此处name是扫描需要打印sql语句的mapper包,可配置多个,而level则是打印日志的级别,还可以精确到某个类。
  2. 级别分为:TRACE < DEBUG < INFO < WARN < ERROR < FATAL
  3. 只能展示大于或等于设置的日志级别的日志;也就是说springboot默认级别为INFO,那么在控制台展示的日志级别只有INFO 、WARN、ERROR、FATAL
  4. 此处的log.file代表输入到日志文件的路径,需要在application.yml中配置,后面会说到

第二步,打开application.yml文件,新增以下配置

# 指定自定义命名的配置文件
logging:
  config: classpath:logback-custom.xml
# 打印日志统一根路径
log:
  file: D:/log
此时启动项目便可自动打印出mybatis的sql语句到控制台,需要指定mapper的包路径,也可以输出日志到文件中。后面还需要测试lombok的输出,单元测试最后给出。

第三步,代码里打印日志,在pom.xml文件中添加依赖,如下

<!-- 打印日志 @Slf4j 注解依赖 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.16</version>
</dependency>

第四步,IDEA添加lombok插件,选择file—>setting—>plugins,搜索lombok插件进行安装,不懂请自行百度

第五步,编写单元测试类,LogbackApplicationTests,并进行测试

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;

@Slf4j
// 获取启动类,加载配置,确定装载 Spring 程序的装载方法,它回去寻找 主配置启动类(被 @SpringBootApplication 注解的)
@SpringBootTest
class LogbackApplicationTests {

    private Logger fileLog = LoggerFactory.getLogger("fileLog");

    @Test
    void consoleLogTest() {
        log.info("测试输出到控制台");
    }

    @Test
    void fileLogTest() {
        fileLog.info("测试输出到日志文件");
    }

    @BeforeEach
    void testBefore(){
        log.info("测试开始!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
    }

    @AfterEach
    void testAfter(){
        log.info("测试结束!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
    }

}
  1. @Slf4j注解跟log.info配合使用,属于lombok工具方式输出,直接输出到控制台,调试的时候特别方便。另外一种fileLog.info会特定输出到指定的日志文件
  2. log.后面的方法名代表打印级别,包括log.trace(),log.debug(),log.info(),log.warn(),log.error()等方法

自定义Banner

我们在之前发现,实际上Banner部分和日志部分是独立的,SpringBoot启动后,会先打印Banner部分,那么这个Banner部分是否可以自定义呢?答案是可以的。

我们可以直接来配置文件所在目录下创建一个名为banner.txt的文本文档,内容随便你:

//                          _ooOoo_                               //
//                         o8888888o                              //
//                         88" . "88                              //
//                         (| ^_^ |)                              //
//                         O\  =  /O                              //
//                      ____/`---'\____                           //
//                    .'  \\|     |//  `.                         //
//                   /  \\|||  :  |||//  \                        //
//                  /  _||||| -:- |||||-  \                       //
//                  |   | \\\  -  /// |   |                       //
//                  | \_|  ''\---/''  |   |                       //
//                  \  .-\__  `-`  ___/-. /                       //
//                ___`. .'  /--.--\  `. . ___                     //
//              ."" '<  `.___\_<|>_/___.'  >'"".                  //
//            | | :  `- \`.;`\ _ /`;.`/ - ` : | |                 //
//            \  \ `-.   \_ __\ /__ _/   .-` /  /                 //
//      ========`-.____`-.___\_____/___.-`____.-'========         //
//                           `=---='                              //
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //
//             佛祖保佑          永无BUG         永不修改             //

可以使用在线生成网站进行生成自己的个性Banner:www.bootschool.net/ascii

我们甚至还可以使用颜色代码来为文本切换颜色:

${AnsiColor.BRIGHT_GREEN}  //绿色

也可以获取一些常用的变量信息:

${AnsiColor.YELLOW} 当前 Spring Boot 版本:${spring-boot.version}

玩的开心!