SpringBoot从入门到进阶——学会Logback日志的配置和搭建

内容html

  从实际项目需求出发,以最快的速度实现SpringBoot下Logback的配置。而后前后实践测试了SpringBoot内置的基础配置(SizeBasedTriggeringPolicy)、按时间划分日志文件的配置(TimeBasedRollingPolicy) 、同时按时间和大小划分日志文件的配置(SizeAndTimeBasedRollingPolicy)、不一样级别日志输出到不一样日志文件四种状况。java

版本git

  IDE:IDEA 2017.2.2 x64github

​  JDK:1.8.0_171spring

  manve:3.3.3app

  SpringBoot:1.5.9.RELEASEide

  Logback:1.1.11(SpringBoot中适配的版本)post

适合人群测试

  Java开发人员idea

说明

  转载请说明出处:SpringBoot从入门到进阶——学会Logback日志的配置和搭建

  GitHub仓库:https://github.com/leo-zz/SpringBootDemo

参考

  官方文档中filters内容: https://Logback.qos.ch/manual/filters.html

  官方文档中appenders内容:https://Logback.qos.ch/manual/appenders.html

注意

  修改过电脑时间后,intelij idea的光标没法聚焦到代码区,须要重启 intelij idea才能继续编写代码。

步骤

快速配置出项目所需的Logback

项目对于日志的要求:

  一般,咱们对于项目的日志会有以下要求:

  一、时效性:保存30天

  二、按时间分割:每一个小时生成1个文件夹

  三、按大小分割:每一个日志文件大小不超过50MB

  四、限定体积:日志文件总大小20GB

  五、按级别分割:不一样级别的日志保存到不一样的文件中

  下面,咱们先基于这些常见的需求,搭建出一个SpringBoot项目。

Logback配置:

application.yaml
#其余配置
... 
#指明日志存放位置,在jar包所在路径下的logs文件夹中
logging:
  file: logs/application-gatewayservice-${server.port}.logs
logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
     <!-- 引入SpringBoot的默认配置文件defaults.xml -->
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring.log}"/>
    <!-- 引入SpringBoot中内置的控制台输出配置文件console-appender.xml -->
    <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
    <!-- 引入自定义的文件输出配置文件logback-spring-file-level.xml -->
    <include resource="logback-spring-file-level.xml" />
    
    <!-- 设置root logger的级别为INFO,并将控制台输出和文件输出中的appender都添加到root logger下 -->
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="INFO_FILE" />
        <appender-ref ref="WARN_FILE" />
        <appender-ref ref="ERROR_FILE" />
    </root>
    <jmxConfigurator/>
</configuration>
logback-spring-file-level.xml
<?xml version="1.0" encoding="UTF-8"?>
<included>
    <!--只输出INFO Level到日志文件的appender-->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名,%i用来标记分割日志的序号 -->
            <fileNamePattern>${LOG_FILE}.INFOLevel.%d{yyyy-MM-dd_HH}.%i.log</fileNamePattern>
            <!-- 单个日志文件最大50MB, 保存30天的日志, 日志文件空间为20GB -->
            <maxFileSize>50MB</maxFileSize>
            <maxHistory>30</maxHistory>
            <totalSizeCap>20GB</totalSizeCap>
        </rollingPolicy>
        <!--配置日志的级别过滤器,只保留INFO Level的日志-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <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} - %msg%n</pattern>
        </encoder>
    </appender>

    <!--只输出WARN Level到日志文件的appender-->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- %i用来标记分割日志的序号 -->
            <fileNamePattern>${LOG_FILE}.WARNLevel.%d{yyyy-MM-dd_HH}.%i.log</fileNamePattern>
            <!-- 单个日志文件最大50MB, 保存30天的日志, 日志文件空间为20GB -->
            <maxFileSize>50MB</maxFileSize>
            <maxHistory>30</maxHistory>
            <totalSizeCap>20GB</totalSizeCap>
        </rollingPolicy>
        <!--配置日志的级别过滤器,只保留WARN Level的日志-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>

     <!--只输出ERROR Level到日志文件的appender-->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- %i用来标记分割日志的序号 -->
            <fileNamePattern>${LOG_FILE}.ERRORLevel.%d{yyyy-MM-dd_HH}.%i.log</fileNamePattern>
            <!-- 单个日志文件最大50MB, 保存30天的日志, 日志文件空间为20GB -->
            <maxFileSize>50MB</maxFileSize>
            <maxHistory>30</maxHistory>
            <totalSizeCap>20GB</totalSizeCap>
        </rollingPolicy>
        <!--配置日志的级别过滤器,只保留ERROR Level的日志-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>
