日志logback详解

news2024/11/16 3:36:36

该篇博客是我参考了很多博客总结出来的,内容很多,你能看完不睡着算你厉害!

一、日志框架发展史

二、日志规范

三、日志级别

四、Logback

4.1 Maven引入

4.2 logback-spring.xml是在哪里加载的?

4.3 logback.xml和logback-spring.xml区别

五、logback-spring.xml格式详解

5.1 完整格式

5.2 configuration

5.2.1 定时器是如何生效的?

5.3 contextName

5.4 property/springProperty

5.5 timestamp

5.6.logger和root

5.6.1 说明

5.6.2.appender-ref

5.7 appender

5.7.1 ConsoleAppender

5.7.2 FileAppender

5.7.3 RollingFileAppender

5.7.3.1  TimeBasedRollingPolicy

5.7.3.2 SizeBasedTriggeringPolicy

5.7.3.3 FixedWindowRollingPolicy

5.7.3.4 SizeAndTimeBasedRollingPolicy

5.8 encoder说明

5.8.1 %n

5.8.2 %c %lo %logger

5.8.3 %C %class

5.8.4.%d %date

5.8.5.%caller

5.8.6.%L %line

5.8.9 %m %msg %message

5.8.8.%M %method

5.8.9 %p %le %level

5.8.10 %r %relative

5.8.11.%t %thread

5.8.12 %replace

6.8.13 宽度设置

5.8.14.显示设置

5.8.14.1.%clr和defaults.xml

5.8.14.2.支持的颜色

5.9 filter

5.9.1 LevelFilter

5.9.2 ThresholdFilter

5.9.3 EvaluatorFilter

5.9.4 自定义过滤器

六、优化异常堆栈stack

6.1 未优化前

6.2.优化


一、日志框架发展史

参考博客:

【精选】Java日志框架的发展历史,你不想了解一下吗_java日志历史-CSDN博客 [Java日志框架的发展历史,你不想了解一下吗]

第1阶段:只有System.out 与System.error

第2阶段:Apache大佬Ceki Gülcü 搞了个 Log4j,爆火

第3阶段:Sun眼红Log4j, 自己制定一套标准JUL  (Java Util Logging),没啥人用

第4阶段:Apache不服,也自己制定一套标准JCL (Jakarta Commons Logging), 可以在Log4j和JUL之间切换,但存在问题。

第5阶段,大佬Ceki Gülcü离开Apache公司,觉得JCL不好用,自己搞了个Slf4j (Simple Logging Facade For Java 简单日志门面)。但想要Apache和Sun来对接Slf4j太难,于是弄了桥接包,通过桥接包来帮助Slf4j接口与其他日志库建立关系,这种方式称桥接设计模式。

但仍然存在一个问题:日志配置文件未做统一,假如你的系统使用了Slf4j作为日志接口,使用Log4j作为日志产品,则配置文件需要配2份。

Ceki Gülcü发话: 没事,大家都选择用Slf4j统一吧,我来帮大家统一,没有事是桥接包解决不了的,有的话,那就再来个。

第6阶段:Ceki Gülcü 巨佬觉得市场上的日志标准库都是间接实现Slf4j接口,也就是说每次都需要配合桥接包,也就是之前的日志产品都不是正统的Slf4j的实现。

因此在2006年,Ceki Gülcü 基于Slf4j接口写出了Logback日志标准库

第7阶段:Slf4j+Logback的模式,显然很冲击JCL+Log4j,并且本身Logback确实比Log4j性能更优,设计更为合理,所以,老东家Apache可就坐不住了。

   在2012年,Apache直接推出新项目,不是Log4j1.x升级,而是新项目Log4j2,因为Log4j2是完全不兼容Log4j1.x的。

   并且很微妙的,Log4j2几乎涵盖Logback所有的特性(这不是对着干是啥~而且还有抄袭的嫌疑哈哈哈),更甚者的Log4j2也搞了分离的设计,分化成log4j-api和log4j-core这个log4j-api也是日志接口,log4j-core才是日志产品

二、日志规范

参考博客

https://www.cnblogs.com/yangyongjie/p/16230247.html [Java日志规范]

1、【强制】应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架 (SLF4J)中的 API,使用门面模式的日志框架。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component
public class SpringUtil implements ApplicationContextAware {
    private static final Logger log = LoggerFactory.getLogger(SpringUtil.class);
}

或者使用lombok注解:

import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class SpringUtil implements ApplicationContextAware {
}

2、【强制】所有日志文件至少保存15天,因为有些异常具备以“周”为频次发生的特点。日志文件格式为: {logname}.log.{保存日期},日期格式:yyyy-MM-dd,例如info.log.2023-04-21

3、【强制】对 trace/debug/info 级别的日志输出,必须使用条件输出形式或者使用占位符的方式。

错误示例:(如果日志级别是 warn,该日志不会打印,但是会执行字符串拼接操作,如果 symbol 是对象,会执行 toString()方法,浪费了系统资源,但最终日志却没有打印)

log.debug("Processing trade with id: " + id + " and symbol: " + symbol);

解决方法一:打印日志前加上判断:

if (log.isInfoEnabled()) {
    log.info("Processing trade with id: " + id + " and symbol: " + symbol);
}
if (log.isWarnEnabled()) {
    log.warn("Processing trade with id: " + id + " and symbol: " + symbol);
}
if (log.isDebugEnabled()) {
    log.debug("Processing trade with id: " + id + " and symbol: " + symbol);
}

解决方法二(推荐使用)使用参数化形式{}占位,[] 进行参数隔离因为 String 字符串的拼接会使用 StringBuilder 的 append()方式,有一定的性能损耗。使用占位符仅是替换动作,可以有效提升性能。

log.debug("Processing trade with id: [{}] and symbol: [{}]", id, symbol);

4、【强制】生产环境禁止直接使用 System.out 或 System.err 输出日志或使用 e.printStackTrace()打印异常堆栈。

5、【强制】生产环境禁止打印debug日志

6、【建议】打印日志不要使用JSON.toJSONString()写法,而是通过重写对象的toString()方法(可以使用lombok的 @ToString(callSuper=true))。

错误示例:

log.info("基础数据拉取sc:{},mqJson:{}", dockDTO.getLeelenNeighNo(), JSON.toJSONString(amcBaseInfoPo));

正确示例:

log.info("基础数据拉取sc:{},mqJson:{}", dockDTO.getLeelenNeighNo(), amcBaseInfoPo);

三、日志级别

参考博客

日志打印的8种级别(很详细)_日志级别-CSDN博客[日志打印的8种级别(很详细)]

log4j定义了8个级别的log,优先级从高到低依次为:

OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL
如果日志设置为L,一个级别为P的输出日志只有当P >= L时日志才会输出。

Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG

四、Logback

参考博客:

logback 日志 介绍和配置详解_logback日志配置-CSDN博客 [logback 日志 介绍和配置详解]

万字详解logback日志框架,再没这么全的了!-腾讯云开发者社区-腾讯云 [万字详解logback日志框架,再没这么全的了!]

logback详解 - 知乎[logback详解]

(三)Logback中的Appender - 程序员大本营[(三)Logback中的Appender]

Java日志框架:logback详解 - 知乎[Java日志框架:logback详解]

logback -- 配置详解 -- 三 -- <encoder>[logback -- 配置详解 -- 三 -- <encoder>]

logback 配置颜色高亮_黑帽子技术的博客-CSDN博客[logback 配置颜色高亮]

LogBack 基本使用_凯凯JAVA的博客-CSDN博客[LogBack 基本使用]

(六)Logback中的Filter_logback filter-CSDN博客[(六)Logback中的Filter]

logback logback.xml常用配置详解(三) <filter>-CSDN博客[logback logback.xml常用配置详解(三) <filter>]

RollingFileAppender详解[RollingFileAppender详解]

logback解析——Appender - 简书[logback解析——Appender]

4.1 Maven引入

Spring Boot 默认使用 SLF4J+Logback 记录日志。

1、springBoot已经帮我们引入了logback包,所以我们不需要再去引用。

2、在项目资源文件夹 resources 下 创建 logback-spring.xml 文件。logback 将会自动读取该配置文件文件。

logback是springboot自带的日志框架.该框架主要有3个模块:

logback-core:核心代码块

logback-classic:实现了slf4j的api,加入该依赖可以实现log4j的api。

logback-access:访问模块与servlet容器集成提供通过http来访问日志的功能(也就是说不需要访问服务器,直接在网页上就可以访问日志文件,实现HTTP访问日志的功能)。

maven已经帮我们集成好了,只需引用:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.5.RELEASE</version>
    <relativePath/>
</parent>
<dependencies>
<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

点击进入spring-boot-starter-web,可以看到:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter</artifactId>
  <version>2.2.5.RELEASE</version>
  <scope>compile</scope>
</dependency>

点击进入spring-boot-starter包,可以看到:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-logging</artifactId>
  <version>2.2.5.RELEASE</version>
  <scope>compile</scope>
</dependency>

点击进入spring-boot-starter-logging,可以看到:

<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.2.3</version>
  <scope>compile</scope>
</dependency>

4.2 logback-spring.xml是在哪里加载的?

参考博客

springboot 源码阅读之 logback-spring.xml 是在哪里加载的?_logback-spring加载流程-CSDN博客 [springboot 源码阅读之 logback-spring.xml 是在哪里加载的?]

随便在logback-spring.xml写个错误:

<configuration scan="true" scanPeriod="10 seconds" debug="false">
    <a></a>
</configuration>

启动报错:

Exception in thread "main" java.lang.IllegalStateException: Logback configuration error detected: 
ERROR in ch.qos.logback.core.joran.spi.Interpreter@2:8 - no applicable action for [a], current ElementPath  is [[configuration][a]]
	at org.springframework.boot.logging.logback.LogbackLoggingSystem.loadConfiguration(LogbackLoggingSystem.java:169)
	at org.springframework.boot.logging.AbstractLoggingSystem.initializeWithConventions(AbstractLoggingSystem.java:80)
	at org.springframework.boot.logging.AbstractLoggingSystem.initialize(AbstractLoggingSystem.java:60)
	at org.springframework.boot.logging.logback.LogbackLoggingSystem.initialize(LogbackLoggingSystem.java:118)
	at org.springframework.boot.context.logging.LoggingApplicationListener.initializeSystem(LoggingApplicationListener.java:313)
	at org.springframework.boot.context.logging.LoggingApplicationListener.initialize(LoggingApplicationListener.java:288)
	at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEnvironmentPreparedEvent(LoggingApplicationListener.java:246)
	at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEvent(LoggingApplicationListener.java:223)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127)
	at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:76)
	at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:53)
	at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:345)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
	at com.top.whysu.web.system.SystemWebApplication.main(SystemWebApplication.java:17)

进入LogbackLoggingSystem.java第169行,不断debug发现

1、org.springframework.boot.logging.logback.LogbackLoggingSystem定了4个默认配置文件:

@Override
protected String[] getStandardConfigLocations() {
   return new String[] { "logback-test.groovy", "logback-test.xml", "logback.groovy", "logback.xml" };
}

从这里可以看出来读取顺序是:logback-test.groovy,  logback-test.xml, logback.groovy, logback.xml

2、org.springframework.boot.logging.AbstractLoggingSystem这边先判断4个默认配置文件是否存在,如果不存的话,则加上-spring后缀再查询。

4.3 logback.xml和logback-spring.xml区别

参考博客

logback.xml和logback-spring.xml的区别_logback-spring和logback.xml-CSDN博客 [logback.xml和logback-spring.xml的区别]

https://www.cnblogs.com/huangdh/p/16778065.html [logback.xml和logback-spring.xml的区别]

【精选】附加:logback日志组件中,logback.xml和logback-spring.xml的区别;(本篇博客并没有得出明确的结论……)_logback.xml和配置文件的区别’-CSDN博客 [附加:logback日志组件中,logback.xml和logback-spring.xml的区别;]

我们使用SLF4J框架记录日志时,会用到 logback.xml 和 logback-spring.xml 两个不同的配置文件。

1、logback-spring.xml 只有在Spring应用程序运行的时候才生效,即带有@SpringBootApplication注解的类启动的时候才会生效。

     如果不是Spring应用程序,而是一个main方法或者一个JUnit的测试方法,要用 logback.xml 来配置。

2、存放的位置不同:

    logback-spring.xml存放的位置是在SpringApplication主类所在的项目的resources目录,也就是application.yml或者application.properties所在的目录

     logback.xml存放的位置是在你启动的那个类所在的项目的resources目录。

3、二者的加载顺序是:logback.xml—>application.properties—>logback-spring.xml。如果你在logback.xml定义了变量,而恰好这个变量又被写在了application.properties中,那么就有可能会获取不到,因为application.properties在logback.xml的后面执行。这也是为什么springboot推荐使用logback-spring.xml来替代logback.xml来配置。

五、logback-spring.xml格式详解

5.1 完整格式

logback的日志配置文件格式如下所示:

<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <property name="glmapper-name" value="glmapper-demo" />
    <contextName>${glmapper-name}</contextName>
    <appender>
        //xxxx
    </appender>
    <logger>
        //xxxx
    </logger>
    <root>
        //xxxx
    </root>
