LogBack在boot项目中的解析与应用

LogBack是 Spring Boot 项目(Spring Boot 默认使用 Logback 作为日志框架)。Logback 提供了更简洁的配置、更快的执行速度、更小的内存占用,并支持多种日志输出方式和灵活的配置选项。

日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出

在 Spring Boot 项目中,Logback 是默认的日志框架 ,它被广泛用于日志的采集、格式化、输出和管理。Spring Boot 对 Logback 提供了良好的集成支持,开发者可以通过简单的配置实现日志的集中管理、异步写入、按需过滤等功能。

Boot中Logback的默认行为

默认日志框架

  • Spring Boot 默认使用 Logback 作为日志实现框架。
  • 无需额外添加依赖(spring-boot-starter 已默认包含 logback-classic)。
  • 支持通过 application.propertiesapplication.yml 动态配置日志级别。

默认日志输出

  • 控制台输出 :默认将日志输出到控制台(使用 ConsoleAppender)。
  • 日志级别 :默认日志级别为 INFO
  • 日志格式 :默认使用 Spring Boot 提供的美化格式

Boot中Logback的配置方式

application.yml

logging:
  level:
    root: INFO
    com.example.service: DEBUG
    org.springframework.web: WARN
  file:
    name: logs/app.log
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
    file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
  • 优点:简单易用,适合快速配置。
  • 缺点:无法实现复杂的日志行为(如异步日志、多 Appender、Filter 等)。

yml和xml的优先级

在 Spring Boot 项目中:

  • 存在 logback-spring.xml :优先使用 logback-spring.xml 的日志配置,application.ymllogging 配置被忽略。
  • 不存在 logback-spring.xml :使用 application.yml 中的 logging 配置。

logback自定义配置

基本语法

根节点<configuration>

  • scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true
  • scanPeriod:设置监测配置文件是否有修改的时间间隔
  • debug:true打印出logback内部日志信息,实时查看logback运行状态。默认值false
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="false" scanPeriod="60 seconds" debug="false">
</configuration>

子节点<appender>

Appender 是负责将日志事件输出到指定目的地的核心组件。每个 Appender 定义了一个日志输出的目标(如控制台、文件、数据库等),并通过 Layout/EncoderFilter 控制日志的格式和过滤逻辑。

每个 Appender 包含以下关键元素:

  • 目标 :日志输出的位置(如控制台、文件、网络等)。
  • Layout/Encoder :定义日志的格式(如文本、JSON、XML)。
  • Filter :控制哪些日志事件需要被处理或忽略。
    在这里插入图片描述

常见 Appender

  • ConsoleAppender:输出到控制台。
  • FileAppender:输出到文件。
  • RollingFileAppender:支持滚动策略(如按时间或大小滚动日志文件)。
  • SocketAppender:通过网络发送日志到远程服务器。
  • SMTPAppender:通过邮件发送日志。
  • AsyncAppender:异步日志输出,减少对主线程的影响。

ConsoleAppender

将日志输出到控制台,适用于开发调试或实时监控

<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />


<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
       <pattern>${log.pattern}</pattern>
       <charset>UTF-8</charset>
    </encoder>
</appender>

FileAppender

将日志写入指定文件,需要持久化日志但无需滚动的场景

<appender name="FILE" class="ch.qos.logback.core.FileAppender">
  <file>logs/app.log</file>
  <append>true</append> <!-- 是否追加写入 -->
  <encoder>
    <pattern>%d{HH:mm:ss} [%thread] %-5level %logger - %msg%n</pattern>
  </encoder>
</appender>

RollingFileAppender(常用)

将日志写入指定文件,需要持久化日志且需要日志文件滚动的场景(按大小或时间归档)

核心组件

  • RollingPolicy :定义滚动策略(如 TimeBasedRollingPolicySizeAndTimeBasedRollingPolicy)。
  • TriggeringPolicy :触发滚动的条件(如文件大小)。
TimeBasedRollingPolicy

时间维度

