最全的Logback快速实践

11,684 阅读3分钟

简介

logback是当下最受欢迎的log记录工具,高性能,功能全,文档全,同时作者也log4j的系列的开发者, 本文从logback常用的组件和功能点进行介绍,并提供了简单的例子参考,logback官网


java中如何使用logback

pom.xml中引入关键的两个包

 <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-core -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.2.3</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
            <scope>test</scope>
        </dependency>

然后在resources目录下创建一个logback.xml就可以了,请参考全量的可用配置文件这个章节


日志级别

推荐使用以下几种,级别从高到低排列

Level描述
ERROR错误事件可能仍然允许应用程序继续运行
WARN指定具有潜在危害的情况
INFO指定能够突出在粗粒度级别的应用程序运行情况的信息的消息
DEBUG指定细粒度信息事件是最有用的应用程序调试

Appender级别

What is an Appender?

Appender class dependency

appender

ConsoleAppender (将日志输出到控制台)

将日志信息打印在控制台中

配置类型描述
encoderEncoder日志输出格式
targetString日志输出目标,可以是System.out或者System.err,默认是System.out
withJansiboolean默认是false,这个使用不到,好像是开启后输出的ANSI会有颜色,具体看官网介绍

sample:

<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
    </encoder>
  </appender>

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

FileAppender(将日志输出到文件中)

FileAppender OutputStreamAppender的子类,将日志输出到指定文件中。如果文件已经存在,根据配置属性来判断在末尾追加或者重新生成文件

配置类型描述
appendboolean默认为true,会将日志追加到现有文件末尾
encoderEncoder日志输出格式
fileString文件名,可以带路径,如不过文件或目录不存在则会创建,例如: logs/info.log,该属性没有默认值
immediateFlushboolean一旦有日志产生立即刷新到文件,通过情况下把它设为false,以提高性能,因为会频繁的flush buffer;

sample:

<configuration>
  <!-- 使用时间戳作为文件名 -->
  <timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>testFile-${bySecond}.log</file>
    <append>true</append>
    <!-- set immediateFlush to false for much higher logging throughput -->
    <immediateFlush>true</immediateFlush>
    <!-- encoders are assigned the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>

RollingFileAppender(滚动式输出)

RollingFileAppender继承于FileAppender, 按照一些特定策略生成滚动文件,例如与TimeBasedRollingPolicy策略搭配时,当文件到达指定时间,会重新生成一个新的文件,关于策略,后面章节会有具体详细介绍。

配置类型描述
appendboolean看FileAppender配置
encoderEncoder看FileAppender配置
fileString看FileAppender配置
rollingPolicyRollingPolicy日志滚动策略:配置这个选项会让日志文件按照指定策略进行滚动
triggeringPolicyTriggeringPolicy触发滚动策略:通常搭配rollingPolicy一起使用,用于设置滚动的触发条件

sample:

<appender name="errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>logs/error.log</file>
    <!-- 设置滚动策略 TimeBasedRollingPolicy 按日期滚动 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <!--设置日志命名模式-->
        <fileNamePattern>errorFile.%d{yyyy-MM-dd}.log</fileNamePattern>
        <!--最多保留30天log-->
        <maxHistory>30</maxHistory>
    </rollingPolicy>
    <!-- 超过150MB时,立即触发滚动策略,生成新的文件 -->
    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
        <maxFileSize>150</maxFileSize>
    </triggeringPolicy>
    <encoder>
        <pattern>%d [%p] %-5level %logger - %msg%newline</pattern>
    </encoder>
</appender>

日志文件策略 *Policy(常用)

TimeBasedRollingPolicy(按日期滚动策略)

TimeBasedRollingPolicy 可能是logback最受欢迎的滚动策略,基于时间的滚动,可以是一天也可以是一个月,这个较为常用,通常我们可以设置一天生成一个新的文件,很好归纳,统计

