Feign自定义打印请求响应log

需求如下:

1,项目启动时打印项目中使用feignclient的name及url相关信息

2,在调用feignclient方法时,打印request, response信息,并有开关来控制此项功能,因为并不是所有feignclient都需要打印request, response,所以颗粒度需要细化到具体的feignclient

实现方案:

需求1:

方案1: 此种方式只能打印项目中注入的feignclient信息


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cloud.openfeign.FeignClientSpecification;
import org.springframework.stereotype.Component;import java.lang.reflect.Proxy;
import java.util.Set;@Component
@Slf4j
public class FeignClientInfoPrinter implements BeanPostProcessor {@Autowiredprotected Set<FeignClientSpecification> feignClientSpecificationList;@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof Proxy &&  feignClientSpecificationList.stream().anyMatch(x -> x.getClassName().equals(beanName))){log.info("Information about feign client: {}", bean);}return bean;}
}// 打印示例如下:
// Information about feign client: HardCodedTarget(type=XXServiceClient, name=XXClient, url=https://xxxx/)

方案2: 此种方式可以打印项目中所有的feignclient信息

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.FeignClientFactoryBean;import javax.annotation.PostConstruct;
import java.util.Set;@Component
@Slf4j
public class FeignClientInfoPrinter {@Autowiredprotected Set<FeignClientFactoryBean> feignClientFactoryBeans;@PostConstructpublic void init() {feignClientFactoryBeans.forEach(x -> log.info("Information about feign client: {}, {}, {}", x.getObjectType(), x.getName(), x.getUrl()));}
}

需求2:

首先我们需要配置两个开关,

feign.third-party-logger:true #此开关开启代表允许此功能启用
feign.third-party-name:XXServiceClient, OOServiceClient... #此开关用来定义哪些feignclient类允许调用方法时打印请求响应体

代码如下:

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class FeignConfiguration {@Bean@ConditionalOnProperty(value = "feign.third-party-logger", havingValue = "true")FeignThirdPartyLogger createMyLogger() {return new FeignThirdPartyLogger();}}
import feign.Logger;
import feign.Request;
import feign.Response;
import feign.Util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map;import static feign.Util.decodeOrDefault;
import static feign.form.util.CharsetUtil.UTF_8;@Slf4j
public class FeignThirdPartyLogger extends Logger {@Value("#{'${feign.third-party-name}'.split(',')}")List<String> feignThirdName;@Overrideprotected void logRequest(String configKey, Level logLevel, Request request) {if(!CollectionUtils.isEmpty(feignThirdName) && feignThirdName.contains(configKey.split("#")[0])){byte[] arrBody = request.body();String body = arrBody == null ? "" : new String(arrBody);log.info("[feign log request started]\n{} Request URL: {}\nRequest Body:\n{}",request.httpMethod(),request.url(),body);}}@Overrideprotected Response logAndRebufferResponse(String configKey,Level logLevel,Response response,long elapsedTime) {if(!CollectionUtils.isEmpty(feignThirdName) && feignThirdName.contains(configKey.split("#")[0])){int status = response.status();String content = "";if (response.body() != null && !(status == 204 || status == 205)) {byte[] bodyData;try {bodyData = Util.toByteArray(response.body().asInputStream());} catch (IOException e) {throw new RuntimeException(e);}if (bodyData.length > 0) {content = decodeOrDefault(bodyData, UTF_8, "Binary data");}response = response.toBuilder().body(bodyData).build();}log.info("[feign log request ended]\ncost time(ms): {} status:{} from {} {}\nResponse Body:\n{}",elapsedTime,status,response.request().httpMethod(),response.request().url(),content);return response;}else{return response;}}@Overrideprotected void log(String configKey, String format, Object... args) {}// 该方法可以打印header中的信息private static String CombineHeaders(Map<String, Collection<String>> headers) {StringBuilder sb = new StringBuilder();if (headers != null && !headers.isEmpty()) {sb.append("Headers:\r\n");for (Map.Entry<String, Collection<String>> ob : headers.entrySet()) {for (String val : ob.getValue()) {sb.append("  ").append(ob.getKey()).append(": ").append(val).append("\r\n");}}}return sb.toString();}
}

