Java Spring Boot logback 日志配置与使用总结

在项目开发中,日志是必不可少的,没有日志,怎么排查bug,而且日志也有助于我们看到相关的输入输出,总的来说,日志是日常项目开发必须要有的。今天我们学习 Spring Boot 中集成 logback 日志,这里主要会涉及到 日志的配置 和简单实现,更多的细节请移步官方文档,自己品读,此文档有助于初涉 Spring Boot & logback 人群,可以快速直接上手 web 项目。

环境说明:

  • Spring Boot: 3.2.0
  • jdk: 17

1.logback简介

之前我们分享过 log4j 的使用,其实 log4j 和 logback 都是一拨人开发的,相当于 logback 是 log4j 的进阶版、升级版,这两种日志框架也都是基于 slf4j(Simple log facade for Java) 接口实现的,而且在 Spring Boot 中 logback 也是内置的,这点我们从源码就可以看到:

Why logback

现在 logback 应用也广,为何呢[1]:

  • 1.更快的执行速度。基于 Log4J , Logback 重写了内部实现,在一定场景下,速度快10倍,而且需要的内存更少。
  • 2.测试充分。据说 这框架测试很充分,而且和 Log4j 不是一个级别,咱们也不知道,暂且相信吧。

主要组成

Logback 主要由三个模块组成:

  • logback-core,基础组件,其他模块基于此构建,提供一些关键的通用机制
  • logback-classic,相当于 Log4J 的升级版,实现了 SLF4J
  • logback-access,与 Servlet 交互的容器,如 tomcat、jetty 等,提供一些 HTTP 访问功能

2.配置项

通常我们会在 resources 目录下,和 application.properties 同级目录,另外起一个 日志 的配置文件,文件名为 logback-spring.xml ,当然你也可以在 application.properties或者application.yaml 中定义 logging 项,但不方便做到像在 xml 文件中定义的那么细,即在主配置文件中的配置,是个比较通用的,粗粒度的,如果想要更加细粒度的,比如设置多个输出项,不同的 format ,不同的 Level 输出,这种细粒度的,建议就在 logback-spring.xml 设置好了。

另外,总体来说,Logback 毕竟在 Log4J 基础上升级开发,所以其配置和 Log4J 的配置很相近,如果你了解过 Log4J 的配置,那么这里的配置对于你来说就是一通百通了,需要了解 Log4J 的配置,请参考[2]。

Logback 配置结构

xml 复制代码
<configuration scan="true" scanPeriod="60 seconds" debug="false">  
    <property name="xxx" value="yyy" /> 
    
    <contextName>${xxx}</contextName>
    
    <appender>
        //xxxx
    </appender>   
    
    <logger>
        //xxxx
    </logger>
    
    <root>             
       //xxxx
    </root>  
</configuration>  

可以看出主要就是在标签 configuration 下有3个 子元素:

  • appender
  • logger
  • root

接下来,我们就主要的标签元素做相应说明[4]。

日志标签元素

configuration

这是一个根节点,其中的各个属性如下:

  1. scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
  2. scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
  3. debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。

property

标记一个上下文变量,属性有name和value,定义变量之后可以使用${}来获取。

contextName

标识一个上下文名称,默认为default,一般用不到

appender

用来格式化日志输出节点,有两个属性nameclass,class用来指定哪种输出策略,常用就是控制台输出策略文件输出策略

这个节点很重要,通常的日志文件需要定义三个appender,分别是控制台输出,常规日志文件输出,异常日志文件输出。

logger

可选节点,用来具体指明包的日志输出级别,它将会覆盖root的输出级别。 该节点有几个重要的属性如下:

  1. name:指定的包名

  2. level:可选,日志的级别

  3. addtivity:可选,默认为true,将此logger的信息向上级传递,将有root节点定义日志打印。如果设置为false,将不会上传,此时需要定义一个appender-ref 节点才会输出。

root

这是一个必须节点,用来指定基础的日志级别,只有一个level属性,默认值是DEBUG。 该节点可以包含零个或者多个元素,子节点是appender-ref,标记这个appender将会添加到这个logger中。

springProperty

从属性文件在properties/yml文件中找到对应的配置项。

encoder

和pattern节点组合用于具体输出的日志格式和编码方式。

pattern

确定日志输出的格式。

filter