配置类型描述
fileNamePatternStringlog文件命名规则,通常使用%d来按天或按月输出,例如errorFile.%d{yyyy-MM-dd}.log,生成出来的文件类似于errorFile.2018-10-09.log,带上日期后这样每天生成的文件就不会名字重复了,这个还支持选择时区,例如%d{yyyy-MM-dd,UTC}
maxHistoryint日志保留天数,超过该天数的历史日志文件将会被logback异步删除
totalSizeCapint归档文件的总大小,优先应用maxHistory的策略。
cleanHistoryOnStartboolean默认为false,触发归档文件立即删除的动作。

滚动输出支持自动压缩,文件名以.gz或者.zip结尾即可,例如:/wombat/foo.%d.gz

sample:

<configuration>
  <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>

  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>

SizeAndTimeBasedRollingPolicy(按大小和时间滚动策略)

这个应该是最常用的吧,按照指定时间和文件大小的策略来滚动日志。废话不多说看下面的例子

<configuration>
  <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>


  <root level="DEBUG">
    <appender-ref ref="ROLLING" />
  </root>

</configuration>

请注意除“%d”之外的“%i”转换标记。 %i%d令牌都是强制性的。 每当当前日志文件在当前时间段结束之前达到maxFileSize时,它将以增加的索引存档,从0开始


FixedWindowRollingPolicy(以固定的算法策略生成滚动文件 不常用)

这个策略不常用,咱就不多bb了,属性和其他滚动策略是一样的,通常文件命名规范是这样的:tests.%i.log,当到达条件触发滚动时会生成文件test1.log,test2.log,test3.log ...


SizeBasedTriggeringPolicy(根据大小触发滚动的策略)

这个标签里的配置,用来触发滚动时间的,例如文件大小到了指定值,就是触发滚动

sample:

<configuration>
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>test.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
      <fileNamePattern>test.%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>

  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>

fileNamePatten的一些规则(例子,按年,月,日,天,时,分,秒滚动)

例子描述
/wombat/foo.%d按天滚动,格式 年-月-日,都生成在一个文件夹中
/wombat/%d{yyyy/MM}/foo.txt按月滚动,每个月生成一个相同的文件,在不同的月份文件夹中,例如first: /wombat/2018/09/foo.txt,next: /wombat/2018/10/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按指定时区每分钟生成一次
/foo/%d{yyyy-MM,aux}/%d.log每天生成一次,按照年和月区分,例如,/foo/2018-09/中存在一个月的log,log名是每天的日期

pattern配置(日志输出格式化)

例子

下面会介绍一些常用的配置规则。

<encoder>
    <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
  • %-4relative: 将输出日志记录的时间,进行左对齐,宽度为4.
  • %thread: 将输出记录日志的线程号
  • %-5level: 输出5个日志级别,进行左对齐。
  • %logger{35}: 输出日志记录的logger名通常为类名,长度为35。
  • %msg%n: 输出应用程序提供的信息,并换行。

注意:所有关键字在使用的时候必须带上%,如上,-为对其标志

pattern表格

关键字 描述
c{length}
lo{length}
输出logger所属的类目,通常就是所在类的全名,参数为logger名保留长度,默认不填为全名.
%logger com.util.StringUtils com.util.StringUtils
%logger{0} com.util.StringUtils StringUtils
%logger{10} com.util.StringUtils c.u.StringUtils
C{length}
class{length}
和上面用法类似,输出调用者的全名,性能较差,不推荐配置。
contextName
cn|
输出上下文名称
d{pattern}
date{pattern}
输出日志的打印时间,和java中的日期格式化类似
%d 2019-02-12 18:00:00,000
%date 2019-02-12 18:00:00,000
%date{ISO8601} 2019-02-12 18:00:00,000
%date{HH:mm:ss,SSSS} 18:00:00,000
%date{yyyy-MM-dd HH:mm:ss,SSSS} 2019-02-12 18:00:00,000
caller{depth} 输出日志调用者的调用栈深度信息,值越大,输出的栈信息越多
%caller{2} [main]-[INFO]: log test
Caller+0 at com.util.StringUtil.subString(StringUtil.java :22)
Caller+1 at com.util.Main.exec(Main.java :17)
L
line
输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。如不考虑性能问题,可以使用
m
msg
message
应用程序提供的信息
M
method
输出执行日志记录的方法名性能较差,如不考虑性能问题,可以使用
n 输出一个回车换行符,Windows平台为“/r/n”,Unix平台为“/n”
p
le
level
输出日志级别,即DEBUG,INFO,WARN,ERROR,FATAL
t
thread
输出打印日志的线程名
replace(msg){r,t} msg为日志内容,r是正则表达式,将msg中符合r的内容替换成t。
例如:%replace(%msg){'\s',""}
r
relative
输出自应用启动到输出该log信息耗费的毫秒数