<appender name="ROLLING" class="ch.qos.logback.core.RollingFileAppender">
  <file>logs/app.log</file>
  <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <!-- 每天滚动一次,保留30天历史日志 -->
    <fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern>
    <maxHistory>30</maxHistory>
  </rollingPolicy>
  <encoder>
    <pattern>%d{HH:mm:ss} [%thread] %-5level %logger - %msg%n</pattern>
  </encoder>
  <!-- 此日志文件只记录warn级别的,上级别和下级别都不会记录 -->
 <filter class="ch.qos.logback.classic.filter.LevelFilter">
     <level>WARN</level>
     <onMatch>ACCEPT</onMatch>
     <onMismatch>DENY</onMismatch>
 </filter>
</appender>
SizeAndTimeBasedRollingPolicy

结合了时间和大小的双重维度

  • 每次写入日志时,检查当前文件大小是否超过 maxFileSize
  • 如果超过,则触发滚动,生成新的文件(%i 序号递增)。
  • 示例 :logs/app.%d{yyyy-MM-dd}.%i.log

生成文件名:

  • app.2023-10-01.0.log(第一个文件)
  • app.2023-10-01.1.log(因大小超限生成的第二个文件)
  • app.2023-10-02.0.log(第二天的新文件)
<appender name="ROLLING" class="ch.qos.logback.core.RollingFileAppender">
  <!-- 当前写入的日志文件 -->
  <file>logs/app.log</file>
  
  <!-- 定义滚动策略 -->
  <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
    <!-- 文件名模式:按天滚动,且文件大小不超过 100MB -->
    <fileNamePattern>logs/app.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
    <!-- 单个文件最大大小,默认 10MB -->
    <maxFileSize>100MB</maxFileSize>
    <!-- 日志文件最大保留天数 -->
    <maxHistory>30</maxHistory>
    <!-- 总日志大小限制(可选) -->
    <totalSizeCap>1GB</totalSizeCap>
  </rollingPolicy>
  
  <!-- 日志格式 -->
  <encoder>
    <pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
  </encoder>
</appender>

SMTPAppender

通过邮件发送日志(如 ERROR 级别日志)

<appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
  <smtpHost>smtp.example.com</smtpHost>
  <to>admin@example.com</to>
  <from>logger@example.com</from>
  <subject>ERROR: %logger{20} - %m</subject>
  <evaluator class="ch.qos.logback.classic.boolex.OnErrorEvaluator"/>
  <layout class="ch.qos.logback.classic.PatternLayout">
    <pattern>%d{HH:mm:ss} [%thread] %-5level %logger - %msg%n</pattern>
  </layout>
</appender>

DBAppender

将日志写入预定义的数据库表

<appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
  <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
    <driverClass>com.mysql.cj.jdbc.Driver</driverClass>
    <url>jdbc:mysql://localhost:3306/logs</url>
    <user>root</user>
    <password>password</password>
  </connectionSource>
</appender>

AsyncAppender

<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
    <appender-ref ref="ROLLING_FILE" />
    <queueSize>1024</queueSize> <!-- 队列大小 -->
    <discardingThreshold>0</discardingThreshold> <!-- 丢弃阈值 -->
</appender>

异步机制

  • 使用 BlockingQueue 缓冲日志事件
  • 工作线程从队列取事件交给目标 Appender

关键参数

  • queueSize:队列容量(默认256)
  • discardingThreshold:队列剩余容量阈值,低于此值丢弃 WARN 以下日志
  • includeCallerData:是否收集调用者数据(影响性能)

缺点

  • 如果服务崩溃,容易造成日志丢失

Appender的Filter

Filter 的作用

  • 日志筛选 :根据日志级别、内容、上下文等条件,决定是否输出该日志。
  • 条件过滤 :支持基于正则表达式、自定义规则等复杂条件筛选。
  • 多级过滤 :可以在一个 Appender 中配置多个 Filter,按顺序执行过滤逻辑。

Filter 的执行流程

  • Filter 是在 Appender 内部配置的。

  • 日志事件进入 Appender 后,会依次经过每个 Filter。

  • Filter 返回以下三种状态之一:

    • FilterReply.ACCEPT:接受该日志,继续处理。
    • FilterReply.DENY:拒绝该日志,直接丢弃。
    • FilterReply.NEUTRAL:不处理,继续下一个 Filter。