</configuration> 

5.2 configuration

根节点<configuration>,包含下面三个属性:

scan: 默认值为true。当此属性设置为true时,配置文件如果发生改变,将会被重新加载。

scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。如可以设置为scanPeriod="30 seconds"表示每30秒检测一次。

debug: 默认值false。当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。

<configuration scan="true" scanPeriod="30 seconds" debug="false">
</configuration>

5.2.1 定时器是如何生效的?

把debug设置为true

<configuration scan="true" scanPeriod="30 seconds" debug="true">

发现启动的时候打印了一句:

16:09:09,385 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - Setting ReconfigureOnChangeTask scanning period to 30 seconds

打开类 ch.qos.logback.classic.joran.action.ConfigurationAction;

发现的确有个定时器:

5.3 contextName

<contextName>标签作用是用来设置日志上下文的名称,可以用来区分不用应用程序。

5.4 property和springProperty

1、通过property元素可定义变量。它有name和value两个属性。

可以通过“${name}”来使用变量。

<property name="LOG_HOME" value="/home/smart-community-docking/scd/logs"/>

如果你是在windows上启动的话,然后你的项目在D盘,则日志会生成在D:\home\smart-community-docking\scd\logs目录下。

2、使用springProperty的话,值是可以从配置文件application.properties里面取值的。

例如现在有application.propertis定义了值:

spring.application.name=smart-community-docking

则可以通过springProperty获取到该值:

<configuration scan="true" scanPeriod="30 seconds" debug="false">
    <springProperty scope="context" name="APP_NAME" source="spring.application.name" defaultValue="smart-community-docking"/>
    <contextName>${APP_NAME}</contextName>
</configuration>

5.5 timestamp

用来获取时间戳字符串。这个属性很少使用。

有两个属性key和datePattern。

key: 标识此<timestamp> 的名字;

datePattern: 设置将当前时间(解析配置文件的时间)转换为字符串的模式,遵循 java.txt.SimpleDateFormat的格式。

<configuration scan="true" scanPeriod="30 seconds" debug="false">
   <timestamp key="currentDate" datePattern="yyyy-MM-dd" />
</configuration>

5.6.logger和root

5.6.1 说明

logger:

  • name属性:用来指定logger约束的包或者具体类。
  • level属性:用于设置日志打印级别。RACE,DEBUG,INFO,WARN,ERROR,ALll和OFF还有INHERITED(NULL)。如果没有设置则默认为(null)会继承上级的级别
  • addtivity属性:是否向上级logger传递打印信息,默认为true。如果设置为true,在输出日志时,你会发现控制台会输出两遍。所以一般设置additivity为false
<!-- 指定包-->
<logger name="com.top.scd.controller"/>
<!-- 指定类-->
<logger name="com.top.scd.controller.UserController" level="DEBUG" additivity="true"/>
  • <root>也是<logger>元素

  • 它的name就是ROOT。所以只能配置level属性

  • level属性的取值范围只能取 TRACE, DEBUG, INFO, WARN, ERROR, ALL, OFF。

  • level默认是DEBUG。

5.6.2.appender-ref

<logger>和<root> 标签下允许有0个或者多个 <appender-ref>

<appender-ref>只有一个ref 用于指定<appender>标签。

5.7 appender

appender用来定义日志的输出格式,过滤规则,以及日志文件如何生成。

有2个属性name 和class。

name当然是appender的名称啦。

class对应的是实现类。目前有如下三种常用的类:ConsoleAppender,FileAppender,RollingFileAppender。你会发现loback-core.jar包下真的有这3个类。

5.7.1 ConsoleAppender

ConsoleAppender:日志输出到控制台,类名ch.qos.logback.core.FileAppender。

属性名

类型

备注

encoder

ch.qos.logback.core.encoder.Encoder

对日志进行格式化。

使用<pattern>指定格式。具体格式见后面章节。

<charset>指定字符编码。

target

String

有效值为System.out或者System.err,默认为System.out。一般不写。

示例:

注意:禁止向除了ConsoleAppender之外的appender配置彩色日志。

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="1 seconds" debug="false">
<!--${CONSOLE_LOG_PATTERN}在这个文件里面引用的-->
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debug</level>
        </filter>
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
    </root>
</configuration>

5.7.2 FileAppender

FileAppender:日志输出到文件,类名ch.qos.logback.core.FileAppender。

属性名

类型

备注

file

String

被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值

append

boolean

如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。

encoder

ch.qos.logback.core.encoder.Encoder

对日志进行格式化。

使用<pattern>指定格式。具体格式见后面章节。

<charset>指定字符编码。

prudent

boolean

如果是 true,日志会被安全的写入文件(即使其他的FileAppender也在向此文件做写入操作),效率低,默认是 false。

示例:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="1 seconds" debug="false">
    <!--定义日志路径,如果是windows启动并且代码在D盘, 则日志会生成于D:\home\smart-community-docking\scd\logs下-->
    <property name="LOG_HOME" value="/home/smart-community-docking/scd/logs"/>
    <appender name="file" class="ch.qos.logback.core.FileAppender">
        <!--日志格式配置-->
        <encoder>
            <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
        </encoder>
        <!--日志输出路径-->
        <file>${LOG_HOME}/logback.log</file>
        <!--默认日志被追加到文件结尾-->
        <append>true</append>
    </appender>
    <root level="INFO">
        <appender-ref ref="file"/>
    </root>
</configuration>

5.7.3 RollingFileAppender

RollingFileAppender:滚动记录文件,FileAppender的子类。

先将日志文件指定到文件,当符合某个条件时,将日志记录到其他文件

类名:ch.qos.logback.core.rolling.RollingFileAppender。

属性名

类型

备注

file

String

被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值

append

boolean

如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。

rollingPolicy

ch.qos.logback.core.rolling.RollingPolicy

当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名

属性class定义具体的滚动策略类

triggeringPolicy

ch.qos.logback.core.rolling.TriggeringPolicy

告知 RollingFileAppender 何时激活滚动

这个要配合具体的rollingPolicy使用,不同的rollingPolicy会有所不同。目前有用到的就只有SizeBasedTriggeringPolicy。

encoder

ch.qos.logback.core.encoder.Encoder

对日志进行格式化。

使用<pattern>指定格式。具体格式见后面章节。

<charset>指定字符编码。

prudent

boolean

当为true时,不支持FixedWindowRollingPolicy。支持TimeBasedRollingPolicy,但是有两个限制,1不支持也不允许文件压缩,2不能设置file属性,必须留空。