配置:

<configuration>

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!-- 日期 [线程] [class类]-[日志级别] log内容 回车符号 -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n</pattern>
        </encoder>

    </appender>

    <!-- 输出INFO及以上的日志 -->
    <root level="INFO">
        <!-- 让自定义的appender生效 -->
        <appender-ref ref="STDOUT"/>
    </root>

</configuration>

控制台输出:

2018-10-09 14:27:55 [main] [org.springframework.web.servlet.handler.SimpleUrlHandlerMapping]-[INFO] Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-10-09 14:27:55 [main] [org.springframework.jmx.export.annotation.AnnotationMBeanExporter]-[INFO] Registering beans for JMX exposure on startup
2018-10-09 14:27:55 [main] [org.apache.coyote.http11.Http11NioProtocol]-[INFO] Starting ProtocolHandler ["http-nio-6677"]
2018-10-09 14:27:55 [main] [org.apache.tomcat.util.net.NioSelectorPool]-[INFO] Using a shared selector for servlet write/read
2018-10-09 14:27:55 [main] [org.springframework.boot.web.embedded.tomcat.TomcatWebServer]-[INFO] Tomcat started on port(s): 6677 (http) with context path ''
2018-10-09 14:27:55 [main] [com.xj.plugins.Springboot2AnalyzeApplication]-[INFO] Started Springboot2AnalyzeApplication in 2.014 seconds (JVM running for 3.949)


控制台输出的log配置颜色

格式描述
%black黑色
%red红色
%green绿色
%yellow黄色
%blue蓝色
%magenta品红
%cyan青色
%white白色
%gray灰色
%highlight高亮色
%bold更鲜艳色颜色,强化以上所有的颜色,例如%boldRed,%boldBlack

例子:

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!-- 日期 [线程] [class类]-[日志级别] log内容 回车符号 -->
            <pattern>%blue(%d{yyyy-MM-dd HH:mm:ss,SSS}) [%cyan(%t)] [%yellow(%c)]-[%highlight(%p)] %m%n</pattern>         
        </encoder>
    </appender>

    <!-- 输出INFO及以上的日志 -->
    <root level="INFO">
        <!-- 让自定义的appender生效 -->
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

配置过后的控制台输出

增加色彩输出


日志定向输出

logback.xml中如何需要将某中日志输出到文件中可以使用过滤器,类似于以下这个例子

xml配置过滤器,例如将error日志输出到error.log中

    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
           <encoder>
               <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] [%c]-[%p] %m%n</pattern>
           </encoder>

           <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
               <!-- rollover daily -->
               <fileNamePattern>${LOG_HOME}/error-%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
               <!-- 文件最大30MB,保留60天,总大小20GB -->
               <maxFileSize>30MB</maxFileSize>
               <maxHistory>60</maxHistory>
               <totalSizeCap>20GB</totalSizeCap>
           </rollingPolicy>

           <!-- 过滤器,只写入error级别log -->
           <filter class="ch.qos.logback.classic.filter.LevelFilter">
               <level>ERROR</level>
               <onMatch>ACCEPT</onMatch>
               <onMismatch>DENY</onMismatch>
           </filter>

       </appender>

如果有需要特殊log需要定向输出的话可以重写 Filter方法

public class MyLogFilter extends Filter<ILoggingEvent> {
       @Override

       public FilterReply decide(ILoggingEvent event) {
           
           if(event.getMessage() != null
                   && (event.getMessage().startsWith("test")
                   || event.getMessage().startsWith("demo"))) {
               return FilterReply.ACCEPT;
           } else {
               return FilterReply.DENY;
           }
       }
   }

然后将filter加入到你的appender中

<!-- 过滤器,写入test和demo开头的日志 -->
<filter class="xx.xxx.xxxx.MyLogFilter" />

