Spring Boot日志logback

jasmine 于 2020-05-01 发布

1、集成springboot过程

SpringBoot中只识别resource目录下四中文件:

如果需要对配置文件名进行修改,或者希望把放到其它目录下, 可以在application中通过logging.config属性来指定, 如logging.config=classpath:config/my-log-config.xml。

resource下添加配置文件logback-spring.xml

spring-boot-starter-web中已包含logback依赖

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!--配置日志的上下文名称-->
    <contextName>${log.context.name}</contextName>
    <!-- 常量定义start -->
    <!--项目名称,也是存储日志的具体目录-->
    <property name="log.context.name" value="xxx"/>
    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <property name="log.directory" value="./logs/${log.context.name}"/>
    <!--日志的字符编码-->
    <property name="log.charset" value="UTF-8"/>
    <!--历史记录最大保存天数-->
    <property name="log.maxHistory" value="30"/>
    <!--最大单个日志大小-->
    <property name="log.maxSize" value="1gb"/>
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
    <property name="log.pattern"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS}$$${HOSTNAME}$$%level{}$$${log.context.name}$$[%thread]$$%logger{50}$$%msg%n"/>
    <!--日志Error级别名称配置-->
    <property name="log.error.log.level" value="ERROR"/>
    <!--异步写日志的队列大小配置,默认为256-->
    <property name="log.async.queue.size" value="512"/>
    <!-- 常量定义end -->

    <!--控制台日志输出配置,可以匹配色彩和高亮-->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="com.xxx.conifg.log.MyEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{50}) - %yellow([%file:%line]) - %msg%n
            </pattern>
            <charset>${log.charset}</charset>
        </encoder>
    </appender>

    <!-- 服务器上使用的appender start -->
    <!-- 默认的file appender,按天切分日志 -->
    <!-- 打印INFO以上轻量日志,被ELK收集 -->
    <appender name="ROLLING_FILE_DEFAULT" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.directory}/${HOSTNAME}.log</file>
        <append>true</append>
        <prudent>true</prudent>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <!-- 仅INFO以上通过 -->
            <level>INFO</level>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${log.directory}/${HOSTNAME}_application.%d{yyyy-MM-dd}.%i.log
            </fileNamePattern>
            <maxHistory>${log.maxHistory}</maxHistory>
            <maxFileSize>${log.maxSize}</maxFileSize>
        </rollingPolicy>
        <encoder class="com.xxx.conifg.log.MyEncoder">
            <pattern>${log.pattern}</pattern>
            <charset>${log.charset}</charset>
        </encoder>
    </appender>

    <!-- 错误日志,按天切分 -->
    <appender name="ROLLING_FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>${log.error.log.level}</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <file>${log.directory}/${HOSTNAME}_error.log</file>
        <!-- 日志追加配置 -->
        <append>true</append>
        <prudent>true</prudent>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.directory}/${HOSTNAME}_error.%d{yyyy-MM-dd}.log
            </fileNamePattern>
            <maxHistory>${log.maxHistory}</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录error级别的 -->
        <encoder class="com.xxx.conifg.log.MyEncoder">
            <pattern>${log.pattern}</pattern>
            <charset>${log.charset}</charset>
        </encoder>
    </appender>

    <!-- debug级别日志,按大小切分 -->
    <appender name="ROLLING_FILE_DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <append>true</append>
        <prudent>true</prudent>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${log.directory}/${HOSTNAME}_debug.%d{yyyy-MM-dd}.%i.log
            </fileNamePattern>
            <maxHistory>${log.maxHistory}</maxHistory>
            <maxFileSize>${log.maxSize}</maxFileSize>
        </rollingPolicy>
        <encoder class="com.xxx.conifg.log.MyEncoder">
            <pattern>${log.pattern}</pattern>
            <charset>${log.charset}</charset>
        </encoder>
    </appender>


    <!-- 异步默认日志文件的配置 -->
    <appender name="ASYNC_FILE_DEFAULT" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
        <!--<discardingThreshold>0</discardingThreshold>-->
        <!-- 20180830 将异步记录日志的方式改为可以丢失ERROR级别以下 -->
        <discardingThreshold>-1</discardingThreshold>
        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
        <queueSize>${log.async.queue.size}</queueSize>
        <appender-ref ref="ROLLING_FILE_DEFAULT"/>
    </appender>
    <appender name="ASYNC_FILE_DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <queueSize>${log.async.queue.size}</queueSize>
        <appender-ref ref="ROLLING_FILE_DEBUG"/>
    </appender>
    <!-- 异步错误日志文件的配置 -->
    <appender name="ASYNC_FILE_ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
        <!--<discardingThreshold>0</discardingThreshold>-->
        <!-- 20180830 将异步记录日志的方式改为可以丢失ERROR级别以下 -->
        <discardingThreshold>-1</discardingThreshold>
        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
        <queueSize>${log.async.queue.size}</queueSize>
        <appender-ref ref="ROLLING_FILE_ERROR"/>
    </appender>

    <!-- sql mapper -->
    <logger name="com.xxx.repository.mapper" level="DEBUG" additivity="false">
        <springProfile name="!dev">
            <appender-ref ref="ASYNC_FILE_ERROR"/>
        </springProfile>