部分代码参考于:全局记录Feign的请求和响应日志_feign 日志-CSDN博客

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

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

相关文章

【DC-6靶场渗透】

文章目录 前言 一、确定靶场地址 二、信息收集 三、账号枚举并破解 四、寻找漏洞 五、反弹shell 六、提权 前言 今天做一下DC6靶场 一、确定靶场地址 1、查看靶机mac地址 2、kali使用nmap&#xff0c;arp-scan工具扫描 nmap -sn 172.16.100.0/24 arp-scan 172.16.100.0/24 I…

Kali Linux保姆级教程|零基础从入门到精通,看完这一篇就够了!(附工具包)

作为一名从事网络安全的技术人员&#xff0c;不懂Kali Linux的话&#xff0c;连脚本小子都算不上。 Kali Linux预装了数百种享誉盛名的渗透工具&#xff0c;使你可以更轻松地测试、破解以及进行与数字取证相关的任何其他工作。 今天给大家分享一套Kali Linux资料合集&#xf…

医院体检中心客户满意度抽样方法

医院体检中心客户满意度调查的抽样方法是确定调查对象的一种方式&#xff0c;以确保调查结果具有代表性。以下是一些常见的抽样方法&#xff1a; 简单随机抽样&#xff1a; 这是一种随机选择客户的方法&#xff0c;每个客户都有被选中的机会&#xff0c;且每个客户被选中的概率…

C++算法学习心得六.回溯算法(2)

1.组合总和&#xff08;39题&#xff09; 题目描述&#xff1a; 给定一个无重复元素的数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的数字可以无限制重复被选取。 说明&#xff1a; 所有数字&am…

Python 循环结构之for循环

在Python中&#xff0c;循环结构用于重复执行一段代码&#xff0c;是非常重要的编程方法&#xff0c;其中for循环是特别常用的循环结构。 一、理解&#xff1a; for循环用于遍历一个可迭代对象&#xff08;如列表、元组、字符串等&#xff09;中的元素&#xff0c;或者执行固…

深入理解单例模式:如何确保一个类只有一个实例?

欢迎来到英杰社区 https://bbs.csdn.net/topics/617804998 欢迎来到阿Q社区 https://bbs.csdn.net/topics/617897397 单例模式 前言单例模式饿汉模式懒汉模式 前言 单例模式&#xff08;Singleton Pattern&#xff09;是一种常用的设计模式&#xff0c;用于确保一个类只有一个…

【大模型评测】常见的大模型评测数据集

开源大模型评测排行榜 https://huggingface.co/spaces/HuggingFaceH4/open_llm_leaderboard 其数据是由其后端lm-evaluation-harness平台提供。 数据集 1.英文测试 MMLU https://paperswithcode.com/dataset/mmlu MMLU&#xff08;大规模多任务语言理解&#xff09…

公网对讲|酒店无线对讲系统

提高工作效率 酒店对讲机可以帮助酒店员工实现快速、有效的内部沟通&#xff0c;从而提高服务质量。例如&#xff0c;前台接待人员可以通过对讲机及时通知客房服务人员为客人提供快速入住服务&#xff0c;或者通知餐饮部门为客人提供送餐服务。此外&#xff0c;对讲机还可以帮…

我劝你千万不要去做CSGO游戏搬砖

大家好&#xff0c;我是阿阳。今天我要给大家讲解一下做CSGO游戏搬砖项目前必须知道的五个问题。作为一个做这个项目已经三年多的老手&#xff0c;我带过的搬砖学员已经有好几百人了。在这个过程中&#xff0c;也积累了不少经验和教训&#xff0c;希望能够通过这篇文章给大家一…

Oracle数据库避坑:CASE WHEN ‘ ‘ = ‘ ‘ 空字符串比较,预期的结果与判断逻辑的实现之间存在不匹配

Oracle数据库避坑&#xff1a;CASE WHEN 空字符串比较&#xff0c;预期的结果与判断逻辑的实现之间存在不匹配 1、背景2、具体示例分析3、其他相同案例4、结论 1、背景 在业务开发中&#xff0c;查询sql视图时&#xff0c;使用CASE WHEN语句判断空字符串是否不等于column…