这里有如下常用的4种滚动策略:TimeBasedRollingPolicy,SizeBasedTriggeringPolicy,FixedWindowRollingPolicy,SizeAndTimeBasedRollingPolicy

5.7.3.1  TimeBasedRollingPolicy

时间滚动策略  ch.qos.logback.core.rolling.TimeBasedRollingPolicy

可以基于时间滚动按时间生成日志

属性名

类型

备注

fileNamePattern

String

定义了归档日志文件的名字。

1、它的值由文件名%d的占位转换符组成,如果没有指定时间和日期格式,默认为yyyy-MM-dd。(由java.text.SimpleDateFormat进行格式化)。

2、轮转周期通过fileNamePattern推断出来的。可以指定多个 %d,但是只能有一个是主要的,用于推断轮转周期,其它的 %d 占位符必须通过 'aux' 标记为辅助的。

例如:/var/log/%d{yyyy/MM,aux}/myapplication.%d{yyyy-MM-dd}.log

3、也可以指定时区:%d{yyyy-MM-dd_HH-mm, UTC},如果指定的时区timezone不能被识别或者拼写错误的话,将会根据TimeZone.getTimeZone(String)方法指定为 GMT。

举例:

/foo.%d  默认%d格式是yyyy-MM-dd,按天滚动。

/%d{yyyy/MM}/foo.log 按月滚动

/%d{yyyy-MM-dd_HH}.log  按小时滚动

/%d{yyyy-MM-dd_HH-mm, UTC}.log 按分钟滚动

/%d{yyyy-MM, aux}/%d.log  按天滚动

maxHistory

int

表示日志文件保存的最大数量。

例如:如果根据fileNamePattern判断出来是按天滚动,该值设为30,则日志文件最多保存30天。

totalSizeCap

int

来控制所有归档文件总的大小。当达到这个大小后,旧的归档文件将会被异步的删除。

使用这个属性时还需要设置 maxHistory 属性。而且,maxHistory 将会被作为第一条件,该属性作为第二条件。

cleanHistoryOnStart

boolean

如果设置为 true,那么在 appender 启动的时候,归档文件将会被删除。默认的值为false。

下面是一些例子:

文件命名格式

滚动计划

备注

/wombat/foo.%d

按日滚动

%d默认是yyyy-MM-dd格式。

昨天:/wombat/foo.2023-04-22

今天:/wombat/foo.2023-04-23

如果RollingFileAppender设置了<file>属性,则当前的日志会被打印到file配置的文件中。例如如果<file>值为/wombat/aaaa.txt, 则:

昨天:/wombat/foo.2023-04-22

今天:/wombat/aaaa.txt

TimeBasedRollingPolicy支持归档日志文件自动压缩,如果fileNamePattern的值以.gz或者.zip结尾则可利用该特性。

文件命名格式

滚动计划

备注

/wombat/foo.%d.gz

按日滚动,归档日志文件会自动GZIP压缩

文件格式如下:

昨天:/wombat/foo.2019-05-05.gz

当天:/wombat/foo.2019-05-06

示例:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="1 seconds" debug="false">
    <!--定义日志路径,使用${LOG_HOME访问}, 如果是windows启动并且代码在D盘, 则日志会生成于D:\home\smart-community-docking\scd\logs下-->
    <property name="LOG_HOME" value="/home/smart-community-docking/scd/logs"/>
    <!-- 滚动文件的方式生成日志日志文件,文件的存储位置通过file标签指定 -->
    <!-- 通过encoder指定日志的生成格式,每个appender的日志格式都可以自定义,不用相同 -->
    <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/test.log</file>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %5level - %msg%n</pattern>
        </encoder>
        <!--
        通过rollingPolicy设置日志滚动的策略,这是使用按照时间滚动
        fileNamePattern属性设置滚动生成文件的格式,这里设置的精确到天,也就是按照天滚动,如果时间设置精确到秒,就按秒来滚动
        maxHistory属性设定最大的文件数,比如按天滚动,这里设置了30天,在第31天日志生成的时候,第一天的日志就会被删掉
        -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--设置按天来滚动,前一天日志打印到23点59分,然后就一直没有请求日志,直到次日的1点才有新的日志进入。
                    在0点到1点这个时间段,日志文件是不会滚动生成新的日志文件。因为滚动的动作是需要日志写入动作来触发。-->
            <fileNamePattern>${LOG_HOME}/test-%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
            <totalSizeCap>3GB</totalSizeCap>
            <cleanHistoryOnStart>false</cleanHistoryOnStart>
        </rollingPolicy>
    </appender>
    <root level="INFO">
        <appender-ref ref="file"/>
    </root>
</configuration>
5.7.3.2 SizeBasedTriggeringPolicy

观察当前活动文件的大小,如果已经大于了指定的值,它会给 RollingFileAppender 发一个信号触发对当前活动文件的轮转

ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy

属性名

类型

备注

maxFileSize

int

可以为字节,千字节,兆字节,千兆字节,通过在数值后面指定一个后缀 KB,MB 或者 GB。例如,5000000,5000KB,5MB 以及 2GB 都是有效的,前三个是一样的。(默认值是 10 MB)

官方的示例这个要放在<triggeringPolicy>触发策略使用,并且和FixedWindowRollingPolicy一起使用,所以这里先不说。

5.7.3.3 FixedWindowRollingPolicy

基于窗口大小的滚动策略。ch.qos.logback.core.rolling.FixedWindowRollingPolicy

这个听起来可能有点难理解,其实说白了就是将归档日志文件到最大了就写到下一个文件里,而窗口大小就是最多允许多少份日志文件。

属性名

类型

备注

fileNamePattern

String

必须包含“%i”。

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

minIndex

int

窗口下限。下限一般都是1啦

maxIndex

int

窗口上限。一般我们用上限就可以了。

示例:(官方示例FixedWindowRollingPolic和SizeBasedTriggeringPolicy一起使用:)

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="1 seconds" debug="false">
    <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>
    <root level="DEBUG">
        <appender-ref ref="FILE" />
    </root>
</configuration>

5.7.3.4 SizeAndTimeBasedRollingPolicy

前面介绍的第1种TimeBasedRollingPolicy是根据时间生成,如何SizeBasedTriggeringPolicy是根据大小来生成,但很尴尬的一点是这2个类冲突,没法同时使用。

故而官方提供了基于时间和文件大小的滚动策略:ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy

属性名

类型

备注

fileNamePattern

String

必选参数。

具体介绍可以看TimeBasedRollingPolicy的介绍。

区别点是必须包含 %i

maxFileSize

int

每个文件最大多少。可以指定KB,MB 或者 GB,默认值是 10 MB。

maxHistory

int

表示日志文件保存的最大数量。

