Logback配置与运用

背景

从毕业到现在参加工作已经有两年了,在这两年期间,经历的几个大项目和一些小项目,每个项目都涉及到日志这个模块。存在的意义无非就是两个:

  1. 记录业务日志,方便后期排查问题
  2. 以日志上的形式记录业务数据,并将日志文件推送第三方

每次接手一个新项目,就会先问有没有配置日志,如果没有配置日志模块,那么排查问题就是一个很恼火的问题,不清楚请求参数是什么,走了哪个判断,调用第三方接口的参数和返回结果是什么,一切的问题都需要一步一步的调试且耗时耗力。自从意识到这个问题后,每次写代码都会加入日志,并将请求参数,返回结果,耗时的数据写入日志,方便后期排查问题。

目前接触比较多Java 开源框架是SpringBoot,默认的日志实现是LogBack,通过配置xml文件就可以输出日志。之前在配置LogBack时,总是无脑的将其他项目的配置复制过来,也不懂为什么要这样配置。通过这几天的学习,把自己对logback的日志记录如下。

基础知识

日志级别

日志输出级别从大高到低为:

  1. OFF
  2. FATAL
  3. ERROR
  4. WARN
  5. INFO
  6. DEBUG
  7. TRACE
  8. ALL

日常开发中常用的是:

  1. ERROR:用于输出影响系统正常运行的信息
  2. WARN:用于输出错误信息,但不影响系统正常运行
  3. INFO:用于记录正常业务日志信息,方便后期的问题排查
  4. DEBUG:用于开发环境下的信息输出

方法打印

推荐使用Slf4j记录日志,在LogBack不被允许的情况下可以方便的切换到其他日志系统。实例化logger对象:

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

public class XXX {
    public static final Logger log = LoggerFactory.getLogger(XXX.class);
}

如果使用了lombok,则可以使用@Slf4j注解实例化logger对象

  • 输出ERROR日志
log.error("this is error log;time:{}", System.currentTimeMillis());
  • 输出WARN日志
log.warn("this is warn log;time:{}", System.currentTimeMillis());
  • 输出INFO日志
log.info("this is info log;time:{}", System.currentTimeMillis());
  • 输出DEBUG日志
        if (log.isDebugEnabled()) {
            log.debug("this is debug log;time:{}", System.currentTimeMillis());
        }

在开发中,使用参数化日志而不是字符串拼接,可以调高代码可读性并提高性能,在记录debug日志时,先判断目前所处环境是否支持debug输出,因为 String 字符串的拼接会使用 StringBuilder 的 append()方式,有一定的性能损耗。使用占位符仅 是替换动作,可以有效提升性能。(摘自:阿里巴巴Java开发手册嵩山版)

日志规约

Logback配置与运用_第1张图片
Java开发手册(泰山版)

配置LogBack

在SpringBoot框架中使用LogBack只需在resources目录下添加配置文件即可,可以项目启动日志设置为debug查看其初始化步骤:

23:42:43,896 |-INFO in ch.qos.logback.classic.LoggerContext[heron] - Could NOT find resource [logback-test.xml]
23:42:43,897 |-INFO in ch.qos.logback.classic.LoggerContext[heron] - Could NOT find resource [logback.groovy]
23:42:43,897 |-INFO in ch.qos.logback.classic.LoggerContext[heron] - Found resource [logback.xml] at [file:/E:/heron/target/classes/logback.xml]

这里使用logback.xml方式配置LogBack。

配置文件的组成


    

    
        
            %d{yyyy-MM-dd HH:mm:ss} [%-5level] %logger{36} [%file:%line] - %msg%n
        
    

    
        
    


    
        
    

整个XML文件由 标签包裹,属性含义:
  • scan: 扫描配置文件,查看配置文件是否有改动
  • scanPeriod:扫描时间间隔

用于定义变量,例如:



输出日志的核心,定义了日志的数据格式、日志类型、日志文件大小、日志保存时间和轮转策略

属性含义:

  • name:定义logger所用应用的名称,名称随意
  • class:定义日志输出实现类,常用的输出包括:控制台,文件和消息中间件
决定通过哪种方式写日志
定义日志输出格式,例如:年月日时分秒和毫秒信息,线程名称,类名,日志级别

