logback日志[10分钟掌握]

3,120 阅读4分钟

引言

本文将通过介绍logback的常用配置,根据完整的配置文件举例说明每一个标签属性的意义和用法,实现适用生产的日志拆分、日志保存功能,并提供完整的运行过程效果

logback配置标签

先介绍一下logback常用的一些标签,方便大家有个理解,logback常用的配置标签结构大致如下:

  • configuration标签 configuration下有3个配置项
<configuration scan="true" scanPeriod="60 seconds" debug = "true">

scan="true" 表示打开动态加载配置,scanPeriod 用于配置动态加载时间,当不指定scanscanPeriod时默认scan="true" scanPeriod="60 seconds",配置debug = "true"打开logback的调试日志,默认不打开

  • property标签 property用于声明变量
<property name="CHARSET" value="UTF-8"/>

logback也支持读取spring配置文件中的配置项,可以通过springProperty读取

    <springProperty scope="context" name="springAppName"
                    source="spring.application.name" />
  • appender标签 appender 是对日志事件进行输出的组件
 <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${PATTERN}</pattern>
            <charset>${CHARSET}</charset>
        </encoder>
    </appender>

常用的appender有:
ConsoleAppender 将日志事件附加到控制台
FileAppender 将日志事件输出到文件中
RollingFileAppender 轮转日志文件,当日志文件满足条件后,将日志输出到另外一个文件

  • logger标签
    logger用来设置某个包或者某个类的级别以及指定appender
  <logger name="errorLogger" additivity ="true" level="ERROR">
     <appender-ref ref="errorAppender" />
 </logger>

additivity声明向上级logger传递打印信息,默认是true;appender-ref指定日志输出的组件,可以配置多个

  • root标签
<root level="INFO">
     <appender-ref ref="STDOUT"/>
 </root>

root标签是所有logger的上级,如果下级appender指定了additivity="true",下级appender的输出都会在root中声明的appender中体现

实践

直接上一个完整可用配置

  <?xml version="1.0" encoding="UTF-8"?>
<configuration>

   <springProperty scope="context" name="springAppName"
                   source="spring.application.name" />
   <springProperty scope="context" name="springActive"
                   source="spring.profiles.active" />
   <property name="CHARSET" value="UTF-8"/>
   <property name="SAVE_PATH" value="/data/logs/${springAppName}"/>
   <property name="PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %X{trackId} [%15.15t] %class{39}.%method[%L] : %m%n"/>
   <if condition='property("springActive").equals("prod")'>
       <then>
           <property name="maxHistory" value="7"/>
       </then>
       <else>
           <property name="maxHistory" value="3"/>
       </else>
   </if>
   <property name="maxFileSize" value="200MB"/>
   
   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
       <encoder>
           <pattern>${PATTERN}</pattern>
           <charset>${CHARSET}</charset>
       </encoder>
   </appender>
   
   <appender name="digestAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
       <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
           <level>INFO</level>
       </filter>
       <file>${SAVE_PATH}/${springAppName}-digest.log</file>
       <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
           <fileNamePattern>${SAVE_PATH}/digest/${springAppName}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
           <maxHistory>${maxHistory}</maxHistory>
           <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
               <maxFileSize>${maxFileSize}</maxFileSize>
           </timeBasedFileNamingAndTriggeringPolicy>
       </rollingPolicy>
       <encoder>
           <pattern>${PATTERN}</pattern>
           <charset>UTF-8</charset>
       </encoder>
       <append>true</append>
   </appender>
   
   <appender name="bizAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
       <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
           <level>INFO</level>
       </filter>
       <file>${SAVE_PATH}/${springAppName}-biz.log</file>
       <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
           <fileNamePattern>${SAVE_PATH}/biz/${springAppName}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
           <maxHistory>${maxHistory}</maxHistory>
           <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
               <maxFileSize>${maxFileSize}</maxFileSize>
           </timeBasedFileNamingAndTriggeringPolicy>
       </rollingPolicy>
       <encoder>
           <pattern>${PATTERN}</pattern>
           <charset>UTF-8</charset>
       </encoder>
       <append>true</append>
   </appender>
   
    <appender name="statAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
       <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
           <level>INFO</level>
       </filter>
       <file>${SAVE_PATH}/${springAppName}-stat.log</file>
       <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
           <fileNamePattern>${SAVE_PATH}/stat/${springAppName}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
           <maxHistory>${maxHistory}</maxHistory>
           <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
               <maxFileSize>${maxFileSize}</maxFileSize>
           </timeBasedFileNamingAndTriggeringPolicy>
       </rollingPolicy>
       <encoder>
           <pattern>${PATTERN}</pattern>
           <charset>${CHARSET}</charset>
       </encoder>
       <append>true</append>
   </appender>
   
   <appender name="errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
       <file>${SAVE_PATH}/${springAppName}-error.log</file>
       <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
           <fileNamePattern>${SAVE_PATH}/error/${springAppName}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
           <maxHistory>${maxHistory}</maxHistory>
           <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
               <maxFileSize>${maxFileSize}</maxFileSize>
           </timeBasedFileNamingAndTriggeringPolicy>
       </rollingPolicy>
       <encoder>
           <pattern>${PATTERN}</pattern>
           <charset>${CHARSET}</charset>
       </encoder>
       <filter class="ch.qos.logback.classic.filter.LevelFilter">
           <level>ERROR</level>
           <onMatch>ACCEPT</onMatch>
           <onMismatch>DENY</onMismatch>
       </filter>
       <append>true</append>
   </appender>
   
    <logger name="digestLogger" additivity ="true">
       <appender-ref ref="digestAppender" />
   </logger>
   <logger name="bizLogger" additivity ="true">
       <appender-ref ref="bizAppender" />
   </logger>
   <logger name="statLogger" additivity ="true">
       <appender-ref ref="statAppender" />
   </logger>
   <logger name="errorLogger" additivity ="true" level="ERROR">
       <appender-ref ref="errorAppender" />
   </logger>
     <logger name = "cn.sleeper" level = "DEBUG"/>