<!--        <springProfile name="dev">-->
<!--            <appender-ref ref="STDOUT"/>-->
<!--        </springProfile>-->
    </logger>

    <logger name="com.xxx" level="DEBUG" additivity="false">
        <springProfile name="!dev">
            <appender-ref ref="ASYNC_FILE_DEBUG"/>
            <appender-ref ref="ASYNC_FILE_DEFAULT"/>
            <appender-ref ref="ASYNC_FILE_ERROR"/>
        </springProfile>
        <springProfile name="dev">
            <appender-ref ref="STDOUT"/>
        </springProfile>
    </logger>

    <root level="info">
        <springProfile name="local,dev">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="ASYNC_FILE_DEFAULT"/>
            <appender-ref ref="ASYNC_FILE_ERROR"/>
        </springProfile>
        <springProfile name="!dev">
            <appender-ref ref="ASYNC_FILE_DEFAULT"/>
            <appender-ref ref="ASYNC_FILE_ERROR"/>
        </springProfile>
    </root>
</configuration>

springboot中也提供了配置文件的简单配置(只支持简单配置)

2、标签说明

configuration标签

配置文件的根标签,定义Logback的全局配置。

属性:

<!-- 输出logback的本身状态数据 -->
<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />

子标签:

contextName标签

用来设置上下文名称,每个logger都关联到logger上下文,默认上下文名称为default。 但可以使用<contextName>设置成其他名字,用于区分不同应用程序的记录。一旦设置,不能修改

property标签

定义配置文件中的变量,可在其他标签中使用

  • 可包含属性:name, value

属性:

子标签:无

Appender标签

日志输出器,将日志事件输出到指定目标的组件,负责将日志消息传递给特定的目标,如文件、控制台、网络等。

属性:

有8个输出实现如下:

1)ConsoleAppender:将日志输出到控制台

子节点:

<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <!--格式化输出:%d表示日期,%thread表示线程名,%highlight()高亮显示,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) [%logger{15}:%line] - %msg%n</pattern>
        <charset>UTF-8</charset>
    </encoder>
</appender>

2)FileAppender:将日志输出到文件

子节点:

示例:

<appender name="FILE" class="ch.qos.logback.core.FileAppender">  
    <file>testFile.log</file>   
    <append>true</append>  
    <encoder>  
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>  
    </encoder>  
</appender>  

3)RollingFileAppender:将日志输出到滚动文件,可以配置文件的大小、保留文件的数量等

子节点:

滚动策略详解:
a)SizeAndTimeBasedRollingPolicy(根据时间和文件大小的滚动策略),最常用的滚动策略,根据时间再根据文件大小来滚动生成文件

子节点:

<!--当前项目的目录下-->
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <!-- rollover daily -->
        <fileNamePattern>${LOG_HOME}/mylog-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
        <!-- 每个文件最多5MB,保存60天的历史记录,但最多20GB -->
        <maxFileSize>5MB</maxFileSize>
        <maxHistory>60</maxHistory>
        <totalSizeCap>20GB</totalSizeCap>
    </rollingPolicy>
    <encoder>****
        <pattern>%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} - %msg%n</pattern>
        <charset>UTF-8</charset>
    </encoder>