例如:如果根据fileNamePattern判断出来是按天滚动,该值设为30,则日志文件最多保存30天。

totalSizeCap

int

可选参数,表示所有归档日志文件的的文件总大小。

假如设置每个日志文件到10mb的时候开始切分,最多保留30天,但最大到20GB,哪怕没到30天但容量达到20G了也要删除多余的日志。

cleanHistoryOnStart

boolean

可选参数,表示appender应用程序启动时是否应进行日志存档清理,默认为false。

示例:(每个文件最多5MB,保存60天的历史记录,但最多20GB。)

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="1 seconds" debug="false">
    <property name="LOG_HOME" value="/home/smart-community-docking/scd/logs"/>
    <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>
    <root level="DEBUG">
        <appender-ref ref="file" />
    </root>
</configuration>

5.8 encoder说明

encoder表示对参数进行格式化。

<encoder>是0.9.19版本之后引进的,以前的版本使用<layout>,logback极力推荐的是使用<encoder>而不是<layout>

<encoder>节点负责两件事情:

1、把日志信息转换为字节数组

2、把字节数组写到输出流

目前使用的是ch.qos.logback.classic.encoder.PatternLayoutEncoder (是唯一有用的且默认的encoder ),它有一个<pattern>节点,用来设置日志的输入格式。

使用“%”加“转换符”方式

如果要输出“%”,则必须用“\”对“\%”进行转义。

5.8.1 %n

转换符

作用

是否避免使用

n

日志换行。

根据使用平台输出\n或\r\n

说明:

看到最后一列的标题是"是否避免使用",这是因为这些信息是无法直接拿到的(比如请求行号、调用方法名),logback必须通过一些特殊手段去获取这些数据(比如在日志打印出产生一个堆栈信息),这种操作会比较影响效率,因此除非必要,否则不建议打印这些数据。

5.8.2 %c %lo %logger

转换符

作用

是否避免使用

c{length}

lo{length } 

logger{length}

输出日志的logger名,有一个形参,功能是缩短logger名,设置为0表示只输入logger最右边点符号之后的字符串。

{length} 限制了总输出长度,如果输出长度不够,尽可能显示类名压缩包名

示例:

例如我在com.top.scd.web.system.controller.module.xmga.XmgaController打印了一行日志

package com.toptop.scd.web.system.controller.module.xmga;
@RestController
@RequestMapping("/dockset/sc_xmga")
@Slf4j
public class XmgaController {
    @GetMapping("/time")
    @ResponseBody
    public String time() {
        log.warn("aaaaa");
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String timeStr = "厦门公安-当前时间:" + format.format(new Date());
        return timeStr;
    }
}

logback-spring.xml中配置:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="1 seconds" debug="true">
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%c-%lo-%logger</pattern>
        </encoder>
    </appender>
    <root level="info">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

打印结果:

com.toptop.scd.web.system.controller.module.xmga.XmgaController-com.toptop.scd.web.system.controller.module.xmga.XmgaController-com.toptop.scd.web.system.controller.module.xmga.XmgaController

可以注意到点号也是有被算进来的

pattern格式

打印结果

打印长度

%logger

com.toptop.scd.web.system.controller.module.xmga.XmgaController

63

%logger{0}

XmgaController

14

%logger{1}

c.l.s.w.s.c.m.x.XmgaController

30

%logger{14}

c.l.s.w.s.c.m.x.XmgaController

30

%logger{30}

c.l.s.w.s.c.m.x.XmgaController

30

%logger{32}

c.l.s.w.s.c.m.x.XmgaController

30

%logger{33}

c.l.s.w.s.c.m.xmga.XmgaController

33

%logger{38}

c.l.s.w.s.c.module.xmga.XmgaController

38

%logger{47}

c.l.s.w.s.controller.module.xmga.XmgaController

47

%logger{52}

c.l.s.w.system.controller.module.xmga.XmgaController

52

%logger{54}

c.l.s.web.system.controller.module.xmga.XmgaController

54

%logger{56}

c.l.scd.web.system.controller.module.xmga.XmgaController

56

%logger{61}

c.toptop.scd.web.system.controller.module.xmga.XmgaController

61

%logger{63}

com.toptop.scd.web.system.controller.module.xmga.XmgaController

63

%logger{100}

com.toptop.scd.web.system.controller.module.xmga.XmgaController

63

5.8.3 %C %class

转换符

作用

是否避免使用

C{length}

class{length } 

输出日志调用所在类。

length与%logger(简写%c或%lo)的用法相同。

尽量避免使用,除非执行速度不造成任何问题。

不被推荐使用

5.8.4.%d %date

转换符

作用

是否避免使用

d{pattern}

date{pattern} 

输出时间格式,模式语法同

java.text.SimpleDateFormat

可以指定日期格式精确到毫秒:%d{yyyy-MM-dd HH:mm:ss.SSS}

5.8.5.%caller

转换符

作用

是否避免使用

caller{depth}

输出日志的调用者的位置信息,整数选项表示输出信息深度。

<pattern>%caller</pattern>

打印:

Caller+0  at com.toptop.scd.web.system.controller.module.xmga.XmgaController.time(XmgaController.java:49)

Caller+1  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

Caller+2  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

Caller+3  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

Caller+4  at java.lang.reflect.Method.invoke(Method.java:498)

<pattern>%caller{1}</pattern>

打印:

Caller+0  at com.toptop.scd.web.system.controller.module.xmga.XmgaController.time(XmgaController.java:49)

5.8.6.%L %line

转换符

作用

是否避免使用

L

line

输出执行日志请求的行号。

尽量避免使用,除非执行速度不造成任何问题。

<pattern>%L</pattern>
5.8.9 %m %msg %message

转换符

作用

是否避免使用

m

msg

message

输出应用程序提供的信息

log.warn("aaaaa");
<pattern>%msg</pattern>

打印:

aaaaa

5.8.8.%M %method

转换符

作用

是否避免使用

M

method

数值执行日志请求的方法名。

尽量避免使用,除非执行速度不造成任何问题。

public String time() {
    log.warn("aaaaa");
}
<pattern>%method</pattern>

打印:

time

5.8.9 %p %le %level

转换符

作用

是否避免使用

p

le

level

输出日志级别

log.warn("aaaaa");
<pattern>%level</pattern>

打印:

WARN

5.8.10 %r %relative

转换符

作用

是否避免使用

r

relative

输出从程序启动到创建日志记录的时间,单位是毫秒

<pattern>%r%n</pattern>

多执行几次,打印:

30675581

30676817

30677965

30679104

30680009

5.8.11.%t %thread

转换符

作用

是否避免使用

t

thread

输出产生日志的线程名

<pattern>%thread</pattern>

打印:

