简记

  1. logback 是 springboot 到目前5.0 版本默认的日志框架, 是log4j的升级
  2. 异步性能效果不是很明显,性能不如 log4j2

    配置说明

    LogBack配置文件可以分为几个节点,其中 Configuration 是根节点,Appender、Logger、Root是Configuration的子节点。

configuration


    1. 根节点, 可选参数, 开启定时扫描并更新配置
    2. debug 开启时将打印logback自身日志

      appender

    3. 负责写日志的组件。appender有两个必要属性name、class 。name指定appender的名称,class指定appender的全限定名class,主要包括:

ch.qos.logback.core.ConsoleAppender 控制台输出
ch.qos.logback.core.FileAppender 文件输出
ch.qos.logback.core.RollingFileAppender 文件滚动输出

consoleAppender

把日志添加到控制台,有如下节点:

  1. - <encoder> : 对日志进行格式化。
  2. - <target> : 字符串System.out 或者 System.err, 默认 System.out;

FileAppender

把日志添加到文件,有如下节点:

  - <file>:被写入的文件名,可以是相对目录      , 也可以是绝对目录 , 如果目录不存在则会自动创建。
  - <append>:如果是true ,      日志被追加到文件结尾 , 如果是false,清空现存文件 , 默认是true。
  - <encoder>:对日志进行格式化    

rollingFileAppender

滚动纪录文件,先将日志记录到指定文件,当符合某种条件时,将日志记录到其他文件,有如下节点:

  - <file>:被写入的文件名,可以是相对目录,也可以解决目录,如果目录不存在则自动创建。
  - <append>:如果是true,日志被追加到文件结尾,如果是false,清空现存文件,默认是true。
  - <encoder>:对日志进行格式化。<br />
  - <rollingPolicy>:当发生滚动时,决定      RollingFileAppender 的行为,涉及文件移动和重命名。<br />
     - ch.qos.logback.core.rolling.TimeBasedRollingPolicy    
        - 最常用的滚动策略,根据时间来制定滚动策略,**即负责滚动也负责触发滚动**。有如下节点;<br />
     - ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy
        - 基于时间+大小进行滚动。是对于第一种的补充。避免单个日志文件过大,不便于阅读
     - ch.qos.logback.core.rolling.FixedWindowRollingPolic
        - 基于窗口滚动, 可以理解成自定义滚动规则,避免使用出现单个文件过大或者日志文件过多的情况。**需要同时配置triggeringPolicy用于指定滚动触发规则**
  - <triggeringPolicy>  配合基于窗口滚动策略使用 , 用于通知何时触发滚动    
     - 官方只有一个策略实现类   ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy   
     - 观察当前活动文件的大小,如果已经大于了指定的值,它会给 RollingFileAppender 发一个信号触发对当前活动文件的轮转。
        - 只接收 maxFileSize 这一个参数,它的默认值是 10 MB。
        - maxFileSize 可以为字节,千字节,兆字节,千兆字节,通过在数值后面指定一个后缀 KB,MB 或者 GB。例如,5000000,5000KB,5MB 以及 2GB 都是有效的,前三个是一样的。

fileNamePattern的介绍

/wombat/foo.%d :
每天轮转(晚上零点)。由于省略了指定 %d 的日期格式,所以默认为 yyyy-MM-dd。
/wombat/%d{yyyy/MM}/foo.txt:
每个月开始的时候轮转。
/wombat/foo.%d{yyyy-ww}.log:
每周的第一天(取决于时区)轮转。
/wombat/foo%d{yyyy-MM-dd_HH}.log:
每小时轮转。
/wombat/foo%d{yyyy-MM-dd_HH-mm}.log:
每分钟轮转。
/wombat/foo%d{yyyy-MM-dd_HH-mm, UTC}.log:
每分钟轮转,时间格式为UTC。
/foo/%d{yyyy-MM, aux}/%d.log:
每天轮转。归档文件在包含年月的文件夹下。
任何斜杆或者反斜杠够会被当作文件夹分隔符。任何必要的文件夹都会在有需要的时候创建。可以将日志文件放在单独的文件夹中。
TimeBasedRollingPolicy支持文件自动压缩。如果 fileNamePattern以 .gz 或者 .zip结尾,将会启动这个特性。
例如:/wombat/foo.%d.gz:每天轮转(晚上零点),自动将归档文件压缩成 GZIP 格式