</included>

  项目启动后,日志文件会保留在jar包所在路径下的logs文件夹中,而且按照日志级别,输出到不一样的文件中。

  同时,每小时会生成一个日志文件,若是当日志文件的大小超过50MB时,会分割日志文件。日志系统会保留30天的日志文件,且当全部日志文件的大小超过20GB时,日志系统会在下一天的0时,删除部分日志文件,使日志文件整体的大小控制在20GB之内。

  项目源码地址:FastConfig

 

SpringBoot内置的基础配置:

application.yaml

#指明日志存放位置
logging:
  file: logs/application-gatewayservice-${server.port}.logs

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/base.xml"/>
    <jmxConfigurator/>
</configuration>

  其中的base.xml,引自SpringBoot的jar包中的基础配置:

1540955132065

base.xml

  能够看到base.xml中引入了defaults.xml,以及控制台输出日志配置文件console-appender.xml和文件输出日志配置文件file-appender.xml。

<?xml version="1.0" encoding="UTF-8"?>
<!--Base logback configuration provided for compatibility with Spring Boot 1.1-->
<included>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring.log}"/>
    <include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
    <include resource="org/springframework/boot/logging/logback/file-appender.xml"/>
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="FILE"/>
    </root>
</included>

  defaults.xml和console-appender.xml在本示例中不作讨论。

file-appender.xml

  经过文件输出日志配置文件,能够看到默认状况下SpringBoot的日志系统限定单个文件大小为10MB。

<?xml version="1.0" encoding="UTF-8"?>
<included>
    <appender name="FILE" class="ch.qos.Logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
        </encoder>
        <file>${LOG_FILE}</file>
        <rollingPolicy class="ch.qos.Logback.core.rolling.FixedWindowRollingPolicy">
            <fileNamePattern>${LOG_FILE}.%i</fileNamePattern>
        </rollingPolicy>
        <triggeringPolicy class="ch.qos.Logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10MB</MaxFileSize>
        </triggeringPolicy>
    </appender>
</included>

打印日志的测试接口

@Controller public class LogController { ​ Logger logger=Logger.getLogger("LogController"); @GetMapping("/log") @ResponseBody public String testLog(){ for (int i=0;i<1000;i++) logger.info(String.valueOf(i)); return "999"; } }

SizeBasedTriggeringPolicy的测试

  使用Postman进行日志接口的重复调用,此处请求100次"/log"。

1540956372674

  日志文件超过10MB,日志系统会自动分割日志文件,使得单个文件大小在10MB之内。

1540956468416

  配置文件的fileNamePattern{LOG_FILE}.%i中的i为序号。

  经过本例的测试可知,最先的日志文件,序号越大,每次分割文件时,全部日志文件的序号都会更新。最先的日志文件序号始终是最大的。

  若是删除了旧的日志文件,会发生什么呢?

1540956737704

  使用Postman再次调用日志测试接口生成日志,能够看到日志系统会从新编号。

1540956900748

  观察大小10MB的日志文件,其中大约9.6W行数据。所以平均一行的日志大概104个字节。

1540956057238

  项目源码地址:DefaultConfig

按时间划分日志文件

  SpringBoot内置的日志系统使用SizeBasedTriggeringPolicy将日志文件在占用空间的维度进行分割。下面咱们使用TimeBasedRollingPolicy,将日志文件按时间维度进行分割,示例保留了3天的日志,而且日志文件的最大容量为20MB。

  项目配置文件application.yaml不变。

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration><include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring.log}"/>
    <include resource="org/springframework/boot/logging/logback/console-appender.xml" /><include resource="logback-spring-file.xml" /><root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
    </root>
    <jmxConfigurator/>