http-nio-8998-exec-1

5.8.12 %replace

转换符

作用

是否避免使用

replace(p){r,t}

p为日志内容, r是正则表达式, 将p中符合r的内容替换为t

log.warn("aaaaa");
<pattern>%replace(%msg){"a", "b"}</pattern>

打印结果:

bbbbb

6.8.13 宽度设置

%20logger:当字符数少于20个字符时,则左侧留空白;
%-20logger:当字符数少于20个字符时,则右侧留空白;
%.30logger:当字符数据大于30个时,则截断;

还可以合起来使用,例如:%-20.20logger     %20.20class

{length}可指定长度,如%logger{36}

log.warn("123456789");
<pattern>%80logger%n%-80logger%n%.20logger</pattern>

5.8.14.显示设置

%highligth(日志内容):突出显示

%green(日志内容):字体显示为指定颜色

%clr(日志内容){颜色} 设置颜色

5.8.14.1.%clr和defaults.xml
<pattern>%clr(%msg){faint}%n</pattern>

这里启动会报错说找不到%clr对应的转换器。

Exception in thread "main" java.lang.IllegalStateException: Logback configuration error detected:

ERROR in ch.qos.logback.core.pattern.parser.Compiler@79145d5a - There is no conversion class registered for composite conversion word [clr]

ERROR in ch.qos.logback.core.pattern.parser.Compiler@79145d5a - Failed to create converter for [%clr] keyword

解决方法一:

引入springboot的默认日志配置:

<include resource="org/springframework/boot/logging/logback/defaults.xml" />

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="1 seconds" debug="false">
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%clr(%msg){faint}%n</pattern>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

解决方法二:或者手动引入需要的配置:

<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="1 seconds" debug="false">
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%clr(%msg){faint}%n</pattern>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

这个文件是怎么冒出来的呢?查看前面的那个default.xml文件就可以看到啦!

5.8.14.2.支持的颜色

%black 黑色

%red 红色

%green 绿色

%yellow 黄色

%blue 蓝色

%magenta 洋红色

%cyan 青色

%white 白色

%gray 灰色

%faint 灰白色

以下为对应加粗的颜色代码

%boldRed

%boldGreen

%boldYellow

%boldBlue

%boldMagenta

%boldCyan

%boldWhite

%highlight 高亮色

5.9 filter

5.9.1 LevelFilter

<appender>标签里面可以指定<filter>过滤器,

例如ch.qos.logback.classic.filter.LevelFilter,表示根据日志级别进行过滤。

<level>:设置过滤级别

<onMatch>:用于配置符合过滤条件的操作

<onMismatch>:用于配置不符合过滤条件的操作

举例:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="1 seconds" debug="true">
    <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>
        <encoder>
            <pattern>
                %-4relative [%thread] %-5level %logger{30} - %msg%n
            </pattern>
        </encoder>
    </appender>
    <root level="DEBUG">
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>
public String time() {
    log.trace("====trace====");
    log.debug("====debug====");
    log.info("====info====");
    log.warn("====warn====");
    log.error("====error====");
}

打印结果:

186556 [http-nio-8998-exec-6] INFO  c.l.s.w.s.c.m.x.XmgaController - ====info====

5.9.2 ThresholdFilter

临界值过滤器,过滤掉低于指定临界值的日志。

对应的类是ch.qos.logback.classic.filter.ThresholdFilter。

当日志级别等于或高于临界值时,过滤器返回NEUTRAL;当日志级别低于临界值时,日志会被拒绝。

<level>:设置过滤级别

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

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="1 seconds" debug="true">
    <appender name="CONSOLE"
              class="ch.qos.logback.core.ConsoleAppender">
        <!-- 过滤掉低于INFO级别的日志-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <encoder>
            <pattern>
                %-4relative [%thread] %-5level %logger{30} - %msg%n
            </pattern>
        </encoder>
    </appender>
    <root level="DEBUG">
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>
public String time() {
    log.trace("====trace====");
    log.debug("====debug====");
    log.info("====info====");
    log.warn("====warn====");
    log.error("====error====");
}

打印结果:

393494 [http-nio-8998-exec-9] INFO  c.l.s.w.s.c.m.x.XmgaController - ====info====

393494 [http-nio-8998-exec-9] WARN  c.l.s.w.s.c.m.x.XmgaController - ====warn====

393494 [http-nio-8998-exec-9] ERROR c.l.s.w.s.c.m.x.XmgaController - ====error====

5.9.3 EvaluatorFilter

求值过滤器,评估、鉴别日志是否符合指定条件。

对应类是ch.qos.logback.core.filter.EvaluatorFilter。

需要额外的两个JAR包,commons-compiler.jar和janino.jar。

有以下子节点:

<evaluator>鉴别器,常用的鉴别器是ch.qos.logback.classic.boolex.JaninoEventEvaluator

,也是默认的鉴别器。它以任意的java布尔值表达式作为求值条件,求值条件在配置文件解释过成功被动态编译,布尔值表达式返回true就表示符合过滤条件。

<evaluator>有个子标签<expression>,用于配置求值条件

<onMatch>:用于配置符合过滤条件的操作

<onMismatch>:用于配置不符合过滤条件的操作

求值表达式作用于当前日志,logback向求值表达式暴露日志的各种字段:

Name

Type

Description

event

LoggingEvent

与记录请求相关联的原始记录事件,下面所有变量都来自event,例如,event.getMessage()返回下面"message"相同的字符串

message

String

日志的原始消息,例如,设有logger mylogger,"name"的值是"AUB",对于 mylogger.info("Hello {}",name); "Hello {}"就是原始消息。

formatedMessage

String

日志被各式话的消息,例如,设有logger mylogger,"name"的值是"AUB",对于 mylogger.info("Hello {}",name); "Hello Aub"就是格式化后的消息。

logger

String

logger 名。

loggerContext

LoggerContextVO

日志所属的logger上下文。

level

int

级别对应的整数值,所以 level > INFO 是正确的表达式。

timeStamp

long

创建日志的时间戳。

marker

Marker

与日志请求相关联的Marker对象,注意“Marker”有可能为null,所以你要确保它不能是null。

mdc

Map

包含创建日志期间的MDC所有值得map。访问方法是: mdc.get("myKey") 。mdc.get()返回的是Object不是String,要想调用String的方法就要强转,例如,

((String) mdc.get("k")).contains("val") .MDC可能为null,调用时注意。

throwable

java.lang.Throwable

如果没有异常与日志关联"throwable" 变量为 null. 不幸的是, "throwable" 不能被序列化。在远程系统上永远为null,对于与位置无关的表达式请使用下面的变量throwableProxy

throwableProxy