<root level="INFO">
       <appender-ref ref="STDOUT"/>
   </root>
</configuration>
   

解释

如上配置

  • springProperty从spring配置文件中获取了应用名用以对日志的命名,获取了spring.profiles.active参数用于区分运行环境

  • property定义了CHARSET用于指定日编码、定义SAVE_PATH用于指定日志文件的报存路径、定义PATTERN指定日志格式、定义maxHistory声明日志文件保持天数、 maxFileSize指定每个日志文件的最大容量,需要一提的是,logback中使用<if condition...判断,需要添加janino 依赖,参考如下:

     <dependency>
             <groupId>org.codehaus.janino</groupId>
             <artifactId>janino</artifactId>
             <version>2.6.1</version>
     </dependency>
    
  • appender
    (1)STDOUTappender类型为ConsoleAppender,作为控制台输出,指定控制台输出日志格式、编码类型
    (2)bizAppenderappender类型为RollingFileAppender,作为业务日志输出
    (3)digestAppenderappender类型为RollingFileAppender,作为摘要日志输出
    (4)statAppenderappender类型为RollingFileAppender,作为统计日志输出
    (5)errorAppenderappender类型为RollingFileAppender,作为异常日志输出
    在以上每个appender定义了<level>日志打印级别,使用TimeBasedRollingPolicy定义日志文件的轮转策略,指定了日志文件命名、最长保存时间、文件最大容量,使用 <encoder>定义日志格式、日志编码,errorAppender使用LevelFilter过滤ERROR级别的日志,所有ERROR级别的日志交给errorAppender处理,非INFO级别的日志会被过滤掉,其他appender使用ThresholdFilter过滤低于配置值INFO级别的日志

  • logger
    针对每一个定义的appender,定义了对应的logger,使用appender-ref关联,便于在代码中进行日志拆分,additivity="true"表示日志会反馈到root中,root中定义的是控制台输出的appender,也就是说在logger声明了additivity="true",不仅会被<logger>本身到appender记录到文件中,也会打印到控制台

  • root
    level定义了打印级别 appender-ref指定了输出到控制台到ConsoleAppender

效果

结合上面的配置文件,我们定义了多个logger,所以在使用的时候,需要对log进行一层封装,以便在调用的时候能够调用定义好的对应的appender组件

public interface LogApi {
    Logger dlog = LoggerFactory.getLogger("digestLogger");
    Logger blog = LoggerFactory.getLogger("bizLogger");
    Logger slog = LoggerFactory.getLogger("statLogger");
    Logger elog = LoggerFactory.getLogger("errorLogger");
}

使用LogApi打印日志测试

@RestController
@RequestMapping("/test")
public class LogController  {
    @GetMapping
    public void log() {

        blog.trace("测试业务日志 trace");
        blog.debug("测试业务日志 debug");
        blog.info("测试业务日志 info");
        blog.warn("测试业务日志 warn");
        blog.error("测试业务日志 error");

        elog.trace("测试异常日志 trace");
        elog.debug("测试异常日志 debug");
        elog.info("测试异常日志 info");
        elog.warn("测试异常日志 warn");
        elog.error("测试异常日志 error");

        slog.trace("测试统计日志 trace");
        slog.debug("测试统计日志 debug");
        slog.info("测试统计日志 info");
        slog.warn("测试统计日志 warn");
        slog.error("测试统计日志 error");

        dlog.trace("测试摘要日志 trace");
        dlog.debug("测试摘要日志 debug");
        dlog.info("测试摘要日志 info");
        dlog.warn("测试摘要日志 warn");
        dlog.error("测试摘要日志 error");

    }
}

控制台输出效果 生成的目录结构 biz目录下
为了测试,定义了2KB拆分,所以当文件大于2kb,将会放到配置的目录中去,生成新的文件
logTest-biz.log logTest-error.log

本例代码已上传 github.com/chenxuancod…