</appender>

b)TimeBasedRollingPolicy(根据时间的滚动策略),根据时间的滚动策略,既负责滚动也负责触发滚动

子节点:

例:每天生成一个日志文件,保存30天的

<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <FileNamePattern>d://log/business.log.%d.log</FileNamePattern>
        <maxHistory>30</maxHistory>
    </rollingPolicy>
    <encoder>
        <pattern>%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} - %msg%n</pattern>
        <charset>UTF-8</charset>
    </encoder>
</appender>

c)FixedWindowRollingPolicy(固定窗口的滚动策略),根据固定窗口算法重命名文件的滚动策略

子节点:

fileNamePattern :必须包含“%i”例如,假设最小值和最大值分别为1和2,命名模式为 mylog%i.log,会产生归档文件mylog1.log和mylog2.log。还可以指定文件压缩选项,例如,mylog%i.log.gz 或者 没有log%i.log.zip。

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

4)SocketAppender:将日志通过网络发送到远程主机的特定端口

项目中的日志采用的是基于ELK来进行日志管理配置如下:

<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>debug</level>
    </filter>
    <destination>192.168.0.11:5061</destination>
    <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder">
        <customFields>{"project": "springboot-logback-elk"}</customFields>
    </encoder>
</appender>

注意:在pom文件中引入logstash-logback-encoder依赖。

<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
    <version>5.1</version>
</dependency>

5)SMTPAppender:通过电子邮件方式发送日志

6)SyslogAppender:将日志发送到 Syslog 服务器

7)DBAppender:将日志存储到数据库中

8)AsyncAppender:将日志异步输出到其他Appender

子节点:

示例:

<!-- 异步输出 -->
<appender name="ASYNCDEBUG" class="ch.qos.logback.classic.AsyncAppender">
    <!-- 默认如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志,若要保留全部日志,设置为0 -->
    <discardingThreshold>0</discardingThreshold>
    <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
    <queueSize>1024</queueSize>
    <!-- 添加附加的appender,最多只能添加一个 -->
    <appender-ref ref="DEBUGFILE"/>
    <includeCallerData>true</includeCallerData>
</appender>

filter标签

Appender内子标签,过滤器,Appender标签中的子标签,用任意条件对日志进行过滤,可以有多个,按照配置顺序执行

常见过滤器:

a)LevelFilter级别过滤器,根据日志级别进行过滤
子节点:

其中onMatch和onMismatch有三个值: DENY(日志将立即被抛弃不再经过其他过滤器), NEUTRAL(有序列表里的下个过滤器过接着处理日志), ACCEPT(日志会被立即处理,不再经过剩余过滤器)

示例:

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">   
    <filter class="ch.qos.logback.classic.filter.LevelFilter">   
      <level>INFO</level>   
      <onMatch>ACCEPT</onMatch>   
      <onMismatch>DENY</onMismatch>   
    </filter>   
</appender>   

b)ThresholdFilter临界值过滤器,过滤掉低于指定临界值的日志, 当日志级别等于或高于临界值时,过滤器返回NEUTRAL;当日志级别低于临界值时,日志会被拒绝。

例如:过滤掉所有低于INFO级别的日志。 示例:

  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">   
    <!-- 过滤掉 TRACE 和 DEBUG 级别的日志-->   
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">   
      <level>INFO</level>   
    </filter>   
  </appender>  

c)EvaluatorFilter求值过滤器,评估、鉴别日志是否符合指定条件。 需要额外的两个JAR包,commons-compiler.jar和janino.jar 子节点:

例如:过滤掉所有日志消息中不包含“billing”字符串的日志。

<configuration>   
   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">   
    <filter class="ch.qos.logback.core.filter.EvaluatorFilter">         
      <evaluator> <!-- 默认为 ch.qos.logback.classic.boolex.JaninoEventEvaluator -->   
        <expression>return message.contains("billing");</expression>   
      </evaluator>   
      <OnMatch>ACCEPT </OnMatch>  
      <OnMismatch>DENY</OnMismatch>  
    </filter>   
    <encoder>   
      <pattern>   
        %-4relative [%thread] %-5level %logger - %msg%n   
      </pattern>   
    </encoder>   
  </appender>   