日志输出拦截器,没有特殊定制一般使用系统自带的即可,但是如果要将日志分开,比如将ERROR级别的日志输出到一个文件中,将除了ERROR级别的日志输出到另外一个文件中,此时就要拦截ERROR级别的日志了。

rollingPolicy

日志回滚策略,如下,我们看到有多种日志滚动策略,看命名就知道,详细可以看源码:logback-core-1.4.11

file

节点用来指明日志文件的输出位置,可以是绝对路径也可以是相对路径。

fileNamePattern

指明日志存储格式,可以连路径一起。

maxHistory

可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件,,例如设置为30的话,则30天之后,旧的日志就会被删除,此处设置和 fileNamePattern 的设置有关,比如我们在 case 中设置的 <fileNamePattern>${filePath}/myDemo.info.%d{yyyy-MM-dd}.log</fileNamePattern> ,那么我们这里设置的整型数值表示天,按天滚动,如果我们设置的是 <fileNamePattern>${filePath}/myDemo.info.%d{yyyy-MM-dd-HH}.log</fileNamePattern>maxHistory 设置整型数值时,这里就表示的是 按小时滚动,所以到底是按 天 滚动还是按 小时 滚动,取决于我们设置的 fileNamePattern 的最后一位是 dd 还是 HH

maxFileSize 每个日志文件的大小容量。

totalSizeCap

可选节点,用来指定日志文件的上限大小,例如设置为3GB的话,那么到了这个值,就会删除旧的日志。

3.集成配置

我们给日志加点色彩输出,这里的 demo 的主配置文件 application.yaml

yaml 复制代码
server:
  port: 8000

# 彩色输出
spring:
  output:
    ansi:
      enabled: detect

控制台输出

logback-spring.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!-- scan scanPeriod debug -->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <springProperty scope="context" name="filePath" source="logging.file.path"/>
    <!-- contextName 区分不同应用程序 -->
    <contextName>myDemo</contextName>
    <appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出(配色):%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%yellow(%d{yyyy-MM-dd HH:mm:ss.SSS}) %red([%thread]) %highlight(%-5level) %cyan(%logger{50}) %F:%M:%L - %magenta(%msg) %n
            </pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    
    <root level="info">
        <appender-ref ref="consoleLog"/>
    </root>

</configuration>

输出到日志文件

logback-spring.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!-- scan scanPeriod debug -->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <!-- property -> springProperty, 属性文件:在properties文件中找到对应的配置项 -->
    <springProperty scope="context" name="filePath" source="logging.file.path"/>
    <!-- contextName 区分不同应用程序 -->
    <contextName>myDemo</contextName>
    <appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出(配色):%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%yellow(%d{yyyy-MM-dd HH:mm:ss.SSS}) %red([%thread]) %highlight(%-5level) %cyan(%logger{50}) %F:%M:%L - %magenta(%msg) %n
            </pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!--根据日志级别分离日志,分别输出到不同的文件-->
    <appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>DENY</onMatch>
            <onMismatch>ACCEPT</onMismatch>
        </filter>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>
                %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} %F:%M:%L - %msg%n
            </pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!--滚动策略-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--按时间保存日志 修改格式可以按小时、按天、月来保存-->
            <fileNamePattern>${filePath}/myDemo.info.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!--保存时长-->
            <MaxHistory>30</MaxHistory>
            <!-- 每个文件最大容量 -->
            <maxFileSize>100MB</maxFileSize>
            <!--文件总大小,到上限后删除日志-->
            <totalSizeCap>20GB</totalSizeCap>
        </rollingPolicy>
    </appender>


    <root level="info">
        <appender-ref ref="consoleLog"/>
        <appender-ref ref="fileInfoLog"/>
    </root>

</configuration>

输出异常到日志文件

logback-spring.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!-- scan scanPeriod debug -->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <!-- property -> springProperty, 属性文件:在properties文件中找到对应的配置项 -->
    <springProperty scope="context" name="filePath" source="logging.file.path"/>
    <!-- contextName 区分不同应用程序 -->
    <contextName>myDemo</contextName>
    <appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出(配色):%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%yellow(%d{yyyy-MM-dd HH:mm:ss.SSS}) %red([%thread]) %highlight(%-5level) %cyan(%logger{50}) %F:%M:%L - %magenta(%msg) %n
            </pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!--根据日志级别分离日志,分别输出到不同的文件-->
    <appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <encoder>
            <pattern>
                %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} %F:%M:%L - %msg%n
            </pattern>
        </encoder>
        <!--滚动策略-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--路径-->
            <fileNamePattern>${filePath}/myDemo.error.%d{yyyy-MM-dd}.log</fileNamePattern>
            <MaxHistory>30</MaxHistory>
            <!--文件大小-->
            <totalSizeCap>20GB</totalSizeCap>
        </rollingPolicy>
    </appender>

    <root level="info">
        <appender-ref ref="consoleLog"/>
        <appender-ref ref="fileErrorLog"/>
    </root>

