Spring Boot -logback 使用

简单使用

依赖

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </dependency>
        <!--转换器log4j 转 logback-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>log4j-over-slf4j</artifactId>
        </dependency>
        <!--过滤日志用到-->
        <dependency>
            <groupId>org.codehaus.janino</groupId>
            <artifactId>janino</artifactId>
        </dependency>
        <!--日志邮件-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-email</artifactId>
            <version>1.5</version>
        </dependency>

配置

#输出日志文件地址
logging.file=E:/LOG/ex.info.log
#日志输出级别
logging.level.root=info
#指定org.springframework.web.servlet.DispatcherServlet类日志级别为DEBUG
logging.level.org.springframework.web.servlet.DispatcherServlet=debug 

开启logback独立配置

#指定logback配置文件路径,如果配置文件在根目录可自动匹配logback-spring.xml,logback.xml
logging.config=classpath:config/logback.xml

logback配置

核心节点简介

节点 说明
root 控制项目整体输出日志级别,子节点为appender
logger 控制指定包或者类的输出级别,和引用的appender,子节点为appender
appender 控制日志输出形式,格式

其它配置

节点 说明
contextName 上下文可在输出的地方用%contextName来引用
property 定义属性可在节点中通过${propertyName}来使用
conversionRule 自定义格式转换符,spring已自定义了彩色日志,异常日志格式直接引用即可

root,logger

root可以理解为一个特定的logger用来控制整个项目的日志输出级别。

logger下可配置0个或多个appender-ref,用于指定选择的日志输出方式

属性名称 说明
name 包名或类名完整路径
level 指定输出级别
addtivity 是否向上级传递信息,默认为true

appender

appender控制日志输出到哪里,用什么形式输出,,后续的例子也可以参考,例子中包含输出到控制台,输出到文件,输出到邮箱。更详细的内容请查看官网文档

属性名称 说明
name appender名称,在logger或root中通过appender-ref来引用
class 处理日志的类

日志信息

日志内容

appender中encoder标签用于控制输出什么内容输出的内容包含很多参数下面列举一些我用到的参数,详细内容请查看官网文档

名称 别名 说明
%date{format} %d 日期,format为格式化方式
%thread %t 线程名
%level %le,%p 日志级别
%logger{length} %lo,%c 打印日志的类,length为输出的长度,如输出类名称过长则会进行缩写
%method %M 打印日志的方法,影响性能谨慎使用
%caller 调用方法的堆栈,有其它参数请参见官网文档
%message %msg,%m 日志内容
%xException %xEx,%xThrowable 异常堆栈,包含包名
%n 当前系统中换行符

日志格式

例子:%-20.30logger 说明

  • -:表示居左,默认居右
  • 20:表示最小长度,不够的补全空格
  • 30:表示最大长度,超出的自动裁剪,logger会简写包名

过滤器

执行一个过滤器会有返回个枚举值,即DENY,NEUTRAL,ACCEPT其中之一。

  • **DENY:**日志将立即被抛弃不再经过其他过滤器
  • **NEUTRAL:**有序列表里的下个过滤器过接着处理日志
  • **ACCEPT:**日志会被立即处理,不再经过剩余过滤器

下面简单介绍一下我使用到的两个过滤器,其它请参考详细文档

  • 日志内容过滤器 ch.qos.logback.core.filter.EvaluatorFilter:通过指定条件来控制是否输出,其中expression为java代码可直接使用java中方法。
<appender name="REQUEST_CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
  <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
   <evaluator> <!-- 默认为 ch.qos.logback.classic.boolex.JaninoEventEvaluator || message.startsWith("Returning handler method")-->
    <expression>
     <![CDATA[
     return (!message.contains(".") && message.startsWith("Looking up handler method")) ;
     ]]>
    </expression>
   </evaluator>
   <OnMatch>ACCEPT</OnMatch>
   <OnMismatch>DENY</OnMismatch>
  </filter>
 </appender>

  • 日志级别过滤器 ch.qos.logback.classic.filter.LevelFilter:通过指定日志级别来过滤
  <filter class="ch.qos.logback.classic.filter.LevelFilter">
   <level>ERROR</level>
   <onMatch>ACCEPT</onMatch>
   <onMismatch>DENY</onMismatch>
  </filter>

logback配置例子

<?xml version="1.0" encoding="UTF-8"?>

