LogBack 概览

404 阅读4分钟

概念

appender

负责日志写入策略, 如写入到console、文件,日志格式,文件分隔等

layout

负责日志最终输出的格式

encoder

负责将代码中要打印的内容转换成最终将要打印的内容。

encoder 完成转换工作主要是通过 layout 来完成的。

Logger

用户打印日志的入口,一个logger只有关联上 appender 才能输出日志.

每个 Logger 都有一个父 Logger.

所有 Logger 都有一个默认的父Logger: ROOT.

ROOT Logger 没有父 Logger。

module 简介

logback-core

核心模块, appender 和 layout 在这里实现

logback-classic

提供 Logger,

logback-access

主要提供和容器的集成, 如 tomcat, jetty等

logback与log4j比较

  • 内核重写、测试充分、初始化内存加载更小,这一切让logback性能和log4j相比有诸多倍的提升
  • logback非常自然地直接实现了slf4j,这个严格来说算不上优点,只是这样,再理解slf4j的前提下会很容易理解logback,也同时很容易用其他日志框架替换logback
  • logback有比较齐全的200多页的文档
  • logback当配置文件修改了,支持自动重新加载配置文件,扫描过程快且安全,它并不需要另外创建一个扫描线程
  • 支持自动去除旧的日志文件,可以控制已经产生日志文件的最大数量

(取自: www.cnblogs.com/xrq730/p/86…)

配置

下面以xml配置为例

一般在 resource下配置 logback.xml 即可.

注意: spring-boot 项目最好使用 logback-spring.xml, 因为 logback.xml 的加载会早于 application.properties, 那么在 application.properties 里定义的变量, logback 是取不到的, 而且 spring-boot 提供的一些额外功能也无法使用

<configuration>
    <property name="LOG_HOME" value="${catalina.base}/logs"/>
    <springProperty scope="context" name="springAppName" source="spring.application.name"/>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <property name="CONSOLE_LOG_PATTERN"
              value="%clr(%green(%d{yyyy-MM-dd HH:mm:ss.SSS})){faint} %highlight(%p) %cyan(%clr([${springAppName:-},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}])){yellow} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
    <include resource="com/atour/web/logback/base.xml"/>
    <turboFilter class="com.atour.concurrency.profile.ProfileTurboFilter" />
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- encoder 默认配置为PatternLayoutEncoder -->
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>utf-8</charset>
        </encoder>
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/sys.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/sys.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
            <maxFileSize>2GB</maxFileSize>
            <totalSizeCap>80GB</totalSizeCap>
            <!-- 除按日志记录之外,还配置了日志文件不能超过自定大小,若超过,日志文件会以索引0开始,命名日志文件,例如sys.2018-03-25.0.log -->
            <!--<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">-->
            <!--<maxFileSize>2MB</maxFileSize>-->
            <!--</timeBasedFileNamingAndTriggeringPolicy>-->
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>utf-8</charset>
        </encoder>
    </appender>
    <!--async-->
    <appender name="FILEAsync" class="ch.qos.logback.classic.AsyncAppender">
        <!--    丢弃日志的阈值, 如配置20,表示队列还剩 20% 时,丢弃 trace, debug, info 日志    -->
        <discardingThreshold>20</discardingThreshold>
        <!--    队列大小     -->
        <queueSize>1024</queueSize>
        <!--    真正的日志输出    -->
        <appender-ref ref="FILE"/>
        <!--    是否永不阻塞     -->
        <neverBlock>true</neverBlock>
        <!--提取调用者数据,默认为false, 否则无法打印类信息和行号-->
        <includeCallerData>true</includeCallerData>
    </appender>

    <appender name="SLOW_SQL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/slow.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/slow.%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>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>utf-8</charset>
        </encoder>
    </appender>
    <!--async-->
    <appender name="SLOWSQLAsync" class="ch.qos.logback.classic.AsyncAppender">
        <!--    丢弃日志的阈值, 如配置20,表示队列还剩 20% 时,丢弃 trace, debug, info 日志    -->
        <discardingThreshold>20</discardingThreshold>
        <!--    队列大小     -->
        <queueSize>1024</queueSize>
        <!--    真正的日志输出    -->
        <appender-ref ref="SLOW_SQL_FILE"/>
        <!--    是否永不阻塞     -->
        <neverBlock>true</neverBlock>
        <!--提取调用者数据,默认为false, 否则无法打印类信息和行号-->
        <includeCallerData>true</includeCallerData>
    </appender>


    <logger name="slow_log" level="warn" additivity="false">
        <appender-ref ref="SLOWSQLAsync"/>
    </logger>


    <root level="INFO">
        <appender-ref ref="FILEAsync"/>
    </root>

