自定义log4j2中的Appender来获取日志内容的示例代码
作者:咖啡杯里的茶_
springboot版本:2.6.15 log4j版本:2.17.2
Log4j中的Appender 是什么
本文讲述的是通过 log4j
中自定义的 Appender
来获取需要打印的日志信息,那么 Appender
是什么东西呢?先简单了解一下
在 Log4j2 中,Appender 是负责将日志事件输出到目标地点的组件。Appender 可以将日志事件输出到控制台、文件、网络等不同的目的地。 Log4j2 提供了多种内置的 Appender,例如 ConsoleAppender、FileAppender、AsyncAppender 等,同时支持自定义 Appender。 Appender 的主要职责是将日志事件按照指定的格式和目的地输出。每个 Appender 都有自己的名称和类型,可以根据需要配置不同的属性。例如,FileAppender 用于将日志事件输出到文件中,其属性包括文件名、追加模式(是否覆盖已存在的文件或追加到文件末尾)等。
需求背景
有两个系统,系统 A
和系统 B
, 系统 A
会发送指令给系统 B
, 系统 B
会响应结果给系统 A
,这两个系统之间的通信方式是 MQ
, 即 A
通过 MQ
发送数据给 B
(数据中有 UUID
字段值),系统 B
处理完成后将结果通过 MQ
发送给 A
,请求和响应的对应关系则可以通过 UUID
来进行匹配
现在有一个需求是监控在某个时间段内发送了多少指令,以及多少指令失败(在给定时间内没有收到响应或者响应中给了错误结果认为失败)
对于这种需求一般都是通过 AOP
来解决,但是在部分场景下 AOP
也比较难处理,比如上面场景中其实这个监控处理是有两部分的,第一部分是发送请求,第二部分是获取请求对应的结果,而且不是 http
调用,是通过 MQ
调用,即业务逻辑实现是分布在两个方法中的 (可以抽取一层将发送请求和响应结果逻辑放在一起,并且返回原始结果即可)
下面基于已有实现提供另外一种更简单的解决方式,已有实现的特点:
- 指令发送和结果接收都被抽取成独立的方法,只要是两个系统间的
MQ
通信最终都会调用这两个方法(一个发送,一个接收结果) - 在这两个方法中都将原始的参数以及最终的响应结果给打印出来了 基于以上两点,如果可以拿到打印的日志信息就可以比较简单汇总处理
修改前测试代码
log4j2 配置文件
下面 log4j2-dev.xml
配置文件很简单,就是将所有日志打印到控制台,日志级别为 info
<?xml version="1.0" encoding="UTF-8"?> <!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数--> <configuration monitorInterval="60"> <Properties> <property name="LOG_PATTERN_CONSOLE" value="%clr{%d{yyyy-MM-dd HH:mm:ss.SSS}}{faint} %clr{%5p} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n%xwEx"/> </Properties> <appenders> <!-- Console 是将日志信息打印打控制台--> <console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="${LOG_PATTERN_CONSOLE}"/> <ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY"/> </console> </appenders> <loggers> <root level="info"> <AppenderRef ref="Console"/> </root> </loggers> </configuration>
两个测试类代码
给出两个测试类是为了对比,后续自定义的 Appender
只会作用在一个测试类中,对于其他类的日志打印不会获取到对应的日志信息
@Component public class DemoService { private static final Logger logger = LoggerFactory.getLogger(DemoService.class); public void doSomething(String param) { logger.info("test demo"); } } @Component public class DemoService2 { private static final Logger logger = LoggerFactory.getLogger(DemoService2.class); public void doSomething(String param) { logger.info("test demo 2"); } }
自定义Appender
自定义的 Appender
不需要被 Spring
管理,所以不需要 @Component
等注解
package com.example; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.appender.AbstractAppender; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.config.plugins.PluginAttribute; import org.apache.logging.log4j.core.config.plugins.PluginElement; import org.apache.logging.log4j.core.config.plugins.PluginFactory; import org.apache.logging.log4j.core.layout.PatternLayout; import java.io.Serializable; @Plugin(name = "CusAppender", category = "Core", elementType = Appender.ELEMENT_TYPE) public class CustomAppender extends AbstractAppender { protected CustomAppender(String name, Filter filter, Layout<? extends Serializable> layout) { super(name, filter, layout); } @Override public void append(LogEvent event) { // 在这里获取日志信息 String message = event.getMessage().getFormattedMessage(); // 打印日志信息 System.out.println("拦截到的消息" + message); } @PluginFactory public static CustomAppender createAppender(@PluginAttribute("name") String name, @PluginElement("Layout") Layout<? extends Serializable> layout) { if (name == null) { throw new IllegalArgumentException("No name provided for CustomAppender"); } if (layout == null) { layout = PatternLayout.createDefaultLayout(); } return new CustomAppender(name, null, layout); } }
将自定义 Appender 配置到 Log4j 配置文件中
<?xml version="1.0" encoding="UTF-8"?> <!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数--> <configuration monitorInterval="60"> <Properties> <property name="LOG_PATTERN_CONSOLE" value="%clr{%d{yyyy-MM-dd HH:mm:ss.SSS}}{faint} %clr{%5p} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n%xwEx"/> </Properties> <appenders> <!-- 添加自定义的 Appender --> <CusAppender name="CustomAppender" /> <!-- Console 是将日志信息打印打控制台--> <console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="${LOG_PATTERN_CONSOLE}"/> <ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY"/> </console> </appenders> <loggers> <!-- 对某个具体类进行单独的配置, 需要关注 additivity 参数--> <Logger name="com.example.DemoService2" level="info" additivity="true"> <AppenderRef ref="CustomAppender"/> </Logger> <root level="info"> <AppenderRef ref="Console"/> </root> </loggers> </configuration>
上述配置文件针对原始配置文件主要有两个修改点
- 在
<appenders>
标签下面添加了<CusAppender name="CustomAppender" />
标签, 这里使用CusAppender
标签是因为@Plugin(name = "CusAppender"
中配置的是这个名字 - 在
<loggers>
标签下添加了如下内容
<!-- 对某个具体类进行单独的配置, 需要关注 additivity 参数--> <Logger name="com.example.DemoService2" level="info" additivity="true"> <AppenderRef ref="CustomAppender"/> </Logger>
通过这种方式,当 DemoService2
类有日志打印并且级别在 info
及以上时就会调用到自定义 Appender
的 append
方法中
public void append(LogEvent event) { // 在这里获取日志信息 String message = event.getMessage().getFormattedMessage(); // 打印日志信息 System.out.println("拦截到的消息" + message); }
additivity="true" 配置的作用
先看下 loggers
配置
<loggers> <!-- 对某个具体类进行单独的配置, 需要关注 additivity 参数--> <Logger name="com.example.DemoService2" level="info" additivity="true"> <AppenderRef ref="CustomAppender"/> </Logger> <root level="info"> <AppenderRef ref="Console"/> </root> </loggers>
这里的 root
就是顶层的配置,对于 DemoService2
类来说,因为单独配置了 Logger
, 所以会先走单独配置的 Logger
中的 Appender
, 也就是 CustomAppender
,但是 CustomAppender
中只是获取日志信息,并没有往控制台或者文件写日志,这样日志就会丢失了,additivity
参数就是用来控制是否继续使用父级的 Appender
, additivity=true
时,日志会先经过 CustomAppender
处理,然后会让父级( root
) 的 Console
处理。
结果
先调用 DemoService2
方法,然后调用 DemoService
的方法,日志打印如下
拦截到的消息test demo 2 2024-02-05 16:48:21.641 INFO 2760 --- [command-execute] c.e.DemoService2 : test demo 2 2024-02-05 16:48:34.424 INFO 2760 --- [command-execute] c.e.DemoService : test demo
说明只有调用了 DemoService2
类中日志方法时才会调用到自定义的 Appender
中
以上就是自定义log4j2中的Appender来获取日志内容的示例代码的详细内容,更多关于自定义Appender获取日志内容的资料请关注脚本之家其它相关文章!