三种滚动策略

  <!-- 三种滚动策略-->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>logFile.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- daily rollover -->
      <fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
      <!-- keep 30 days' worth of history capped at 3GB total size -->
      <maxHistory>30</maxHistory>
      <totalSizeCap>3GB</totalSizeCap>
    </rollingPolicy>
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender>

  <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <file>mylog.txt</file>
      <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <!-- rollover daily -->
        <fileNamePattern>mylog-%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
         <!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
         <maxFileSize>100MB</maxFileSize>    
         <maxHistory>60</maxHistory>
         <totalSizeCap>20GB</totalSizeCap>
      </rollingPolicy>
      <encoder>
        <pattern>%msg%n</pattern>
      </encoder>
    </appender>

  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <file>test.log</file>
      <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
        <fileNamePattern>tests.%i.log.zip</fileNamePattern>
        <minIndex>1</minIndex>
        <maxIndex>3</maxIndex>
      </rollingPolicy>

      <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
        <maxFileSize>5MB</maxFileSize>
      </triggeringPolicy>
      <encoder>
        <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
      </encoder>
    </appender>

常用的Pattern变量

<!-- 常用的Pattern变量-->
</encoder>
      <pattern>
          %d{yyyy-MM-dd HH:mm:ss} [%level] - %msg%n
          Logger: %logger
          Class: %class
          File: %file
          Caller: %caller
          Line: %line
          Message: %m
          Method: %M
          Relative: %relative
          Thread: %thread
          Exception: %ex
          xException: %xEx
          nopException: %nopex
          rException: %rEx
          Marker: %marker
          %n

      </pattern>      
</encoder>

filter

  1. **级别过滤器(LevelFilter)**
     1. ch.qos.logback.classic.filter.LevelFilter
     1. LevelFilter 根据记录级别对记录事件进行过滤。如果事件的级别等于配置的级别,过滤 器会根据 onMatch 和 onMismatch 属性接受或拒绝事件。<br />
  2. **临界值过滤器(ThresholdFilter)**
     1. ch.qos.logback.classic.filter.ThresholdFilter
     1. 过滤掉低于指定临界值的事件
  3. **求值过滤器(EvaluatorFilter)**
     1. ch.qos.logback.classic.filter.EvaluatorFilter
     1. 评估是否符合指定的条件
     1. 子节点  evaluator    和 matcher   设置条件, 不常用

logger

设置某一个包或者具体的某一个类的日志打印级别,以及指定。logger仅有一个name属性,两个可选属性 level/addtivity。
可以包含零个或多个appender-ref,表示这个appender将会添加到logger。

  • name:用来指定受此loger约束的某一个包或者具体的某一个类。
  • level:用来设置打印级别,大小写无关。可选值有TRACE、DEBUG、INFO、WARN、ERROR、ALL和OFF。还有一个特俗值INHERITED 或者 同义词NULL,代表强制执行上级的级别。如果未设置此属性,那么当前logger将会继承上级的级别。
  • addtivity:是否向上级logger传递打印信息,默认为true;设置为false 时,name指定的包和类的日志将不被 root配置的appender打印,当自身也不配置appender时,将没有日志输出

    root

    元素配置根logger。该元素有一个level属性,没有name属性,因为已经被命名 为root。Level属性的值大小写无关,其值为下面其中一个字符串:TRACE、 DEBUG, INFO、 WARN、ERROR、ALL 和 OFF。如果 root 元素没 有引用任何 appender,就会失去所有 appender。

