首页 > 编程语言 >Java Spring Boot logback 日志配置与使用总结

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

时间:2023-12-06 16:24:12浏览次数:51  
标签:输出 Java MM Spring dd Boot 日志 logback logger

在项目开发中,日志是必不可少的,没有日志,怎么排查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 也是内置的,这点我们从源码就可以看到:

image.png

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 配置结构

<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:可选,日志的级别,允许一个不区分大小写的字符串值 TRACE,DEBUG,INFO,WARN,ERROR,ALL 或 OFF
  3. addtivity:可选,默认为true,将此logger的信息向上级传递,将有root节点定义日志打印。如果设置为false,将不会上传,此时需要定义一个appender-ref 节点才会输出。

<logger>元素可以包含零个或多个<appender-ref>元素。

这样引用的每个 appender 都被添加到指定的 logger 中,logger 元素级别具有继承性。

某些应用场景:如单独把 service 包下的日志输出到 service.log 中,或者是单独处理切面日志。

root

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

springProperty

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

encoder

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

pattern

确定日志输出的格式。

filter

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

或者从另外的角度看,filter 元素中主要有2个过滤器:

  • LevelFilter,只匹配某种级别的日志,即精确匹配日志级别来过滤
  • ThresholdFilter,过滤某些低于该级别的日志,其他日志等于或高于的日志级别保留

其中还有几个子元素:

  • onMatch
  • onMisMatch
    在满足匹配或满足不匹配下分别执行什么动作,如 DENY/ACCEPT 等。

e.g.

只打印 INFO 级别的日志,其余的全部禁止打印输出:

<configuration>
  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>INFO</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>
    <encoder>
      <pattern>
        %-4relative [%thread] %-5level %logger{30} - %msg%n
      </pattern>
    </encoder>
  </appender>
  <root level="DEBUG">
    <appender-ref ref="CONSOLE" />
  </root>
</configuration>

拒绝所有低于 INFO 级别的日志,只输出 INFO 以及以上级别的日志:

<configuration>
  <appender name="CONSOLE"
    class="ch.qos.logback.core.ConsoleAppender">
    <!-- deny all events with a level below INFO, that is TRACE and DEBUG -->
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
      <level>INFO</level>
    </filter>
    <encoder>
      <pattern>
        %-4relative [%thread] %-5level %logger{30} - %msg%n
      </pattern>
    </encoder>
  </appender>
  <root level="DEBUG">
    <appender-ref ref="CONSOLE" />
  </root>
</configuration>

rollingPolicy

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

image.png

TimeBasedRollingPolicy:可能是最受欢迎的滚动策略。它根据时间定义翻转策略,例如按天或按月。
TimeBasedRollingPolicy 承担滚动和触发所述翻转的责任。实际上,TimeBasedTriggeringPolicy 实现了 RollingPolicy 和 TriggeringPolicy 接口。

SizeAndTimeBasedRollingPolicy:有时您可能希望按日期归档文件,但同时限制每个日志文件的大小,特别是如果后处理工具对日志文件施加大小限制。
为了满足此要求,logback 提供了 SizeAndTimeBasedRollingPolicy ,它是 TimeBasedRollingPolicy 的一个子类,实现了基于时间和日志文件大小的翻滚策略。

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

server:
  port: 8000

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

控制台输出

logback-spring.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 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 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 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>

输出特定目录下日志

比如有时我们的需求更加细化,希望将 service 包下的日志集中在 service.log 中,这里又应该如何操作呢,具体请参考[5],service.log 部分。

输出切面日志-请求响应参数或traceId

对于 web应用 最常见的日志需求,我们肯定需要将请求的入参和响应的参数及相关的一些客户端信息打印在一起,或者,综合那么多日志,都是分散的,我们想通过一个参数就追踪到某个请求相关的一系列日志,即日志追踪,这里也请参考[5],http-log部分。

4.日志的使用

测试 controller:

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();
    }

}

测试结果

控制台:

image.png

fileInfo:

image.png

