logback

发布时间 2023-08-11 13:39:45作者: 江南烟雨行舟

Logback、Log4J、JUL 都是日志框架,而 SLF4J、commons-logging(日志门面)可以认为是这些日志框架的统一接口。

2023-08-11-102421

想要通过日志门面调用日志框架,就需要使用桥接器:

2023-08-11-03315

使用日志门面

导入依赖:

<!-- logback-classic 就是桥接器,这个包会自动引入 slf4j-api 包 -->
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.3.11</version>
    <scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>2.0.7</version>
</dependency>

Java 中的写法:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

private final Logger logger = LoggerFactory.getLogger(Object.class);

logback 配置

Spring Boot 建议使用 logback-spring.xml 而不是 logback.xml,因为 Spring Boot 会对 Logback 进行扩展,可以进行高级配置。

<?xml version="1.0" encoding="UTF-8"?>
<!--
scan:当此属性设置为 true 时,配置文件如果发生改变,将会被重新加载。
scanPeriod:每隔多长时间检测一遍文件是不是被修改了
-->
<configuration scan="true" scanPeriod="10 seconds">

    <!-- Spring Boot 对 Logback 的扩展,第一种扩展 -->
    <springProfile name = "staging" >
        <!-- 当 staging 环境激活时 -->
    </springProfile>
    <springProfile  name = "dev | staging" >
        <!-- 当 dev 或 staging 环境激活时 -->
    </springProfile>
    <springProfile  name = "!production" >
        <!-- 当 production 环境没有激活时 -->
    </springProfile>

    <!--
    Spring Boot 对 Logback 的扩展,第二种扩展
    从 Spring Environment 中读取 myapp.fluentd.host 属性值保存到 fluentHost 中,后续可以直接使用 fluentHost。
    -->
    <springProperty scope="context" name="fluentHost" source="myapp.fluentd.host" defaultValue="localhost"/>

    <!-- 
    自定义属性
    ${}:如果没有自定义属性或者没有使用 Logback 的扩展,那么这个就是获取系统属性,System.setProperty("", "");
    -->
    <property name="k1" value="${fluentHost}"/>
    
    <property name="log.path" value="/logs" />

    <!-- %d{HH:mm:ss.SSS} %-5level [%t] %class.%method Line:%-3L - %msg%n -->
    <!-- %d{HH:mm:ss.SSS} %-5level [%thread] %logger{200} - %msg%n -->
    <property name="log.pattern" value="%d{HH:mm:ss.SSS,GMT+8} %-5level [%thread] %logger{200} - [%method,%line] - %msg%n" />

    <!-- 将日志输出到控制台 -->
    <appender name="唯一名称1" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${log.pattern}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- 将日志滚动输出到文件 -->
    <appender name="唯一名称2" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- 过滤级别 -->
            <level>ERROR</level>
            <!-- 匹配到就允许 -->
            <onMatch>ACCEPT</onMatch>
            <!-- 匹配不到就禁止 -->
            <onMismatch>DENY</onMismatch>
        </filter>
        <!-- 将日志输出到这个文件 -->
        <file>${log.path}/文件名.log</file>
        <!-- 追加日志 -->
        <append>true</append>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 归档的文件路径和文件名,将下面的 fileName 改为文件路径和文件名 -->
            <fileNamePattern>${log.path}/文件名.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
            <!--
            单个归档日志文件的大小
            当 <file> 配置的文件超过了 <maxFileSize> 值后,会将日志保存到 <fileNamePattern> -->
            <maxFileSize>2GB</maxFileSize>
            <!-- 单个归档日志保留的最大天数,超过这个数量后,会删除之前的文件 -->
            <maxHistory>7</maxHistory>
            <!--
            归档日志文件总大小,超过这个数量后,会删除之前的文件
            <maxHistory> + <totalSizeCap> = 归档日志保留 7 天内,但是最多 20GB 大小
            -->
            <totalSizeCap>7GB</totalSizeCap>
            <!-- 在启动的时候清理归档日志 -->
            <cleanHistoryOnStart>true</cleanHistoryOnStart>
        </rollingPolicy>

        <encoder>
            <pattern>${log.pattern}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- 日志异步输出 -->
    <appender name="async-唯一名称1" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 队列快满的时候,也要保留所有级别的日志 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 阻塞队列的最大容量 -->
        <queueSize>1024</queueSize>
        <!-- 当队列满了后,不会向队列中继续添加所有级别的日志,而是丢弃这些日志 -->
        <neverBlock>true</neverBlock>
        <appender-ref ref="唯一名称1"/>
    </appender>

    <!-- 指定包或类的日志级别 -->
    <logger name="包名+类名" additivity="false" level="INFO">
        <!-- 关联 <appender> 的 name -->
        <appender-ref ref="唯一名称1"/>
        <appender-ref ref="xxx"/>
    </logger>

    <!-- <root> 是必须的,没有满足的 <logger> 都会使用 <root> -->
    <root level="INFO">
        <appender-ref ref="唯一名称1"/>
    </root>
</configuration>

也可通过配置文件设置日志级别:

logging:
  level:
    org.springframework: warn

下面是一些常见的日志级别:

<logger name="org.mybatis" additivity="false" level="DEBUG">
    <appender-ref ref="console"/>
</logger>

<logger name="org.apache.ibatis.datasource" additivity="false" level="DEBUG">
    <appender-ref ref="console"/>
</logger>

<logger name="druid.sql.Statement" additivity="false" level="debug">
    <appender-ref ref="console"/>
</logger>

<logger name="com.alibaba.druid.filter.stat.StatFilter" additivity="false" level="error">
    <appender-ref ref="console"/>
</logger>

参考资料

https://howtodoinjava.com/spring-boot2/logging/profile-specific-logging/

https://logback.qos.ch/manual/appenders.html

https://blog.51cto.com/u_15067232/4283028

https://howtodoinjava.com/logback/rollingfileappender/

https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.logging.logback-extensions

https://www.baeldung.com/java-lang-unsupportedclassversion

https://stackoverflow.com/questions/47457105/class-has-been-compiled-by-a-more-recent-version-of-the-java-environment