常见的 Filter 类型及配置示例

LevelFilter

根据日志级别进行过滤,只允许指定级别的日志通过。

示例:只输出 ERROR 级别的日志

<appender name="ERROR_ONLY" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
        <level>ERROR</level>
        <onMatch>ACCEPT</onMatch>
        <onMismatch>DENY</onMismatch>
    </filter>
    <encoder>
        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
</appender>
  • onMatch:匹配时的行为(ACCEPT 表示接受)。
  • onMismatch:不匹配时的行为(DENY 表示拒绝)。
ThresholdFilter

根据日志级别阈值 进行过滤,允许等于或高于指定级别的日志通过。

示例:只输出 WARN 及以上级别的日志

<appender name="WARN_THRESHOLD" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>WARN</level>
    </filter>
    <encoder>
        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
</appender>
  • 特点 :比 LevelFilter 更灵活,适用于需要过滤多个级别的情况。
EvaluatorFilter

基于 正则表达式自定义条件表达式 进行日志过滤。

示例:匹配包含 “error” 关键字的日志

<appender name="KEYWORD_FILTER" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
        <evaluator>
            <expression>message.contains("error")</expression>
        </evaluator>
        <onMatch>ACCEPT</onMatch>
        <onMismatch>DENY</onMismatch>
    </filter>
    <encoder>
        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
</appender>
  • expression:支持 Java 表达式(如 message.contains("error"))。
  • 可用于过滤特定异常、用户ID、请求参数等。

Filter 的组合使用(Filter Chain)

可以在一个 Appender 中配置多个 Filter,形成过滤链 ,按顺序执行过滤逻辑。

<appender name="CHAIN_FILTER" class="ch.qos.logback.core.ConsoleAppender">
    <!-- 第一个 Filter:只允许 WARN 及以上级别通过 -->
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>WARN</level>
    </filter>

    <!-- 第二个 Filter:只允许包含 "error" 的日志通过 -->
    <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
        <evaluator>
            <expression>message.contains("error")</expression>
        </evaluator>
        <onMatch>ACCEPT</onMatch>
        <onMismatch>DENY</onMismatch>
    </filter>

    <encoder>
        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
</appender>

自定义 Filter

public class CustomFilter extends Filter<ILoggingEvent> {
    @Override
    public FilterReply decide(ILoggingEvent event) {
        if (event.getMessage().contains("important")) {
            return FilterReply.ACCEPT;
        } else {
            return FilterReply.DENY;
        }
    }
}
<appender name="CUSTOM_FILTER" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="com.example.CustomFilter" />
    <encoder>
        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
</appender>

子节点<logger>

可选节点

<logger> 用于定义特定包或类的日志记录行为

  • 指定日志输出的包或类 :通过 name 属性指定日志记录器的名称(通常是 Java 包名或类名)。

  • 控制日志级别(TRACE, DEBUG, INFO, WARN, ERROR)

  • 关联 Appender(决定日志输出位置)

  • 控制日志事件传递(叠加性)

<logger name="cn.xxx" level="WARN" additivity="false">
    <appender-ref ref="BIZ_LOG_FILE" />
</logger>
name必填,指定日志记录器的名称(通常是包名或类名)。
level可选,设置该日志记录器的日志级别。如果不设置,则继承父级root日志级别。
additivity可选,默认为true,表示是否将日志传递给父级记录器(如 root)。设为false表示不继承父级日志行为。

适用场景

  • 避免日志重复输出 :当某个 <logger> 已绑定特定 Appender,不希望其日志再被全局 Appender 捕获时,设置 additivity="false"
  • 模块化日志管理 :为不同模块(如 service、dao、controller)配置独立的日志输出路径和级别。

动态控制日志级别

在 Spring Boot 中,可以通过 application.properties 动态设置日志级别,但xml配置优先

logging.level.com.example.service=DEBUG
logging.level.com.example.dao=INFO

注意事项

  • 若同时出现对同一个包的logger定义,取最后一个