关闭类中某个级别的log输出

在logback.xml中加入以下配置

OFF表示全部关闭,可以配置指定级别如INFO,DEBUG...

<logger name="xx.xx.class" level="OFF" />

logback.xml读取环境变量

logback.xml支持两种读取方式,从系统环境中读取,从spring配置文件中读取

读取系统环境变量 通过${envName}方式获取

<!-- 从系统环境变量读取日志输出目录 -->
<property name="LOG_HOME" value="${log.dir}"/>

读取spring配置文件的方式

<!-- 从context中读取所以不需要使用${}获取 -->
<springProperty scope="context" name="LOG_HOME" source="logback.dir"/>

默认值设置

如果在环境变量中没有取到LOG_HOME 的值,则会使logs作为默认值,和Shell语法中设置默认值类似

<file>${LOG_HOME:-logs}/test/test-info.log</file>

-

全量的可用配置文件

以下配置会生成三个日志文件,具体的策略是:每天会生成一个新的文件,当天日志文件达到指定大小会自动压缩,并且生成新的文件进行记录。

  • main.log(只记录info级别及以上的日志输出)
  • warn.log(只记录warn级别的日志输出)
  • error.log(只记录error级别的日志输出)
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
    <!-- 从spring中获取配置,如获取不到会使用默认值 -->
    <springProperty scope="context" name="LOG_HOME" source="logging.path"/>
    <springProperty scope="context" name="LOG_LEVEL" source="logging.output.level"/>
    <springProperty scope="context" name="LOG_MAX_SIZE" source="logging.file.max-size"/>
    <springProperty scope="context" name="LOG_TOTAL_SIZE_CAP" source="logging.file.total-size-cap"/>
    <springProperty scope="context" name="LOG_MAX_HISTORY" source="logging.file.max-history"/>
    <!-- 输出样式 -->
    <property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] [%logger{10}]-[%p] %m%n"/>

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%blue(%d{yyyy-MM-dd HH:mm:ss.SSS}) [%cyan(%t)] [%yellow(%logger{10})]-[%highlight(%p)] %m%n</pattern>
        </encoder>
    </appender>

    <appender name="Main-Log" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME:-logs}/logback/main.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <FileNamePattern>${LOG_HOME:-logs}/logback/main-%d{yyyy-MM-dd}_%i.log.zip</FileNamePattern>
            <MaxHistory>${LOG_MAX_HISTORY:-30}</MaxHistory>
            <MaxFileSize>${LOG_MAX_SIZE:-10MB}</MaxFileSize>
            <totalSizeCap>${LOG_TOTAL_SIZE_CAP:-10GB}</totalSizeCap>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>


    <appender name="Error-Log" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME:-logs}/logback/error.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <FileNamePattern>${LOG_HOME:-logs}/logback/error-%d{yyyy-MM-dd}_%i.log.zip</FileNamePattern>
            <MaxHistory>${LOG_MAX_HISTORY:-30}</MaxHistory>
            <MaxFileSize>${LOG_MAX_SIZE:-10MB}</MaxFileSize>
            <totalSizeCap>${LOG_TOTAL_SIZE_CAP:-10GB}</totalSizeCap>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>

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

    <appender name="Warn-Log" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME:-logs}/logback/warn.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <FileNamePattern>${LOG_HOME:-logs}/logback/warn-%d{yyyy-MM-dd}_%i.log.zip</FileNamePattern>
            <MaxHistory>${LOG_MAX_HISTORY:-30}</MaxHistory>
            <MaxFileSize>${LOG_MAX_SIZE:-10MB}</MaxFileSize>
            <totalSizeCap>${LOG_TOTAL_SIZE_CAP:-10GB}</totalSizeCap>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
        <!-- log filter -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    
    <!-- 关闭类中某个级别的输出 OFF全部关闭 , INFO,DEBUG ...
    <logger name="x.x.Constants">
        <level value="OFF"/>
    </logger> 
    -->

    <!-- log output level -->
    <root level="${LOG_LEVEL:-INFO}">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="Main-Log"/>
        <appender-ref ref="Warn-Log"/>
        <appender-ref ref="Error-Log"/>
    </root>

</configuration>