</configuration>  

encoder标签

Appender内子标签,定义日志输出的格式及编码方式,

该格式化字符串的常用占位符如下:

示例:

<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
    <!--引用属性配置管理中定义的某个属性-->
    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}$$${HOSTNAME}$$%level{}$$${log.context.name}$$[%thread]$$%logger{50}$$%msg%n</pattern>
    <charset>utf-8</charset>
</encoder>

logger标签

用于指定目标目录下,类日志输出的级别以及指定那些输出器

子标签:

属性:

additivity示例:

    <logger name="com.gf.order.service.impl" level="info" additivity="true">
        <appender-ref ref="STDOUT"/>
    </logger>

    <logger name="com.gf.order.service" level="debug" additivity="true">
        <appender-ref ref="STDOUT"/>
    </logger>

    <root level="debug">
        <appender-ref ref="STDOUT"/>
    </root>


输出:

        x.y.z--- DEBUG com.gf.order.controller.OrderController - =====OrderController=====debug=====
        x.y.z--- INFO  com.gf.order.controller.OrderController - =====OrderController=====info=====
        x.y.z--- WARN  com.gf.order.controller.OrderController - =====OrderController=====warn=====
        x.y.z--- ERROR com.gf.order.controller.OrderController - =====OrderController=====error=====
        x.y --- DEBUG com.gf.order.service.OrderService - =====[OrderService]=====debug=====
        root--- DEBUG com.gf.order.service.OrderService - =====[OrderService]=====debug=====
        x.y --- INFO  com.gf.order.service.OrderService - =====[OrderService]=====info=====
        root--- INFO  com.gf.order.service.OrderService - =====[OrderService]=====info=====
        x.y --- WARN  com.gf.order.service.OrderService - =====[OrderService]=====warn=====
        root--- WARN  com.gf.order.service.OrderService - =====[OrderService]=====warn=====
        x.y --- ERROR com.gf.order.service.OrderService - =====[OrderService]=====error=====
        root--- ERROR com.gf.order.service.OrderService - =====[OrderService]=====error=====
        x.y.z--- INFO  com.gf.order.service.impl.Haha - =====《Haha》=====info=====
        x.y --- INFO  com.gf.order.service.impl.Haha - =====《Haha》=====info=====
        root--- INFO  com.gf.order.service.impl.Haha - =====《Haha》=====info=====
        x.y.z--- WARN  com.gf.order.service.impl.Haha - =====《Haha》=====warn=====
        x.y --- WARN  com.gf.order.service.impl.Haha - =====《Haha》=====warn=====
        root--- WARN  com.gf.order.service.impl.Haha - =====《Haha》=====warn=====
        x.y.z--- ERROR com.gf.order.service.impl.Haha - =====《Haha》=====error=====
        x.y --- ERROR com.gf.order.service.impl.Haha - =====《Haha》=====error=====
        root--- ERROR com.gf.order.service.impl.Haha - =====《Haha》=====error=====

root标签

定义根记录器,用于指定所有未匹配到具体记录器的日志输出规则

属性:

子节点: appender-ref:指定输出器

其中日志级别:ALL < TRACE < DEBUG < INFO < WARN < ERROR <FATAL <OFF

shutdownHook标签

定义Logback的关闭钩子

statusListener标签

定义状态监听器,用于监听Logback的状态变化

3、MDC分布式应用追踪请求

logback提供了MDC(Mapped Diagnostic Contexts诊断上下文映射),可以让开发人员在诊断上下文中放置信息。 通过ThreadLocal实现了线程与线程之间的数据隔离。在输出时可以通过标识符%X{key}来输出MDC中设置的内容。

分布式应用追踪请求实现思路如下:

WEB拦截器添加唯一ID==》添加ID到MDC中==》调用其他服务时ID作为Header参数 ==》输出日志添加ID参数==》请求结束清除ID==》根据相同ID排查日志

相关地址:https://blog.csdn.net/wo541075754/article/details/109193354