<logger name="cn.xxx" level="info" />
<!-- 只取WARN   -->
<logger name="cn.xxx" level="WARN" />
  • 若出现子包和父包,则会出现子包覆盖父包部分,但子包外部分仍沿用父包配置
<logger name="cn.xxx" level="info" />
<!-- 仅覆盖api包下的配置   -->
<logger name="cn.xxx.user.api" level="WARN" />
  • 如果需要同时设置多个属性 (如级别和输出目标),应合并到同一个 <logger>
<!-- 业务日志(WARN) -->
<appender name="BIZ_LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- 其他配置... -->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
        <level>WARN</level>
        <onMatch>ACCEPT</onMatch>
        <onMismatch>DENY</onMismatch>
    </filter>
</appender>

<!-- 应用日志(ERROR) -->
<appender name="APP_LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- 其他配置... -->
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>ERROR</level>
    </filter>
</appender>

<!-- 控制台日志(INFO) -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- 其他配置... -->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
        <level>INFO</level>
        <onMatch>ACCEPT</onMatch>
        <onMismatch>DENY</onMismatch>
    </filter>
</appender>

<!-- 统一 Logger 配置 -->
<logger name="zsoft.gov" level="INFO" additivity="false">
    <appender-ref ref="BIZ_LOG_FILE" />
    <appender-ref ref="APP_LOG_FILE" />
    <appender-ref ref="STDOUT" />
</logger>

子节点<root>

root代表 根日志记录器(Root Logger) ,是整个日志系统的默认配置中心 。所有其他 <logger> 节点如果没有显式指定日志级别或 Appender,都会继承 <root> 的配置。

<root level="info">
    <appender-ref ref="CONSOLE"/>
    <appender-ref ref="FILE"/>
    <appender-ref ref="INFO_FILE"/>
</root>

logback自定义样例

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">

    <!-- 定义日志路径(可从外部配置文件注入) -->
    <property name="LOG_HOME" value="/opt/logs/myapp" />
    <property name="APP_NAME" value="myapp" />

    <!-- 日志格式模板 -->
    <property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M\(%line\) - %msg%n"/>

    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <!-- 业务日志文件输出(INFO 级别) -->
    <appender name="BIZ_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/${APP_NAME}-biz.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/${APP_NAME}-biz-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>
            <maxFileSize>100MB</maxFileSize>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
        <!-- 仅输出 INFO 级别 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 错误日志文件输出(ERROR 级别) -->
    <appender name="ERROR_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/${APP_NAME}-error.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/${APP_NAME}-error-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>
            <maxFileSize>100MB</maxFileSize>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
        <!-- 仅输出 ERROR 级别 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
    </appender>

    <!-- SQL 日志文件输出(DEBUG 级别) -->
    <appender name="SQL_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/${APP_NAME}-sql.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/${APP_NAME}-sql-%d{yyyy-MM-dd}.log.gz</fileNamePattern>
            <maxHistory>7</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %msg%n</pattern>
        </encoder>
        <!-- 仅输出 DEBUG 级别 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 异步日志(提升性能) -->
    <appender name="ASYNC_BIZ" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="BIZ_LOG" />
        <queueSize>1024</queueSize>
        <discardingThreshold>0</discardingThreshold>
    </appender>

    <appender name="ASYNC_ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="ERROR_LOG" />
    </appender>

    <!-- Root Logger -->
    <root level="INFO">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="ASYNC_BIZ" />
        <appender-ref ref="ASYNC_ERROR" />
    </root>

    <!-- 第三方组件日志级别控制 -->
    <logger name="org.springframework" level="WARN" />
    <logger name="org.hibernate" level="WARN" />
    <logger name="org.apache.zookeeper" level="ERROR" />
    <logger name="org.apache.kafka" level="WARN" />

    <!-- 指定包的日志级别 -->
    <logger name="com.example.myapp.service" level="DEBUG" />
    <logger name="com.example.myapp.repository" level="DEBUG" />

    <!-- SQL 日志绑定到特定包 -->
    <logger name="com.example.myapp.repository" level="DEBUG" additivity="false">
        <appender-ref ref="SQL_LOG" />
    </logger>

</configuration>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值