用于设置一个包或一个类的日志打印级别

属性含义:

  • name:指定包名或类名
  • level:定义当前包或类应输出那个范围的日志
  • additivity:是否继承标签的日志级别定义

标签中应用已定义的 ,可以指定一个类或一个包如何输出日志;可以包含零个或多个

也是一个,但是它是根logger,且只有一个属性,即:level

日志输出至控制台

在没有日志配置文件之前,SpringBoot框架就会将所有日志输出至控制台,这里是通过BasicConfigurator类来实现的

package ch.qos.logback.classic;

import ch.qos.logback.classic.layout.TTLLLayout;
import ch.qos.logback.classic.spi.Configurator;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.ConsoleAppender;
import ch.qos.logback.core.encoder.LayoutWrappingEncoder;
import ch.qos.logback.core.spi.ContextAwareBase;

/**
 * BasicConfigurator configures logback-classic by attaching a 
 * {@link ConsoleAppender} to the root logger. The console appender's layout 
 * is set to a {@link ch.qos.logback.classic.layout.TTLLLayout TTLLLayout}.
 * 
 * @author Ceki Gülcü
 */
public class BasicConfigurator extends ContextAwareBase implements Configurator {

    public BasicConfigurator() {
    }

    public void configure(LoggerContext lc) {
        addInfo("Setting up default configuration.");
        
        ConsoleAppender ca = new ConsoleAppender();
        ca.setContext(lc);
        ca.setName("console");
        LayoutWrappingEncoder encoder = new LayoutWrappingEncoder();
        encoder.setContext(lc);
        
 
        // same as 
        // PatternLayout layout = new PatternLayout();
        // layout.setPattern("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n");
        TTLLLayout layout = new TTLLLayout();
 
        layout.setContext(lc);
        layout.start();
        encoder.setLayout(layout);
        
        ca.setEncoder(encoder);
        ca.start();
        
        Logger rootLogger = lc.getLogger(Logger.ROOT_LOGGER_NAME);
        rootLogger.addAppender(ca);
    }
}

查看TTLLLayout中的doLayout()方法完成日志格式的拼接。

可以在配置文件中自定义控制台日志的输出格式,并在标签中引用即可


    
    
        
            
            %d{yyyy-MM-dd HH:mm:ss} [%-5level] %logger{36} [%file:%line] - %msg%n
            
            %msg%n
        
    
    
        
    

控制台日志的实现类是ch.qos.logback.core.ConsoleAppender,在服务器上使用nohup java -jar xxx.jar命令启动服务时,项目的所有日志会保存在当前目录下的nohup.out文件中,也可以使用nohup java -jar xxx.jar > start.log将日志输出至指定目录下的指定文件中。这样做的缺点是:项目的启动日志和业务日志保存在同一个文件中,没有单独的划分。

日志输出至文件

为了解决上面存在的问题,就需要将启动日志和业务日志分隔开来,并输出至两个不同的文件中,且启动日志在项目正常启动之后并不需要经常查看。所以可以使用LogBack提供的ch.qos.logback.core.FileAppender,将业务日志以指定的格式作为输出。


    
    
    
    
        
            %d{yyyy-MM-dd HH:mm:ss} [%-5level] %logger{36} [%file:%line] - %msg%n
        
    
    
    
        ${logPath}/${appName}.log
        
            %d{yyyy-MM-dd HH:mm:ss} [%-5level] %logger{36} [%file:%line] - %msg%n
        
    
    
    
        
    
    
        
    

上面的配置中使用了两个变量appNamelogPath,使用${}的方式定义了业务日志要输出的路径和文件名称。

在使用nohup java -jar xxx.jar > start.log 2>&1 &命令启动服务时,就会出现两个文件:当前目录下的start.log和/tmp/logs/heron.log文件。在查看start.log文件没有明显的报错时,就可以查看heron.log文件中所存储的内容。若要将日志文件按月,按天,按小时存储,则可以使用做划分。



    ${logPath}/${bySecond}/${appName}.log
    
        %d{yyyy-MM-dd HH:mm:ss} [%-5level] %logger{36} [%file:%line] - %msg%n
    