</configuration>

logback-spring-file.xml

<?xml version="1.0" encoding="UTF-8"?>
<included>
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 此处的${LOG_FILE}是yaml文件中配置的logging.file属性 %d{yyyy-MM-dd_HH}区分了年月日以及小时-->
            <FileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd_HH}.log</FileNamePattern>
            <!-- 日志文件保留近3天,而且最大容量为20MB -->
            <MaxHistory>3</MaxHistory>
            <totalSizeCap>20MB</totalSizeCap>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>
</included>

  注意:file-appender的配置,位置必定要放在<ROOT>标签以前,不然报以下错误:

  java.lang.IllegalStateException: Logback configuration error detected:

  Could not find an appender named [FILE]. Did you define it below instead of above in the configuration file?

TimeBasedRollingPolicy测试

测试totalSizeCap

  开启项目后运行一段时间,能够观察到日志文件会按照FileNamePattern中规定的最小时间周期HH(小时)分割日志文件。

1540968935404

  使用Postman调用日志测试接口生成日志,使单个日志文件的大小超过20MB。

1540969062304

​   整点事后,发现13点和14点的日志文件被删除,剩余日志文件的大小保持在20MB之内。

1540969597549

  由此测试可知配置文件中totalSizeCap的含义:全部日志文件的大小在一个计时周期内(小时HH)能够超过totalSizeCap设定的容量,可是在下一个计时周期开始时,日志系统会清理日志文件,确保日志文件整体的大小在totalSizeCap之内。

测试MaxHistory

  当日志容量不超过totalSizeCap时,更改系统日期为10月30日,10月31日,11月1日,11月2日,并调用日志测试接口生成日志。

1541057233143

  当记录11月2日的日志时,日志系统会清除11月1日的日志文件,保留10月30日、10月31日、11月2日三天的日志。

1541143729656

  再将日期改为11月10日,调用日志测试接口生成日志,日志系统会清除11月2日的日志文件,保留10月30日、10月31日、11月10日三天的日志。因而可知MaxHistory只是限定保存日志的天数,而不是限定保存最近天然日日志的天数,

1540971323304

  经过上面的观察能够发现,在新的日志计时周期到来时,若是全部日志文件大小之和超过totalSizeCap,或日志记录天数超过MaxHistory。日志系统会优先删除最近日期的日志文件,使的日志大小在totalSizeCap内,且日志记录天数在MaxHistory内。

  项目源码地址:TimeBasedConfig

同时按时间和大小划分日志文件的配置

  配置文件application.yaml不变。

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!--<include resource="org/springframework/boot/logging/logback/base.xml"/>-->
    <!--测试按照时间分割日志文件-->
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring.log}"/>
    <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
    <include resource="logback-spring-file.xml" />
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
    </root>
    <jmxConfigurator/>
</configuration>

Logback-spring-file.xml

<?xml version="1.0" encoding="UTF-8"?>
<included>
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- %i用来标记分割日志的序号 -->
            <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd_HH}.%i.log</fileNamePattern>
            <!-- 单个日志文件最大10MB, 保存3天的历史日志, 全部日志文件最大50MB -->
            <maxFileSize>10MB</maxFileSize>
            <maxHistory>3</maxHistory>
            <totalSizeCap>50MB</totalSizeCap>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>
</included>

SizeAndTimeBasedRollingPolicy测试

​   项目启动后的日志信息:

1540973544860

测试maxFileSize:

  调用日志测试接口生成日志,当单个日志文件大小超过10MB时,会新建日志文件存储超过10MB部分的日志内容,而且新日志文件的序号大于旧日志文件的序号(序号规则与Spring内置使用的SizeBasedTriggeringPolicy相反)。

1540974375988

测试maxHistory:

  分别更改系统日期为10月30日,10月31日,11月1日,11月2日并调用日志测试接口生成日志。