</configuration>

常用输出

logback-spring.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!-- scan scanPeriod debug -->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <!-- property -> springProperty, 属性文件:在properties文件中找到对应的配置项 -->
    <property name="logging.file.path" value="./logs" />
    <springProperty scope="context" name="logging.file.path" source="logging.file.path"/>
    <!-- contextName 区分不同应用程序 -->
    <contextName>myDemo</contextName>
    <appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出(配色):%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%yellow(%d{yyyy-MM-dd HH:mm:ss.SSS}) %red([%thread]) %highlight(%-5level) %cyan(%logger{50}) %F:%M:%L - %magenta(%msg) %n
            </pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!--根据日志级别分离日志,分别输出到不同的文件-->
    <appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>DENY</onMatch>
            <onMismatch>ACCEPT</onMismatch>
        </filter>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>
                %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} %F:%M:%L - %msg%n
            </pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!--滚动策略-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--按时间保存日志 修改格式可以按小时、按天、月来保存-->
            <fileNamePattern>${logging.file.path}/myDemo.info.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!--保存时长-->
            <MaxHistory>90</MaxHistory>
            <!--文件总大小-->
            <totalSizeCap>10GB</totalSizeCap>
        </rollingPolicy>
    </appender>

    <appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <encoder>
            <pattern>
                %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} %F:%M:%L - %msg%n
            </pattern>
        </encoder>
        <!--滚动策略-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--路径-->
            <fileNamePattern>${logging.file.path}/myDemo.error.%d{yyyy-MM-dd}.log</fileNamePattern>
            <MaxHistory>90</MaxHistory>
            <!--文件总大小-->
            <totalSizeCap>10GB</totalSizeCap>
        </rollingPolicy>
    </appender>
    <root level="info">
        <appender-ref ref="consoleLog"/>
        <appender-ref ref="fileInfoLog"/>
        <appender-ref ref="fileErrorLog"/>
    </root>
</configuration>

4.日志的使用

测试 controller:

Java 复制代码
package com.example.springbootforlogbackdemo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.SimpleDateFormat;
import java.util.Date;

@RestController
public class LoggerUsageController {
    private static final Logger logger = LoggerFactory.getLogger(LoggerUsageController.class);

    public static String timestampToFormatDatetime() {
        long ts = System.currentTimeMillis();
        Date date = new Date(ts);
        String formatTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(date);
        return formatTime;
    }

    @GetMapping(value = "/logUsage")
    public Object logUsage() {
        logger.debug("this is a debug msg."); // 低级别日志,不输出

        logger.info("this is a info msg."); // 输出到 console 和 info日志
        logger.warn("this is a warn msg.");

        logger.error("this is a error msg."); // 输出到 console 和error日志

        return "当前时间:" + LoggerUsageController.timestampToFormatDatetime();
    }

}

测试结果

控制台:

fileInfo:

fileError:

参考:

相关推荐
青灯文案114 分钟前
SpringBoot 项目统一 API 响应结果封装示例
java·spring boot·后端
微尘81 小时前
C语言存储类型 auto,register,static,extern
服务器·c语言·开发语言·c++·后端
计算机学姐1 小时前
基于PHP的电脑线上销售系统
开发语言·vscode·后端·mysql·编辑器·php·phpstorm
码拉松2 小时前
千万不要错过,优惠券设计与思考初探
后端·面试·架构
白总Server3 小时前
MongoDB解说
开发语言·数据库·后端·mongodb·golang·rust·php
计算机学姐3 小时前
基于python+django+vue的家居全屋定制系统
开发语言·vue.js·后端·python·django·numpy·web3.py
程序员-珍4 小时前
SpringBoot v2.6.13 整合 swagger
java·spring boot·后端
海里真的有鱼4 小时前
好文推荐-架构
后端
骆晨学长4 小时前
基于springboot的智慧社区微信小程序
java·数据库·spring boot·后端·微信小程序·小程序
AskHarries4 小时前
利用反射实现动态代理
java·后端·reflect