Vue创建项目配置情况

刚开始接触vue项目创建和运行因为node版本和插件版本不一致时长遇到刚装好插件&#xff0c;项目就跑不起来的情况&#xff0c;特此记录一下 vue -V vue/cli 5.0.8 node -v v12.22.12 npm -v 6.14.16 关闭驼峰命名检查、未使用语法检查 package.json文件内容&#xff1a; {&…

数学建模常见算法的通俗理解(更新中)

目录 1.层次分析法&#xff08;结合某些属性及个人倾向&#xff0c;做出某种决定&#xff09; 1.1 粗浅理解 1.2 算法过程 1.2.1 构造判断矩阵 1.2.2 计算权重向量 1.2.3 计算最大特征根 1.2.4 计算C.I.值 1.2.5 求解C.R.值 1.2.6 判断一致性 1.2.7 计算总得分 2 神经网…

Verdaccio中,创建私服时,如何用VERDACCIO_PUBLIC_URL修改页面上资源文件的域名

更多内容&#xff0c;欢迎访问&#xff1a;Verdaccio npm私服时&#xff0c;遇到更多问题 用 Verdaccio 搭建私服时&#xff0c;当使用定义的域名访问时&#xff0c;报错&#xff0c;原因是JS等资源文件的访问域名是 127.0.0.1:4873&#xff0c;并不是我们想要的域名: 通过查看…

2024年第二届“华数杯”国际大学生数学建模竞赛 (B题 ICM)| 光伏发电分析 |数学建模完整代码+建模过程全解全析

光伏发电是一种重要的可再生能源。将太阳能转化为电力可以减少对传统能源的依赖,具有显著的环保和可持续发展优势。全球范围内,光伏发电正在迅速发展。目前,许多国家将光伏发电作为推动清洁能源转型的重要手段。这些国家在政策支持、技术创新和市场发展方面增加了对光伏发电的投…

视频改字视频制作系统,祝福视频,告白视频改字系统搭建开发定制

一、视频改字制作系统功能介绍&#xff1a; 素材同步&#xff0c;极速下载&#xff0c;会员充值&#xff0c;达人分销&#xff0c;积分系统&#xff0c;精美UI&#xff0c; 卡密兑换&#xff0c; 直播挂载&#xff0c; 五端兼容&#xff1a;微信小程序&#xff0c;抖音小程序&…

Kafka-RecordAccumulator分析

前面介绍过&#xff0c;KafkaProducer可以有同步和异步两种方式发送消息&#xff0c;其实两者的底层实现相同&#xff0c;都是通过异步方式实现的。 主线程调用KafkaProducer.send方法发送消息的时候&#xff0c;先将消息放到RecordAccumulator中暂存&#xff0c;然后主线程就…

JVM实战(23)——内存碎片优化

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 学习必须往深处挖&…

I2C总线和通信协议详解 (超详细配42张高清图+万字长文)

I2C总线和通信协议详解 (超详细配42张高清图万字长文) I2C&#xff08;Inter-Integrated Circuit&#xff09;通信总线&#xff0c;作为嵌入式系统设计中的一个关键组成部分&#xff0c;其灵活性和高效率使其在高级应用中备受青睐。本文旨在提供关于I2C通信总线的深度解析&…

认识并使用JWT

认识并使用JWT 一、互联网世界的用户认证二、对JWT的基本认知三、JWT的原理1 Header2 Payload3 Signature4 [参考资料](https://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html) 四、使用JWT1、引入依赖2、jwt的生成与解析3、测试3.1 生成jwt3.2 解析jwt 一、互…

DataXCloud部署与配置[智数通]

静态IP设置 # 修改网卡配置文件 vim /etc/sysconfig/network-scripts/ifcfg-ens33# 修改文件内容 TYPEEthernet PROXY_METHODnone BROWSER_ONLYno BOOTPROTOstatic IPADDR192.168.18.130 NETMASK255.255.255.0 GATEWAY192.168.18.2 DEFROUTEyes IPV4_FAILURE_FATALno IPV6INIT…