按照内容分割日志
前言
前一段时间接到一个需求,在特定场景下进行告警。需要将告警内容写入到日志文件中,运维人员会收集这类日志进行告警。这就需要将告警信息写入到单独的日志文件中,即通过内容将日志分割。
这里不介绍logback与log4j2的比较与选择,直奔主题——logback和log4j2是如何通过关键字将日志分割的。
logback
maven依赖
<!-- logback依赖 -->
···
<logback.version>1.2.3</logback.version>
<janino.version>3.1.0</janino.version>
···
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<!-- janino 需要通过此包进行关键字匹配-->
<dependency>
<groupId>org.codehaus.janino</groupId>
<artifactId>commons-compiler</artifactId>
<version>${janino.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.janino</groupId>
<artifactId>janino</artifactId>
<version>${janino.version}</version>
</dependency>
配置文件
logback.xml
如注释所示,配置一个告警日志alertAppender,包含指定关键字的日志内容会写入到所指定的日志文件中。
- alertAppender
- RollingFileAppender
- 按照日期分割日志
- SizeAndTimeBasedRollingPolicy
- 通过maxFileSize,maxHistory,totalSizeCap等参数制定分割规则
+** EvaluatorFilter** - 通过配置expression进行包含关键字内容的过滤
- 通过maxFileSize,maxHistory,totalSizeCap等参数制定分割规则
- RollingFileAppender
<?xml version="1.0" encoding="utf-8" ?>
<configuration debug="true">
<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %X{traceId} %-5level %logger{36} %L - %msg%n</pattern>
</encoder>
</appender>
<!-- 主要配置!!! -->
<!-- 配置报警日志 -->
<appender name="alertAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 接收WARN级别日志,不是WARN级别的会拒绝,WARN级别的进行下一个filter判断 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>NEUTRAL</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 通过EvaluatorFilter结合janino包下的JaninoEventEvaluator 实现指定关键词过滤 -->
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<!-- 日志中必须包含ALERT,包含的接受,不包含的拒绝 -->
<evaluator> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<expression>return message.contains("ALERT");</expression>
</evaluator>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 日志输出到指定日志中,500MB时分割日志,最多30个,最大50GB -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>logs/logback/alert-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>500MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>50GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}--%msg%n</pattern>
</encoder>
</appender>
<appender name="warnAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>logs/logback/warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>500MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>50GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %thread %X{traceId} %X{invokeNo} %logger{40} %msg%n</pattern>
</encoder>
</appender>
<appender name="infoAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>logs/logback/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>500MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>50GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %thread %X{traceId} %X{invokeNo} %logger{40} %msg%n</pattern>
</encoder>
</appender>
<logger name="alertAppender" level="WARN" addtivity="false">
<appender-ref ref="alertAppender"/>
</logger>
<logger name="warnAppender" level="WARN" addtivity="false">
<appender-ref ref="warnAppender"/>
</logger>
<logger name="infoAppender" level="INFO" addtivity="false">
<appender-ref ref="infoAppender"/>
</logger>
<root level="info">
<appender-ref ref="alertAppender"/>
<appender-ref ref="warnAppender"/>
<appender-ref ref="infoAppender"/>
<appender-ref ref="consoleAppender"/>
</root>
</configuration>
Demo
demo与测试结果如下:
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@Slf4j
@SpringBootTest(classes = LogExampleApplication.class)
public class LogTest {
@Test
public void logTest() {
System.out.println("=========================");
log.info(RandomStringUtils.randomAlphabetic(6));
log.info("alert info");
log.warn("alert warn");
log.warn("ALERT warn");
}
}
根据输出结果可以看到,只有包含关键字“ALERT”的内容输出到了alert.log中,其他内容被过滤了。
log4j2
maven依赖
由于使用的是springboot,需要默认使用logback,需要将spring-boot-starter-logging依赖排除
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
配置文件
log4j2.xml
告警日志配置
- 按照每日分割日志:
- 配置RollingFile ,如果同时配置File和RollingFile ,二者的fileName不能相同,否则RollingFile 配置可能会失效。
- 配置TimeBasedTriggeringPolicy ,每日触发分割
- 按照大小分割日志
- 配置SizeBasedTriggeringPolicy ,当日志达到指定大小时,进行分割,分割出来的日志名参照filePattern配置
- 按照关键字过滤日志
- 配置RegexFilter,通过正则匹配符合的内容。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="debug" monitorInterval="60">
<Properties>
<Property name="default_log_pattern">
[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5p] [%t] (%c{1}:%L) [TxId:%X{PtxId} SpanId:%X{PspanId}] %m%n
</Property>
</Properties>
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="${default_log_pattern}"/>
</Console>
<RollingFile name="alertRollingFile"
filePattern="logs/log4j/alert-%d{yyyy-MM-dd}.%i.log"
fileName="logs/log4j/alert.log">
<!-- 正则匹配,符合条件的写入日志 -->
<RegexFilter regex=".*ALERT.*" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout>
<Pattern>%d{yyyy-MM-dd HH:mm:ss}--%msg%n</Pattern>
</PatternLayout>
<Policies>
<!-- 每次启动执行 -->
<!-- <OnStartupTriggeringPolicy />-->
<!-- 达到250MB进行分割 -->
<SizeBasedTriggeringPolicy size="250 MB"/>
<TimeBasedTriggeringPolicy />
</Policies>
<!-- 最多20个 -->
<DefaultRolloverStrategy max="20"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="STDOUT" level="info"/>
<AppenderRef ref="alertRollingFile" level="warn"/>
</Root>
</Loggers>
</Configuration>
Demo
同上
由于只有alertRollingFile配置了写入日志文件,且根据规则过滤,所以只有带关键字“ALERT”的日志内容写到日志文件中。
demo地址: git@github.com:github-lee-future/log-example.git