Logback 分离错误日志和 info 日志

Last Modified: 2023/09/10

概述

有时候需要将 error 级别的日志单独分离出来,这样有助于更好分析和处理错误。本文将会介绍如何根据日志等级分离错误。文中最后会附上一个完整可用的日志配置。

根据日志等级分离日志

下面的这段配置可以将 error 级别的日志分离到 error.log 中。具体原因见下面的解释。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <!-- ... 省略 -->
  <appender name="errorLog" 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>
  </appender>
  
  <root level="info">
    <appender-ref ref="errorLog" />
  </root>
</configuration>

之所以可以分离的根本原因是 appender 的 filter 配置,虽然 <root> 配置的日志级别是 info,但是经过 filter 的过滤后,只有 error 级别的日志会被记录到 error.log 文件中。

<filter class="ch.qos.logback.classic.filter.LevelFilter">
  <!-- 过滤的级别 -->
  <level>ERROR</level>
  <!-- 匹配时的操作:记录日志 -->
  <onMatch>ACCEPT</onMatch>
  <!-- 不匹配时的操作:不记录日志 -->
  <onMismatch>DENY</onMismatch>
</filter>

配置参考完整版

除了将错误日志单独分离到 error.log 中,我们还想将 info 级别以上的日志,包括 error 级别的日志记录到 sys.log 中。做法只需要再增加一个 appender,且该 appender 无需配置任何 filter 即可。

最后将完整的配置放到下面,可以直接复制到项目中使用。该配置会将 error 级别的日志放到 error.log,info 及 info 以上的级别的日志放到 sys.log 中。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <!-- 日志存放路径 -->
  <property name="log.path" value="/app/logs" />
  <!-- 日志输出格式 -->
  <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
  
  <!-- 控制台输出 -->
  <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>${log.pattern}</pattern>
    </encoder>
  </appender>
  
  <!-- 系统日志输出 -->
  <appender name="sysLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${log.path}/sys.log</file>
    <!-- 循环政策:基于时间创建日志文件 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- 日志文件名格式 -->
      <fileNamePattern>${log.path}/sys.%d{yyyy-MM-dd}.log</fileNamePattern>
      <!-- 日志最大的历史 60天 -->
      <maxHistory>60</maxHistory>
    </rollingPolicy>
    <encoder>
      <pattern>${log.pattern}</pattern>
    </encoder>
  </appender>
  
  <appender name="errorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${log.path}/error.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
      <maxHistory>60</maxHistory>
    </rollingPolicy>
    <encoder>
      <pattern>${log.pattern}</pattern>
    </encoder>
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>ERROR</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>
  </appender>
  
  <root level="info">
    <appender-ref ref="console" />
  </root>
  
  <root level="info">
    <appender-ref ref="sysLog" />
    <appender-ref ref="errorLog" />
  </root>
</configuration>

可以将多个特定的日志等级记录到日志文件中吗?例如:仅仅将 warn 和 error 级别的日志记录到日志中。一般不会有这种奇葩需求,但是可以做到,仍然使用 filter 就可以做到。

<appender name="sysLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <filter class="ch.qos.logback.classic.filter.LevelFilter">
    <level>WARN</level>
    <onMatch>ACCEPT</onMatch>
    <!-- 不匹配时的操作:不处理 -->
    <onMismatch>NEUTRAL</onMismatch>
  </filter>
  <filter class="ch.qos.logback.classic.filter.LevelFilter">
    <!-- 过滤的级别 -->
    <level>ERROR</level>
    <onMatch>ACCEPT</onMatch>
    <onMismatch>DENY</onMismatch>
  </filter>
</appender>

重点在于第一个 filter 的 <onMismatch>NEUTRAL</onMismatch>NEUTRAL 表示日志级别不匹配时不做任何处理,因此第二个 filter 仍然有机会决定是否记录日志。假设日志级别为 error,那么第一个 filter 不会处理,来到第二个 filter,第二个 filter 检测到日志级别匹配,因此日志得以记录。

有问题吗?点此反馈!

温馨提示:反馈需要登录