IThrowableProxy

与日志事件关联的异常代理。如果没有异常与日志事件关联,则变量"throwableProxy" 为 null. 当异常被关联到日志事件时,"throwableProxy" 在远程系统上不会为null

EvaluatorFilter支持使用 java 代码来作为过滤标准。但需要导入额外的包:

<!-- janino -->
<dependency>
    <groupId>org.codehaus.janino</groupId>
    <artifactId>janino</artifactId>
    <version>3.1.0</version>
</dependency>
<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="1 seconds" debug="true">
    <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("info");</expression>
            </evaluator>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder>
            <pattern>
                %-4relative [%thread] %-5level %logger - %msg%n
            </pattern>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>
public String time() {
    log.trace("====trace====");
    log.debug("====debug====");
    log.info("====info====");
    log.warn("====warn====");
    log.error("====error====");
}

打印:

21809 [http-nio-8998-exec-1] INFO  com.leelen.scd.web.system.controller.module.xmga.XmgaController - ====info====

5.9.4 自定义过滤器

自定义类:

package com.toptop.scd.base.common.filter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.spi.FilterReply;

public class SampleFilter extends Filter<ILoggingEvent> {

    @Override
    public FilterReply decide(ILoggingEvent event) {
        if (event.getMessage().contains("info")) {
            return FilterReply.ACCEPT;
        } else {
            return FilterReply.DENY;
        }
    }
}

日志配置文件指定过滤器

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="1 seconds" debug="true">
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="com.leelen.scd.base.common.filter.SampleFilter" />
        <encoder>
            <pattern>%-4relative [%thread] %-5level %logger - %msg%n</pattern>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

打印结果:

186556 [http-nio-8998-exec-6] INFO  c.l.s.w.s.c.m.x.XmgaController - ====info====

六、优化异常堆栈stack日志打印

6.1 未优化前

try {
    int i = 1/0;
} catch (Exception e) {
    log.error("发生异常", e);
}

打印结果:(打印了很多不需要的堆栈信息)

打印结果:
2023-04-25 10:58:03.757 ERROR 36556 --- [nio-8998-exec-1] c.l.s.w.s.c.module.xmga.XmgaController   : 发生异常

java.lang.ArithmeticException: / by zero
	at com.toptop.scd.web.system.controller.module.xmga.XmgaController.time(XmgaController.java:50)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1639)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)

6.2.优化后

1、引入logstash-logback-encoder

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

注意jdk版本依赖:

2、引入

<conversionRule conversionWord="stack" converterClass="net.logstash.logback.stacktrace.ShortenedThrowableConverter"/>

3、通过%stack{}进行配置

stack{100,16,2048,rootFirst,regex1,regex2,evaluatorName}

参数解释:

建议查看源码 net.logstash.logback.stacktrace.ShortenedThrowableConverter#parseOptions()

  •  示例:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <conversionRule conversionWord="stack"
                    converterClass="net.logstash.logback.stacktrace.ShortenedThrowableConverter"/>
    <property name="STE_EXCLUSIONS" value="\$\$FastClassByCGLIB\$\$,\$\$EnhancerBySpringCGLIB\$\$,^sun\.reflect\..*\.invoke,^com\.sun\.
    ,^sun\.net\.,^net\.sf\.cglib\.proxy\.MethodProxy\.invoke,^org\.springframework\.cglib\.,^org\.springframework\.transaction\.
    ,^org\.springframework\.validation\.,^org\.springframework\.app\.,^org\.springframework\.aop\.,^java\.lang\.reflect\.Method\.invoke
    ,^org\.springframework\.ws\..*\.invoke,^org\.springframework\.ws\.transport\.,^org\.springframework\.ws\.soap\.saaj\.SaajSoapMessage\.
    ,^org\.springframework\.ws\.client\.core\.WebServiceTemplate\.,^org\.springframework\.web\.filter\.,^org\.apache\.tomcat\.
    ,^org\.apache\.catalina\.,^org\.apache\.coyote\.,^java\.util\.concurrent\.ThreadPoolExecutor\.runWorker,^java\.lang\.Thread\.run$"/>
    <!--
        stack{100,16,2048,rootFirst,regex1,regex2,evaluatorName}
        参数解释: 建议查看源码 net.logstash.logback.stacktrace.ShortenedThrowableConverter#parseOptions() 方法
            第1参数: maxDepthPerThrowable:值可以是 full或者short或者int值,表示每个异常最多打印多少个 stackTraceElements 元素
            第2参数: shortenedClassNameLength:值可以是 full或者short或者int值,将尝试将类名长度缩短到小于此值
                     com.huan.springboot.service.ExceptionService 可能会变成 c.h.s.s.ExceptionService
            第3参数: maxLength:值可以是 full或者short或者int值,指的输出到日志中整个堆栈最大能存在多少个字符。
            后面这些参数没有固定顺序
            第4参数: rootFirst: 可选参数,如果使用该参数,值就是 rootFirst ,表示应首先打印堆栈的根本原因
            第5参数: inlineHash: 可选参数,如果使用该参数,值就是 inlineHash, 指示应该计算和内联十六进制错误哈希
            如果参数都不是上方的类型,那么可能是 evaluator 或者 exclude 类型,这2个都是判断这个 stackTraceElement 是否应该被打印,这2个参数没有顺序关系
                evaluator: 值的是需要实现 EventEvaluator<ILoggingEvent> 的类
                exclude: 指的是需要排除的正则表达式, 如果存在.需要转义成 \.
    -->
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %msg%n%stack{100,full,2048,rootFirst,inlineHash,${STE_EXCLUSIONS},}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="stdout"/>
    </root>
</configuration>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1125801.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

err -110 while initial SD card failed enmmm否系解决方案

1.情况表述 之前把 sd卡从小容量换成了大容量 且运行正常 过了一两个月 发现启动失败 报错&#xff1a;mmc0: error -110 whilst initialising SD card 给出报错图片 2.相关解决方案 给出链接 讲的很有道理&#xff0c;但是 我在bash中没有找到对应内核的驱动文件 SD卡…

抖音SEO优化怎么做?详细的方法来了,搭配批量剪辑让效果更优

抖音作为一个非常受欢迎的短视频平台&#xff0c;无论是用户还是内容创作者&#xff0c;体量都越来越大&#xff0c;这意味着竞争也越来越大&#xff0c;想要在抖音上获得更多的曝光和关注&#xff0c;做好抖音 SEO 优化是一门必修课。 抖音 SEO 优化是指优化我们发布到抖音平…

AMEYA360:瑞萨电子转矩控制解决方案加强工业自动化

