引言:这是我在项目中遇见的一个需求,将项目中几个特定的线程,分别单独打印出INFO、ERROR日志出来,按照小时拆分,保留15天。下面的配置文件就是解决上面的需求。
一、我的Logback依赖版本
外面引用的是此依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<version>2.6.3</version>
<scope>compile</scope>
</dependency>
这是spring-boot-starter-loggin内部的具体依赖项
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.10</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.17.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.33</version>
<scope>compile</scope>
</dependency>
</dependencies>
二、具体实现
Logback里面有几个主要组件appender、encoder、layout、filter。
Appender:输出源,一个日志可以后好几个输出源
Encoder:一个appender有一个encoder,负责将一个event事件转换成一组byte数组,并将转换后的字节数据输出到文件中。
layout:格式化数据将event事件转化为字符串,解析的过程
flter:过滤器
下面就是分线程的鉴定器。我需要分出的特别线程名里面有":"分号,所有将分号的筛选出来,其他还是返回默认main线程中。
public class ThreadDiscriminator extends ContextBasedDiscriminator {
String KEY ="threadName";
/**
* Return the name of the current context name as found in the logging event.
*/
public String getDiscriminatingValue(ILoggingEvent event) {
if (event.getThreadName().contains(":")) {
return event.getThreadName();
}
return "main";
}
public String getDefaultValue() {
return KEY;
}
public String getKey() {
return KEY;
}
public void setKey(String key) {
this.KEY = key;
}
}
使用到Logback中的筛选附加器SiftingAppender,SiftingAppender可用于根据给定的运行时属性来分离(或筛选)日志记录。它的SiftingAppender独特之处在于其引用和配置子附加程序的能力。在下面的示例中, SiftingAppender将创建多个 RollingFileAppender实例,每个 RollingFileAppender实例由与“threadName”MDC 键关联的值标识。每当“threadName”MDC 键被分配一个新值时,RollingFileAppender 就会从头开始构建一个新实例。它 SiftingAppender会跟踪它创建的附加程序。30 分钟内未使用的 Appender 将被自动关闭并丢弃。
变量导出拥有不同的appender实例是不够的;每个实例必须输出到不同的目标资源。为了允许这种区分,在附加程序模板中,传递给鉴别器的密钥(上例中的“threadName”)被导出并成为变量。因此,该变量可用于区分给定子附加程序使用的实际资源。
使用下面的配置文件运行应用程序,将生成多个不同的INFO、ERROR日志文件。
<configuration debug="false">
<!--日志输出地址-->
<property name="log.path" value="logs"/>
<!--日志输出规则-->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{50} - [%method,%line] - %msg%n"/>
<!-- 分线程输出源 -->
<appender name="info_frameworkthread" class="ch.qos.logback.classic.sift.SiftingAppender">
<!--分线程规则-->
<discriminator class="com.example.mybatissourcestudy.config.ThreadDiscriminator">
<key>threadName</key>
<defaultValue>main</defaultValue>
</discriminator>
<sift>
<appender name="FILE-INFO-${threadName}" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/${threadName}-info.log</file>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}/${threadName}-INFO-%d{yyyy-MM-dd-HH}.%i.log.gz</fileNamePattern>
<maxFileSize>5MB</maxFileSize>
<maxHistory>15</maxHistory>
<totalSizeCap>20MB</totalSizeCap>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>5MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
</sift>
</appender>
<appender name="error_frameworkthread" class="ch.qos.logback.classic.sift.SiftingAppender">
<discriminator class="com.example.mybatissourcestudy.config.ThreadDiscriminator">
<key>threadName</key>
<defaultValue>main</defaultValue>
</discriminator>
<sift>
<appender name="FILE-ERROR-${threadName}" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/${threadName}-error.log</file>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}/${threadName}-ERROR-%d{yyyy-MM-dd-HH}.%i.log.gz</fileNamePattern>
<maxFileSize>5MB</maxFileSize>
<maxHistory>15</maxHistory>
<totalSizeCap>20MB</totalSizeCap>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>5MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
</sift>
</appender>
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="info_frameworkthread"/>
<appender-ref ref="error_frameworkthread"/>
<appender-ref ref="STDOUT"/>
</root>
</configuration>
再配置了每小时切割,日志文件达到设定大小再进行压缩设置。
若需要添加其他配置项,不知道是否配置正确,将configuration上面的debug改为false就能打印Logback自己的日志,排除所有的error信息,配置就是正确的。