工程经验 - 服务日志打印方案

一、背景

在工程中,服务日志尤其重要,因为线上是不能 debug 的,只能通过日志分析排查

这里分享实际工作中,我搭建工程时常使用的日志打印方案,以及我为业务组研发组提供的日志规约

二、方案

  • 定义控制台输出打印器:引用此打印器的路径包,所有日志级别(TRACE DEBUG INFO WARN ERROR)都要打印到控制台
  • 定义文件输出打印器:引用此打印器的路径包,比 DEBUG 严重的级别(INFO WARN ERROR)日志需持久化到文件
  • 定义可执行的日志规约,让研发遵循更好地排查 BUG
  • 定义工程所有包,默认打印 INFO 日志

三、实例

3.1 日志库

这里使用 logback,最简单的依赖只需要引入:

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.16</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.5</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.2.3</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>
</dependencies>

在工程的 resources 目录下写 logback.xml,使用 ThresholdFilter 特性,用于级别过滤

<configuration>
    <property name="logbase" value="/var/log/project/trace" />


    <!--  LOG LEVEL: TRACE < DEBUG < INFO < WARN < ERROR -->
    <!--  控制台输出打印器-STDOUT: LOG ALL LEVEL  -->
    <appender name="STDOUT"
              class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%method] [%line] - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!--  文件输出打印器-file: LOG INFO WARN ERROR  -->
    <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <encoder>
            <pattern>%d{MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%method] [%line] - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <FileNamePattern>${logbase}/web.%d{yyyy-MM-dd}.%i.log
            </FileNamePattern>
            <maxFileSize>20MB</maxFileSize>
            <maxHistory>15</maxHistory>
            <totalSizeCap>500MB</totalSizeCap>
        </rollingPolicy>
    </appender>

    <!--  工程所有包默认打印 INFO 日志  -->
    <root level="INFO">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="file" />
    </root>

     <!--  定义业务代码包,开启 DEBUG 日志  -->
    <logger name="io.jalr.blog" level="DEBUG" additivity="true">
    </logger>

</configuration>

3.2 业务代码

如下调用,即可实现日志打印:

@Slf4j
public class Main {
    public static void main(String[] args) {
        log.warn("This is jalr4ever");
    }
}

四、日志规约

4.1 跨网络服务日志

【强制】跨网络的服务调用,服务接收方接口打印 DEBUG 入参,服务请求方打印 DEBUG 响应参数,两方异常栈 ERROR 都需要打印

4.2 日志信息

【强制】info 日志带上当前执行逻辑相关的业务信息,不打业务无关字符串。业务信息举例:业务 name、业务 id、业务过程参数等。

4.3 日志级别

【强制】打日志区分好 info 、error、warning 级别。

  • FETAL:系统进入某种程度的不可用
  • ERROR:需要马上被处理
  • WARN:表示可能出现问题的操作
  • INFO:系统正常运行的状态
  • 扩展阅读:When to use the different log levels