<!--
scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration >
 <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
 <property name="log.path.root" value="E:/log/" />
 <!--编码-->
 <property name="log.charset" value="UTF-8" />

 <!-- 控制台财色输出 -->
 <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
 <!-- spring 美化异常输出 -->
 <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
 <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
 <!--日志格式 -->
 <property name="log.pattern.file" value="%d{yyyy-MM-dd HH:mm:ss.SSS}%-5level ${PID:- } --- [%thread] %logger : %msg%n%xException" />
 <property name="log.pattern.error.file" value="%d{yyyy-MM-dd HH:mm:ss.SSS}%-5level ${PID:- } --- [%thread] %logger %method : %msg%n%caller{1..3}%xException" />
 <!-- 彩色日志格式 -->
 <property name="log.pattern.console" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}) %clr(%-5level) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%-10.10thread]){faint} %clr(%-40.40logger{39}){blue} %clr(:){faint} %m%n%xException" />

 <!-- 控制台输出-->
 <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
  <encoder charset="${log.charset}">
   <pattern>${log.pattern.console}</pattern>
  </encoder>
 </appender>
 <!-- info 日志文件 -->
 <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <file>${log.path.root}ex.info.log</file>
  <append>true</append>
  <encoder charset="${log.charset}">
   <pattern>${log.pattern.file}</pattern>
  </encoder>
  <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!-- 滚动策略 大小 策略 -->
   <fileNamePattern>${log.path.root}/%d{yyyy-MM-dd}exinfo-%i.log</fileNamePattern>
   <maxFileSize>10MB</maxFileSize><!-- 单个日志大小 -->
   <maxHistory>30</maxHistory><!--保留的归档文件的最大数量 -->
  </rollingPolicy>
 </appender>
 <!-- warn 日志文件 -->
 <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <file>${log.path.root}ex.error.log</file>
  <append>true</append>
  <encoder charset="${log.charset}">
   <pattern>${log.pattern.error.file}</pattern>
  </encoder>
  <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!-- 滚动策略 大小 策略 -->
   <fileNamePattern>${log.path.root}/%d{yyyy-MM-dd}exerror-%i.log</fileNamePattern>
   <maxFileSize>10MB</maxFileSize><!-- 单个日志大小 -->
   <maxHistory>30</maxHistory><!--保留的归档文件的最大数量 -->
   <totalSizeCap>${total.size.cap}</totalSizeCap>
  </rollingPolicy>
 </appender>

 <!-- 请求日志过滤-->
 <appender name="REQUEST_CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
  <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
   <evaluator> <!-- 默认为 ch.qos.logback.classic.boolex.JaninoEventEvaluator || message.startsWith("Returning handler method")-->
    <expression>
     <![CDATA[
     return (!message.contains(".") && message.startsWith("Looking up handler method")) ;
     ]]>
    </expression>
   </evaluator>
   <OnMatch>ACCEPT</OnMatch>
   <OnMismatch>DENY</OnMismatch>
  </filter>
  <encoder charset="${log.charset}">
   <pattern>${log.pattern.console}</pattern>
  </encoder>
 </appender>

 <appender name="REQUEST_FLOW_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <file>${log.path.root}ex.request.flow.log</file>
  <append>true</append>
  <encoder charset="${log.charset}">
   <pattern>${log.pattern.file}</pattern>
  </encoder>
  <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!-- 滚动策略 大小 策略 -->
   <fileNamePattern>${log.path.root}/%d{yyyy-MM-dd}ex.request.flow-%i.log</fileNamePattern>
   <maxFileSize>10MB</maxFileSize><!-- 单个日志大小 -->
   <maxHistory>30</maxHistory><!--保留的归档文件的最大数量 -->
   <totalSizeCap>${total.size.cap}</totalSizeCap>
  </rollingPolicy>
 </appender>

 <!-- ERROR邮件发送 -->
 <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
  <smtpHost>smtp.126.com</smtpHost>
  <smtpPort>25</smtpPort>
  <username>xx@mail.com</username>
  <password>password</password>
  <asynchronousSending>true</asynchronousSending>
  <SSL>true</SSL>
  <to>xx@mail.com</to>
  <from>xx@mail.com</from>
  <subject>%d{yyyy-MM-dd HH:mm:ss.SSS}错误日志</subject>
  <layout>
   <Pattern>${log.pattern.error.file}}</Pattern>
  </layout>
  <cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
   <!-- 缓冲的日志数量 -->
   <bufferSize>5</bufferSize>
  </cyclicBufferTracker>
       <!-- 这里采用等级过滤器 指定等级相符才发送 -->
  <filter class="ch.qos.logback.classic.filter.LevelFilter">
   <level>ERROR</level>
   <onMatch>ACCEPT</onMatch>
   <onMismatch>DENY</onMismatch>
  </filter>
 </appender>

 <!--系统警告日志打印到单独日志文件-->
 <logger name="com.bmw.frame" level="ERROR" additivity="false">
  <appender-ref ref="CONSOLE" />
  <appender-ref ref="ERROR_FILE" />
 </logger>

 <!--系统警告日志打印到单独日志文件-->
 <logger name="com.example.test" level="TRACE" additivity="false">
  <appender-ref ref="CONSOLE" />
  <appender-ref ref="INFO_FILE" />
 </logger>

 <!-- 1. 输出SQL 到控制台和文件,生产环境视情况打开-->
 <logger name="org.hibernate.SQL" level="DEBUG" additivity="false" >
  <!--<appender-ref ref="CONSOLE" />-->
  <appender-ref ref="INFO_FILE" />
 </logger>

 <!-- 2. 输出SQL 的参数到控制台和文件,生产环境视情况打开-->
 <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE" additivity="false" >
  <!--<appender-ref ref="CONSOLE" />-->
  <appender-ref ref="INFO_FILE" />
 </logger>

 <!--
 3 输出请求路径到文件
 org.springframework.web.servlet.DispatcherServlet 没有请求执行的方法所以使用当前日志
 -->
 <logger name="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" level="DEBUG" additivity="false" >
  <appender-ref ref="REQUEST_CONSOLE" />
  <appender-ref ref="INFO_FILE" />
 </logger>
 <!--
 4 输出请求耗时流水到文件,生产环境视情况打开-->
 -->
 <logger name="org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext" level="TRACE" additivity="false" >
  <appender-ref ref="REQUEST_FLOW_FILE" />
 </logger>
 <!-- 日志输出级别 -->
 <root level="INFO">
  <appender-ref ref="CONSOLE" />
  <appender-ref ref="INFO_FILE" />
 </root>
</configuration>

参考资料

https://aub.iteye.com/blog/1101222

https://logback.qos.ch/manual/layouts.html


上一篇:Java 8中字符串拼接新姿势:StringJoiner


下一篇:Redis分片(分布式缓存)