fileError:

image.png

参考:

标签:输出,Java,MM,Spring,dd,Boot,日志,logback,logger
From: https://www.cnblogs.com/davis12/p/17879790.html

相关文章

  • Java Spring Boot 常用配置总结
    在涉及项目开发时,通常我们会灵活地把一些配置项集中在一起,如果你的项目不是很大的情况下,那么通过配置文件集中不失为一个很好的解决方案。在SpringBoot中,我们可以方便地通过读取appliction.properties/application.yaml格式的配置文件,进而注入我们的项目中。1.多环境配置......
  • 小白使用springboot项目进行开发系统前期工作
    首先进行项目的创建,springboot项目创建有两种方式。可以使用idea直接创建springboot项目,可以使用阿里云的源,创建会快一点这里可以选择各种的依赖第二种就是直接创建maven项目,直接导入pom坐标类似于这种,点击刷新即可点击查看代码<dependency>......
  • Java Spring Boot 参数校验及自定义校验
    在项目开发中,时常会碰到前端传递过来的请求参数需要校验,毕竟永远不要相信没有经过自己校验的数据,如果是零星几个参数,直接if...elseif...else...即可,但数据量大了,同时为了尽可能地增加复用,这里就可以用到参数校验了,如果你觉得框架提供的校验方法不够用,或者你的校验比较个性化,那......
  • java与算法Day1 Scanner的应用(一)
    java中使用输入需要用到java.util.Scanner。Scanner有next,nextInt,nextString,hasNext,hasNextLine等方法。使用XXX variable=Scanner.NextXXX就可以获取一个输入值。next系列的方法,他们的作用都是从键盘中接收数据。当程序执行到他们的时候,在命令行中就开始等待键盘输入了,而......
  • 【JavaScript高级程序设计】-3语言基础
    3.1语法.........................................................213.1.1区分大小写..................................213.1.2标识符..........................................213.1.3注释..............................................223.1.4严格模式......
  • Spring入门
    Spring框架介绍Spring是一个轻量级Java开发框架,最早有RodJohnson创建,目的是为了解决企业级应用开发的业务逻辑层和其他各层的耦合问题。它是一个分层的JavaSE/JavaEEfull-stack(一站式)轻量级开源框架,为开发Java应用程序提供全面的基础架构支持。Spring负责基础架构,因此Java开发......
  • SpringBoot项目中集成自定义公共Maven依赖如何集成与调试
    场景Nexus-在项目中使用Maven私服,Deploy到私服、上传第三方jar包、在项目中使用私服jar包:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/101391279Maven项目在pom文件中引入lib下的第三方jar包并打包进去:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/det......
  • kettle从入门到精通 第二十三课 kettle carte 错误(java.lang.OutOfMemoryError: GC ov
     1、Couldnotemitbufferduetolackofrequests(无法发出缓冲区,因为请求不足。)原因有两点:1)消费者处理数据能力较弱,如表输出步骤。2)消费者没有处理数据,如传递的数据中有字段type=1的数据,这种情况没有处理。解放方案:针对1)采用多线程处理和开启批量提交,如下图所示批量插入......
  • 【Java 进阶篇】Java会话技术之Cookie的存活时间
    在Web应用程序中,会话管理是一项关键的任务,用于跟踪用户的活动和保持用户状态。Cookie是会话管理的一种重要方式之一,通过Cookie可以存储有关用户的信息,但这些信息不会永久保留,而是有一个特定的存活时间。本篇博客将详细介绍Java中Cookie的存活时间,包括如何设置、修改和管理Cookie的......
  • 【Java 进阶篇】Java Session 原理及快速入门
    大家好,欢迎来到本篇博客。今天,我们将探讨JavaWeb开发中一个重要而令人兴奋的概念,即Session(会话)。Session是一种在Web应用程序中跟踪用户状态和数据的机制。我们将深入了解Session的原理,并通过示例来快速入门。什么是Session?在Web开发中,Session是一种服务器端的机制,用于跟踪用户与W......