随着科技的不断进步和全球制造业的竞争加剧&#xff0c;越来越多的企业开始投资和采用自动化技术&#xff0c;以提高生产效率、降低成本、改善产品质量并确保过程安全。而为协同工作完成复杂任务&#xff0c;确保高质量的生产结果。工业自动化设备对精度控制要求非常高&#xf…

Redis底层核心数据结构详解

文章目录 一、深入String&#xff08;SDS&#xff09;1. 字符串简介2. SDS存在的意义3. SDS结构设计4. SDS与C字符串的区别4.1 常数复杂度获取字符串长度4.2 杜绝缓冲区溢出4.3 二进制安全4.4 SDS API 5 小结 二、深入List (QuickList)1. 链表节点结构设计2. Redis的链表实现的…

linux驱动开发led绑定亮灯

head.h 应用程序 驱动程序 结果

LabVIEW基于机器视觉的钢轨表面缺陷检测系统

LabVIEW基于机器视觉的钢轨表面缺陷检测系统 机器视觉检测技术和LabVIEW软件程序&#xff0c;可以实现轨道工件的表面质量。CMOS彩色工业相机采集的图像通过图像预处理、图像阈值分割、形态分析、特征定位和图案匹配进行处理和分析。图形显示界面采用LabVIEW软件编程设计&…

【大模型的一些基本结论】

这里写自定义目录标题 LLama的一些基本结论 各个论文中给出一些观察显现&#xff0c;我们比摘要更简略地摘要一些文本大模型大佬地基本结论和观察到的现象 LLama的一些基本结论 由于大模型要作为服务&#xff0c;因而推理时间更重要。一个较小的、训练时间较长的模型最终会在…

GLIP,FLIP论文阅读

Scaling Language-Image Pre-training via Masking&#xff08;FLIP&#xff0c;2023&#xff09;&#x1f44d; 贡献&#xff1a; 1.图像端引入MAE的随机MASK&#xff0c;image encoder只处理未mask的patches&#xff08;和之前的MAE方法一致&#xff09;&#xff0c;减少了输…

5年经验之谈 —— 手把手教你接口性能测试之JMeter性能测试篇!

本文是我们《手把手教你接口性能测试》系列文章中的完结篇&#xff0c;介绍如何使用JMeter工具进行接口测试和并发测试。 一、Jmeter 简介 Jmeter是由Apache公司开发的一个纯Java开源项目&#xff0c;即可以用于做接口测试也可以用于做性能测试&#xff0c;具备高移植性和扩展…

QUIC协议包头保护(四)

一&#xff1a;为什么要有包头保护 学过HTTP和HTTPS都知道&#xff0c;随着网络的普及&#xff0c;人们对于信息的保护&#xff0c;个人的隐私越发的重视。信息加密对于未来协议的发展肯定是越来越趋于严格。QUIC作为新生代的协议&#xff0c;必然要站着前辈的肩膀上发展&#…

基于Python实现的复制、移动、离线化你的 Markdown 文档,清理 Markdown 引用路径中的垃圾文件

Markdown 工具箱 完整代码下载地址&#xff1a; Markdown 工具箱 &#x1f6a9; 简介 Markdown 工具箱&#xff0c;是我为 Markdown 笔记管理做的一个工具集。目前有以下几个功能&#xff1a; 复制 批量将 md 笔记&#xff08;连带它的相对路径引用的图片、附件&#xff09;…

c#中使用stringbuilder的Append方法写sql语句

c#中使用stringbuilder的Append方法写sql语句 c#中使用stringbuilder的Append方法写sql语句_c#strsql.append_安静点DGC的博客-CSDN博客https://blog.csdn.net/qq_26925297/article/details/81586884 特此记录 anlog 2023年8月8日

PMP考试中有哪些疑点、难点?

目前PMP考试的内容只有最后5个月是按照旧考纲&#xff0c;后面的考试基本上都是按照新考纲进行。因此&#xff0c;备考的朋友们需要学习很多新的知识点和敏捷学习方法。所以现在是给今年想要备考的朋友们提供学习建议的时候了。 01、新版考纲将主要关注以下三个新领域&#xf…

一、XSS加解密编码解码工具

一、XSS加解密编码解码工具 解释&#xff1a;使用大佬开发的工具&#xff0c;地址&#xff1a;https://github.com/Leon406/ToolsFx/blob/dev/README-zh.md 在线下载地址&#xff1a; https://leon.lanzoui.com/b0d9av2kb(提取码&#xff1a;52pj)&#xff08;建议下载jdk8-w…

每天一道算法题——动态规划

找到工作就不更新了~ 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 注意&#xff1a;给定 n 是一个正整数。 示例 1&#xff1a; 输入&#xff1a; 2 输出&#xff1a; 2 解释&#xff1a; …

博客系统自动化测试

1、博客列表页面测试 测试内容 测试代码&#xff1a; TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class BlogListTest extends Autotest{public static ChromeDriver driver createDriver();// 准备工作TestBeforeAllstatic void ready() {driver.get(&q…

适用于 Mac 电脑的 10 款最佳数据恢复工具集

无论是个人照片还是重要的商业文档&#xff0c;对于那些依赖计算机获取重要文件的人来说&#xff0c;数据丢失都是一场噩梦。 值得庆幸的是&#xff0c;Mac用户可以使用各种数据恢复工具&#xff0c;可以帮助您恢复丢失或意外删除的文件。 在本文中&#xff0c;我们将采用适用于…

RAM(recognize anything)—— 论文详解

一、概述 1、是什么 RAM 论文全称 Recognize Anything: A Strong Image Tagging Model。区别于图像领域常见的分类、检测、分割&#xff0c;他是标记任务——即多标签分类任务&#xff08;一张图片命中一个类别&#xff09;&#xff0c;区分于分类&#xff08;一张图片命中一个…

Unity Meta Quest 一体机开发:前期准备和环境配置(2023 版,Oculus Integration v57)

​ 文章目录 &#x1f4d5;教程说明&#x1f4d5;思维导图概括&#x1f4d5;开发者模式&#x1f4d5;可下载的软件⭐Oculus 电脑客户端⭐SideQuest⭐Meta Quest Developer Hub⭐Unity Hub &#x1f4d5;安装 Unity 时需要添加的模块&#x1f4d5;设置 Unity 的 Build Settings…

构建高性能应用的利器:Nginx反向代理及配置详解

一、Nginx概念解读 对于新事物的理解&#xff0c;最好的方式就是从概念入手&#xff0c;本文作为《Nginx专题》系列文章的第一篇&#xff0c;先从Nginx的名称开始来分解这个神秘的引擎。 Nginx&#xff0c;是engine X的缩写&#xff0c;发音也是engine x&#xff0c;2004年由…