</configuration>

属性 类型 含义
debug boolean 是否开启 debug
packagingData boolean 是否打印每个类所在的 jar 包
scan boolean 是否开始自动扫描
scanPeriod string 扫描周期, 默认是毫秒, 可以指定时间单位, 如 30 seconds

定义具体的日志输出方式

属性 含义
name appender 的名称
class appender 具体的处理类

常用的 appender 如下:

  • ch.qos.logback.core.ConsoleAppender
  • ch.qos.logback.core.rolling.RollingFileAppender
  • ch.qos.logback.classic.AsyncAppender

文件的切割侧率, 常用的有

  • ch.qos.logback.core.rolling.TimeBasedRollingPolicy 按照日期进行分割
  • ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy 按日期进行分割, 如果单文件的大小超过限制, 会在进行分割

下面以 SizeAndTimeBasedRollingPolicy 为例

<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
    <!--日志文件输出的文件名-->
    <FileNamePattern>${LOG_HOME}/sys.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
    <!--日志文件保留天数-->
    <MaxHistory>30</MaxHistory>
    <!--单个文件的大小-->
    <maxFileSize>2GB</maxFileSize>
    <!--所有文件的大小-->
    <totalSizeCap>80GB</totalSizeCap>
</rollingPolicy>

异步输出

对于想要异步输出, 可以用如下的配置

<appender name="FILEAsync" class="ch.qos.logback.classic.AsyncAppender">
    <!--    丢弃日志的阈值, 如配置20,表示队列还剩 20% 时,丢弃 trace, debug, info 日志    -->
    <discardingThreshold>20</discardingThreshold>
    <!--    队列大小     -->
    <queueSize>1024</queueSize>
    <!--    真正的日志输出    -->
    <appender-ref ref="FILE"/>
    <!--    是否永不阻塞     -->
    <neverBlock>true</neverBlock>
    <!--提取调用者数据,默认为false, 否则无法打印类信息和行号-->
    <includeCallerData>true</includeCallerData>
</appender>

注意:

  • 如果未配置 <file> 标签, 默认的文件名为 <FileNamePattern> 指定的文件名, 例如: sys.2020-07-07.0.log
  • 如果不希望这样, 可以通过指定 <file>${LOG_HOME}/sys.log</file> 来让默认的文件为 sys.log, 这样当过了一天或者文件超过大小才会分割出一个 sys.2020-07-07.0.log 文件

将内容装换为最终日志要输出的内容

一般使用 pattern 的形式, 如下:

<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
    <pattern>${CONSOLE_LOG_PATTERN}</pattern>
    <charset>utf-8</charset>
</encoder>

当然也可以自定义自己的 layout

public class MySampleLayout extends LayoutBase<ILoggingEvent> {

  public String doLayout(ILoggingEvent event) {
    StringBuffer sbuf = new StringBuffer(128);
    sbuf.append(event.getTimeStamp() - event.getLoggingContextVO.getBirthTime());
    sbuf.append(" ");
    sbuf.append(event.getLevel());
    sbuf.append(" [");
    sbuf.append(event.getThreadName());
    sbuf.append("] ");
    sbuf.append(event.getLoggerName();
    sbuf.append(" - ");
    sbuf.append(event.getFormattedMessage());
    sbuf.append(CoreConstants.LINE_SEP);
    return sbuf.toString();
  }
}
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
    <layout class="chapters.layouts.MySampleLayout" />
</encoder>

定义logger

  1. 属性如下
属性 含义
name 代码里指定的日志名称或者类的全路径
level 日志输出级别
additivity 是否在父 logger 里输出, 一般设置 false, 否则会打印两份
  1. 指定 appender

<appender-ref ref="FILEAsync"/> 指定appender

  • root 是根 logger
  • 任何没有在配置中指定的logger, 都将按 <root> 里的配置输出日志

其他标签

定义属性, 可以通过 ${} 引用

用于引用其他的配置

动态控制日志的级别

其他

statusListener

shutdownHook

参考

logback.qos.ch/manual juejin.cn/post/684490…