自定義log4j2中的Appender來獲取日志內(nèi)容的示例代碼
springboot版本:2.6.15 log4j版本:2.17.2
Log4j中的Appender 是什么
本文講述的是通過 log4j
中自定義的 Appender
來獲取需要打印的日志信息,那么 Appender
是什么東西呢?先簡單了解一下
在 Log4j2 中,Appender 是負(fù)責(zé)將日志事件輸出到目標(biāo)地點(diǎn)的組件。Appender 可以將日志事件輸出到控制臺(tái)、文件、網(wǎng)絡(luò)等不同的目的地。 Log4j2 提供了多種內(nèi)置的 Appender,例如 ConsoleAppender、FileAppender、AsyncAppender 等,同時(shí)支持自定義 Appender。 Appender 的主要職責(zé)是將日志事件按照指定的格式和目的地輸出。每個(gè) Appender 都有自己的名稱和類型,可以根據(jù)需要配置不同的屬性。例如,F(xiàn)ileAppender 用于將日志事件輸出到文件中,其屬性包括文件名、追加模式(是否覆蓋已存在的文件或追加到文件末尾)等。
需求背景
有兩個(gè)系統(tǒng),系統(tǒng) A
和系統(tǒng) B
, 系統(tǒng) A
會(huì)發(fā)送指令給系統(tǒng) B
, 系統(tǒng) B
會(huì)響應(yīng)結(jié)果給系統(tǒng) A
,這兩個(gè)系統(tǒng)之間的通信方式是 MQ
, 即 A
通過 MQ
發(fā)送數(shù)據(jù)給 B
(數(shù)據(jù)中有 UUID
字段值),系統(tǒng) B
處理完成后將結(jié)果通過 MQ
發(fā)送給 A
,請(qǐng)求和響應(yīng)的對(duì)應(yīng)關(guān)系則可以通過 UUID
來進(jìn)行匹配
現(xiàn)在有一個(gè)需求是監(jiān)控在某個(gè)時(shí)間段內(nèi)發(fā)送了多少指令,以及多少指令失敗(在給定時(shí)間內(nèi)沒有收到響應(yīng)或者響應(yīng)中給了錯(cuò)誤結(jié)果認(rèn)為失敗)
對(duì)于這種需求一般都是通過 AOP
來解決,但是在部分場景下 AOP
也比較難處理,比如上面場景中其實(shí)這個(gè)監(jiān)控處理是有兩部分的,第一部分是發(fā)送請(qǐng)求,第二部分是獲取請(qǐng)求對(duì)應(yīng)的結(jié)果,而且不是 http
調(diào)用,是通過 MQ
調(diào)用,即業(yè)務(wù)邏輯實(shí)現(xiàn)是分布在兩個(gè)方法中的 (可以抽取一層將發(fā)送請(qǐng)求和響應(yīng)結(jié)果邏輯放在一起,并且返回原始結(jié)果即可)
下面基于已有實(shí)現(xiàn)提供另外一種更簡單的解決方式,已有實(shí)現(xiàn)的特點(diǎn):
- 指令發(fā)送和結(jié)果接收都被抽取成獨(dú)立的方法,只要是兩個(gè)系統(tǒng)間的
MQ
通信最終都會(huì)調(diào)用這兩個(gè)方法(一個(gè)發(fā)送,一個(gè)接收結(jié)果) - 在這兩個(gè)方法中都將原始的參數(shù)以及最終的響應(yīng)結(jié)果給打印出來了 基于以上兩點(diǎn),如果可以拿到打印的日志信息就可以比較簡單匯總處理
修改前測試代碼
log4j2 配置文件
下面 log4j2-dev.xml
配置文件很簡單,就是將所有日志打印到控制臺(tái),日志級(jí)別為 info
<?xml version="1.0" encoding="UTF-8"?> <!--monitorInterval:Log4j能夠自動(dòng)檢測修改配置 文件和重新配置本身,設(shè)置間隔秒數(shù)--> <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 是將日志信息打印打控制臺(tái)--> <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>
兩個(gè)測試類代碼
給出兩個(gè)測試類是為了對(duì)比,后續(xù)自定義的 Appender
只會(huì)作用在一個(gè)測試類中,對(duì)于其他類的日志打印不會(huì)獲取到對(duì)應(yīng)的日志信息
@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能夠自動(dòng)檢測修改配置 文件和重新配置本身,設(shè)置間隔秒數(shù)--> <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 是將日志信息打印打控制臺(tái)--> <console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="${LOG_PATTERN_CONSOLE}"/> <ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY"/> </console> </appenders> <loggers> <!-- 對(duì)某個(gè)具體類進(jìn)行單獨(dú)的配置, 需要關(guān)注 additivity 參數(shù)--> <Logger name="com.example.DemoService2" level="info" additivity="true"> <AppenderRef ref="CustomAppender"/> </Logger> <root level="info"> <AppenderRef ref="Console"/> </root> </loggers> </configuration>
上述配置文件針對(duì)原始配置文件主要有兩個(gè)修改點(diǎn)
- 在
<appenders>
標(biāo)簽下面添加了<CusAppender name="CustomAppender" />
標(biāo)簽, 這里使用CusAppender
標(biāo)簽是因?yàn)?@Plugin(name = "CusAppender"
中配置的是這個(gè)名字 - 在
<loggers>
標(biāo)簽下添加了如下內(nèi)容
<!-- 對(duì)某個(gè)具體類進(jìn)行單獨(dú)的配置, 需要關(guān)注 additivity 參數(shù)--> <Logger name="com.example.DemoService2" level="info" additivity="true"> <AppenderRef ref="CustomAppender"/> </Logger>
通過這種方式,當(dāng) DemoService2
類有日志打印并且級(jí)別在 info
及以上時(shí)就會(huì)調(diào)用到自定義 Appender
的 append
方法中
public void append(LogEvent event) { // 在這里獲取日志信息 String message = event.getMessage().getFormattedMessage(); // 打印日志信息 System.out.println("攔截到的消息" + message); }
additivity="true" 配置的作用
先看下 loggers
配置
<loggers> <!-- 對(duì)某個(gè)具體類進(jìn)行單獨(dú)的配置, 需要關(guān)注 additivity 參數(shù)--> <Logger name="com.example.DemoService2" level="info" additivity="true"> <AppenderRef ref="CustomAppender"/> </Logger> <root level="info"> <AppenderRef ref="Console"/> </root> </loggers>
這里的 root
就是頂層的配置,對(duì)于 DemoService2
類來說,因?yàn)閱为?dú)配置了 Logger
, 所以會(huì)先走單獨(dú)配置的 Logger
中的 Appender
, 也就是 CustomAppender
,但是 CustomAppender
中只是獲取日志信息,并沒有往控制臺(tái)或者文件寫日志,這樣日志就會(huì)丟失了,additivity
參數(shù)就是用來控制是否繼續(xù)使用父級(jí)的 Appender
, additivity=true
時(shí),日志會(huì)先經(jīng)過 CustomAppender
處理,然后會(huì)讓父級(jí)( root
) 的 Console
處理。
結(jié)果
先調(diào)用 DemoService2
方法,然后調(diào)用 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
說明只有調(diào)用了 DemoService2
類中日志方法時(shí)才會(huì)調(diào)用到自定義的 Appender
中
以上就是自定義log4j2中的Appender來獲取日志內(nèi)容的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于自定義Appender獲取日志內(nèi)容的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring Boot應(yīng)用Docker化的步驟詳解
這篇文章主要給大家介紹了關(guān)于Spring Boot應(yīng)用Docker化的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-04-04Java Object定義三個(gè)點(diǎn)實(shí)現(xiàn)代碼
這篇文章主要介紹了Java Object定義三個(gè)點(diǎn)實(shí)現(xiàn)代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09Lombok不生效,提示java:?找不到符號(hào)的解決方案
這篇文章主要介紹了Lombok不生效,提示java:?找不到符號(hào)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07記一次集成swagger2(Knife4j)在線文檔提示:Knude4j文檔請(qǐng)求異常的解決辦法
Knife4j是一個(gè)集Swagger2 和 OpenAPI3為一體的增強(qiáng)解決方案,下面這篇文章主要給大家介紹了關(guān)于一次集成swagger2(Knife4j)在線文檔提示:Knude4j文檔請(qǐng)求異常的解決辦法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-02-02SpringBoot在idea中的 .idea和 .iml文件的作用
本文主要介紹了SpringBoot在idea中的 .idea和 .iml文件,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-08-08spring boot 自動(dòng)更新靜態(tài)文件和后臺(tái)代碼的實(shí)例
下面小編就為大家分享一篇spring boot 自動(dòng)更新靜態(tài)文件和后臺(tái)代碼的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-12-12Java中的StringTokenizer實(shí)現(xiàn)字符串切割詳解
這篇文章主要介紹了Java中的StringTokenizer實(shí)現(xiàn)字符串切割詳解,java.util工具包提供了字符串切割的工具類StringTokenizer,Spring等常見框架的字符串工具類(如Spring的StringUtils),需要的朋友可以參考下2024-01-01Java將對(duì)象保存到文件中/從文件中讀取對(duì)象的方法
下面小編就為大家?guī)硪黄狫ava將對(duì)象保存到文件中/從文件中讀取對(duì)象的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-12-12