附 完整配置

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <springProperty scope="context" name="logPath" source="web.upload-path"/>
    <property name="LOG_HOME" value="logback-logs"/>
    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%line - %msg%n</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <!--控制台的输出级别,生产环境使用INFO只打印少量日志和异常信息 ,debug 日志在 data/logs/dev.log, 没有异常信息-->
            <level>DEBUG</level>
        </filter>
    </appender>

    <!-- 按照每天生成日志文件 -->
    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/error/error.log.%d{yyyy-MM-dd}.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%line - %msg%n</pattern>
        </encoder>
        <!--日志文件最大的大小-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10MB</MaxFileSize>
        </triggeringPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印错误日志 -->
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/warn/warn.log.%d{yyyy-MM-dd}.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%line - %msg%n</pattern>
        </encoder>
        <!--日志文件最大的大小-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10MB</MaxFileSize>
        </triggeringPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印错误日志 -->
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/info/info.log.%d{yyyy-MM-dd}.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%line - %msg%n</pattern>
        </encoder>
        <!--日志文件最大的大小-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10MB</MaxFileSize>
        </triggeringPolicy>

        <filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印INFO日志 -->
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/debug/debug.log.%d{yyyy-MM-dd}.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%line - %msg%n</pattern>
        </encoder>
        <!--日志文件最大的大小-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10MB</MaxFileSize>
        </triggeringPolicy>

        <filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印DEBUG日志 -->
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <appender name="TRACE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/trace/trace.log.%d{yyyy-MM-dd}.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%line - %msg%n</pattern>
        </encoder>
        <!--日志文件最大的大小-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10MB</MaxFileSize>
        </triggeringPolicy>

        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>TRACE</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <appender name="DEV" class="ch.qos.logback.core.FileAppender">
        <file>${LOG_HOME}/dev.log</file>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%line - %msg%n</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <!--标准日志文件只记录debug以上级别日志-->
            <level>DEBUG</level>
        </filter>
    </appender>


    <!--日志文件采用异步输出-->
    <appender name="ASYNC-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
        <queueSize>256</queueSize>
        <!-- 添加附加的appender,最多只能添加一个 -->
        <appender-ref ref="INFO"/>
    </appender>
    <appender name="ASYNC-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
        <queueSize>256</queueSize>
        <!-- 添加附加的appender,最多只能添加一个 -->
        <appender-ref ref="DEBUG"/>
    </appender>
    <appender name="ASYNC-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
        <queueSize>256</queueSize>
        <!-- 添加附加的appender,最多只能添加一个 -->
        <appender-ref ref="ERROR"/>
    </appender>
    <appender name="ASYNC-WARN" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
        <queueSize>256</queueSize>
        <!-- 添加附加的appender,最多只能添加一个 -->
        <appender-ref ref="WARN"/>
    </appender>

    <appender name="ASYNC-TRACE" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
        <queueSize>256</queueSize>
        <!-- 添加附加的appender,最多只能添加一个 -->
        <appender-ref ref="TRACE"/>
    </appender>

    <appender name="ASYNC-DEV" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
        <queueSize>256</queueSize>
        <!-- 添加附加的appender,最多只能添加一个 -->
        <appender-ref ref="DEV"/>
    </appender>

    <!--降低部分有大量日志的依赖的日志级别-->
    <logger additivity="false" name="org.activiti" level="TRACE">
        <appender-ref ref="ASYNC-ERROR"/>
        <appender-ref ref="ASYNC-WARN"/>
    </logger>
    <logger additivity="false" name="druid.sql" level="TRACE">
        <appender-ref ref="ASYNC-ERROR"/>
        <appender-ref ref="ASYNC-WARN"/>
    </logger>
    <logger additivity="false" name="org.hibernate" level="TRACE">
        <appender-ref ref="ASYNC-ERROR"/>
        <appender-ref ref="ASYNC-WARN"/>
    </logger>
    <logger additivity="false" name="org.freeswitch" level="TRACE">
        <appender-ref ref="ASYNC-ERROR"/>
        <appender-ref ref="ASYNC-WARN"/>
    </logger>
    <logger additivity="false" name="com.alibaba" level="TRACE">
        <appender-ref ref="ASYNC-ERROR"/>
        <appender-ref ref="ASYNC-WARN"/>
    </logger>
    <logger additivity="false" name="org.apache" level="TRACE">
        <appender-ref ref="ASYNC-ERROR"/>
        <appender-ref ref="ASYNC-WARN"/>
    </logger>
    <logger additivity="false" name="org.snaker" level="TRACE">
        <appender-ref ref="ASYNC-ERROR"/>
        <appender-ref ref="ASYNC-WARN"/>
    </logger>
    <logger additivity="false" name="springfox" level="TRACE">
        <appender-ref ref="ASYNC-ERROR"/>
        <appender-ref ref="ASYNC-WARN"/>
    </logger>
    <logger additivity="false" name="org.springframework" level="TRACE">
        <appender-ref ref="ASYNC-ERROR"/>
        <appender-ref ref="ASYNC-WARN"/>
    </logger>
    <logger additivity="false" name="org.elasticsearch" level="TRACE">
        <appender-ref ref="ASYNC-ERROR"/>
        <appender-ref ref="ASYNC-WARN"/>
    </logger>
    <logger additivity="false" name="freemarker" level="TRACE">
        <appender-ref ref="ASYNC-ERROR"/>
        <appender-ref ref="ASYNC-WARN"/>
    </logger>
    <logger additivity="false" name="io.netty" level="TRACE">
        <appender-ref ref="ASYNC-ERROR"/>
        <appender-ref ref="ASYNC-WARN"/>
    </logger>

    <logger additivity="false" name="ws.schild" level="TRACE">
        <appender-ref ref="ASYNC-ERROR"/>
        <appender-ref ref="ASYNC-WARN"/>
    </logger>

    <!-- 日志输出级别 -->
    <root level="DEBUG">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="ASYNC-ERROR"/>
        <appender-ref ref="ASYNC-WARN"/>
        <appender-ref ref="ASYNC-INFO"/>
        <appender-ref ref="ASYNC-DEBUG"/>
        <appender-ref ref="ASYNC-DEV"/>
    </root>

</configuration>