1541061122949

  当记录11月2日的日志时,日志系统会清除11月1日的日志文件,保留10月30日,10月31日,11月2日三天的日志。

1541147624399

测试totalSizeCap:

  调用日志测试接口生成日志,使全部日志文件大小之和超过50MB。此时日志仍然在记录,日志文件大小还在增加。1541148062409

  将系统时间调至1小时后,继续调用日志测试接口生成日志,日志文件大小超过60MB,此时日志仍然在记录,日志文件大小还在增加。

1541151848427

  将系统时间调至1天后,日志系统进行了日志文件的清理,日志系统清除了11月2日的日志文件,保留10月30日,10月31日,11月3日三天的日志,并使的日志文件大小在50MB范围内。

1541152118166

  可见此示例中SizeAndTimeBasedRollingPolicy清理的周期(一天)与TimeBasedRollingPolicy不一样(一个小时)。

  项目源码地址:SizeAndTimeBasedConfig

 

按日志级别输出到不一样的文件中

  配置文件application.yaml不变。

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!--测试按照时间分割日志文件-->
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring.log}"/>
    <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
    <include resource="logback-spring-file-level.xml" /><root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="INFO_FILE" />
        <appender-ref ref="WARN_FILE" />
        <appender-ref ref="ERROR_FILE" />
    </root>
    <jmxConfigurator/>
</configuration>

logback-spring-file-level.xml

<?xml version="1.0" encoding="UTF-8"?>
<included>
    <!--只保留INFO Level的日志-->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- %i用来标记分割日志的序号 -->
            <fileNamePattern>${LOG_FILE}.INFOLevel.%d{yyyy-MM-dd_HH}.%i.log</fileNamePattern>
            <!-- 单个日志文件最大10MB, 保存3天的历史日志, 全部日志文件最大50MB -->
            <maxFileSize>10MB</maxFileSize>
            <maxHistory>3</maxHistory>
            <totalSizeCap>50MB</totalSizeCap>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender><!--只保留 WARN Level的日志-->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- %i用来标记分割日志的序号 -->
            <fileNamePattern>${LOG_FILE}.WARNLevel.%d{yyyy-MM-dd_HH}.%i.log</fileNamePattern>
            <!-- 单个日志文件最大10MB, 保存3天的历史日志, 全部日志文件最大50MB -->
            <maxFileSize>10MB</maxFileSize>
            <maxHistory>3</maxHistory>
            <totalSizeCap>50MB</totalSizeCap>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender><!--保留ERROR Level的日志-->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- %i用来标记分割日志的序号 -->
            <fileNamePattern>${LOG_FILE}.ERRORLevel.%d{yyyy-MM-dd_HH}.%i.log</fileNamePattern>
            <!-- 单个日志文件最大10MB, 保存3天的历史日志, 全部日志文件最大50MB -->
            <maxFileSize>10MB</maxFileSize>
            <maxHistory>3</maxHistory>
            <totalSizeCap>50MB</totalSizeCap>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>
</included>

Controller

@Controller public class TestLogController { ​ Logger logger=Logger.getLogger("TestLogController"); @GetMapping("/logInfo") @ResponseBody public String testLog(){ for (int i=0;i<1000;i++) logger.info(String.valueOf(i)); return "999"; } ​ @GetMapping("/logWarn") @ResponseBody public String testLogWarn(){ for (int i=0;i<1000;i++) logger.warning(String.valueOf(i)); return "999"; } ​ @GetMapping("/logError") @ResponseBody public String testLogError(){ for (int i=0;i<1000;i++) logger.severe(String.valueOf(i)); return "999"; } }

按日志级别输出到不一样文件的测试:

  前后调用测试接口 http://localhost:7081/logInfohttp://localhost:7081/logWarnhttp://localhost:7081/logError,分别记录INFO、WARN、ERRER级别的日志。

1540979202660

  INFO日志

1540979424835

  WARN日志

1540979390962

  ERRER日志

1540979340871

  可见,经过定义多个Appender,结合filter实现了不一样级别的日志输出到不一样文件中。

  项目源码地址:LevelConfig

相关文章
相关标签/搜索