这里使用yyyy-MM-dd的方式按天存储日志,并在标签以变量的方式应用接口,有了这个配置,业务日志的存储路径为/tmp/logs/2020-10-01/heron.log。每个文件夹下就存在一个heron.log文件。由此,又出现了一个问题。若该系统用户访问量少,日志文件体积小,只生成一个log是说的过去的。但在一个大量用户访问的系统中,每天都会产生大量的业务日志且日志文件的体积也比较大。有些项目的日志需要在服务器保存特定的时间以备相关部门的检查。

日志轮转

为了解决上述问题,logback提供了ch.qos.logback.core.rolling.RollingFileAppender。规定日志以某种方式轮转,解决了单个日志文件体积过大,且需要手动删除早期日志的问题。

ch.qos.logback.core.rolling.RollingFileAppender存在两个重要的子组件:

  • RollingPolicy:负责日志轮转的功能(怎么做)
  • TriggeringPolicy:负责日志轮转的时机(何时做)

RollingPolicy

Logback配置与运用_第2张图片

上图为RollingPolicy接口的实现类,每个实现类完成不同的功能。

  • TimeBasedRollingPolicy:基于时间的轮转策略。即负责怎么做,又决定何时做。以时间维度轮转。
  • SizeAndTimeBasedRollingPolicy: 是TimeBasedRollingPolicy子类,基于文件大小和时间的轮转策略,即可以显示单个日志文件的大小,也可以限制总文件的大小
  • FixedWindowRollingPolicy:根据固定窗口算法重命名文件

TriggeringPolicy

Logback配置与运用_第3张图片

触发策略可以分为两类:

  • 基于时间的触发(常用)
  • 基于文件尺寸的触发

TimeBasedRollingPolicy即负责轮转的行为,又负责触发轮转

ConsoleAppender、FileAppender和RollingFileAppender三者关系

Logback配置与运用_第4张图片

日志输出格式

以默认日志输出格式为例,每个参数的意义

%d{yyyy-MM-dd HH:mm:ss} [%-5level] %logger{36} [%file:%line] - %msg%n
  • %d{yyyy-MM-dd HH:mm:ss}:格式化输出当前时间,pattern语法与SimpleDateFormat相同。
  • [%-5level]:输出日志记录事件的级别
  • %logger{36}:logger名称
  • [%file:%line]:输出类名称和行号
  • %m:内容
  • %n:换行

更多配置信息,点击查看

logback配置模板

几个拿来即用的配置模板,方便你我他
  • 启动日志和业务日志分离,业务日志基于文件尺寸和时间轮转,单个文件最大10M,保留15天,日志总计5GB

    heron
    
    
    
    
        
            %d{yyyy-MM-dd HH:mm:ss} [%-5level] %logger{16} [%file:%line] - %msg%n
        
    
    
    
        ${logPath}/${appName}/${appName}.log
        
            ${logPath}/${appName}/%d{yyyy-MM-dd}/${appName}-%i.log
            10MB
            15
            5GB
        
        
            %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
        
    
    
        
    
    
        
    
  • 分别输出error info debug日志到不同的文件,并以时间和文件尺寸轮转

    heron
    
    

    
    
        
            %d{yyyy-MM-dd HH:mm:ss} [%-5level] %logger{36} [%file:%line] - %msg%n
        
    

    
    
        ${logPath}/${appName}/error.log
        
            ERROR
            ACCEPT
            DENY
        
        
            ${logPath}/${appName}/%d{yyyy-MM-dd}/${appName}-error-%i.log
            10MB
            15
            5GB
        
        
            %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{15} - %msg%n
        
    


    
    
        ${logPath}/${appName}/info.log
        
            INFO
            ACCEPT
            DENY
        
        
            ${logPath}/${appName}/%d{yyyy-MM-dd}/${appName}-info-%i.log
            10MB
            15
            5GB
        
        
            %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{15} - %msg%n
        
    


    
    
        ${logPath}/${appName}/debug.log
        
            DEBUG
            ACCEPT
            DENY
        
        
            ${logPath}/${appName}/%d{yyyy-MM-dd}/${appName}-debug-%i.log
            10MB
            15
            5GB
        
        
            %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{15} - %msg%n
        
    


    
        
        
        
    

    
    
        
    


    
        
    

原文地址:https://www.haicheng.website/...

你可能感兴趣的:(java,springboot,logback,slf4j)