洞察如何选择适合你的企业的小程序开源框架来实现高效开发与管理
1499
2022-09-28
全局记录Feign的请求和响应日志方式
目录1、项目里定义FeignClient接口2、单个FeignClient接口开启日志3、所有FeignClient接口 开启日志3.1、修改FeignConfiguration3.2、还是修改 application.yml 配置3.3、OK了,此时项目里4、重写FeignClient输出日志5、使用Aspect切面输出日志
项目里使用了Feign进行远程调用,有时为了问题排查,需要开启请求和响应日志
下面简介一下如何开启Feign日志:
注:本文基于
spring-boot-starter-parent 2.3.4.RELEASEspring-cloud-starter-openfeign 2.2.3.RELEASE
1、项目里定义FeignClient接口
package com.example.demo.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient(name = "deom", url = "https://baidu.com")
public interface FeignDemo {
@GetMapping("/")
String test();
}
2、单个FeignClient接口开启日志
在 application.yml 里指定Feign接口日志级别为DEBUG,类型为FULL:
注:com.example.demo.feign.FeignDemo就是上面定义的FeignClient接口
logging:
level:
com.example.demo.feign.FeignDemo: debug
# 下面的配置,也可以写代码代替
# @Bean
# public Logger.Level level() { return Logger.Level.FULL; }
feign:
client:
config:
default:
loggerLevel: full
OK了,重启项目,调用 FeignDemo.test() 方法后,会输出如下日志:
2020-10-13 11:46:24.161 DEBUG 20824 --- [nio-8080-exec-4] com.example.demo.feign.FeignDemo : [FeignDemo#test] ---> GET https://baidu.com HTTP/1.12020-10-13 11:46:24.162 DEBUG 20824 --- [nio-8080-exec-4] com.example.demo.feign.FeignDemo : [FeignDemo#test] ---> END HTTP (0-byte body)2020-10-13 11:46:24.255 DEBUG 20824 --- [nio-8080-exec-4] com.example.demo.feign.FeignDemo : [FeignDemo#test] <--- HTTP/1.1 200 OK (93ms)2020-10-13 11:46:24.255 DEBUG 20824 --- [nio-8080-exec-4] com.example.demo.feign.FeignDemo : [FeignDemo#test] content-length: 24432020-10-13 11:46:24.255 DEBUG 20824 --- [nio-8080-exec-4] com.example.demo.feign.FeignDemo : [FeignDemo#test] content-type: text/html2020-10-13 11:46:24.256 DEBUG 20824 --- [nio-8080-exec-4] com.example.demo.feign.FeignDemo : [FeignDemo#test] date: Tue, 13 Oct 2020 03:46:24 GMT2020-10-13 11:46:24.256 DEBUG 20824 --- [nio-8080-exec-4] com.example.demo.feign.FeignDemo : [FeignDemo#test] server: bfe2020-10-13 11:46:24.256 DEBUG 20824 --- [nio-8080-exec-4] com.example.demo.feign.FeignDemo : [FeignDemo#test] 2020-10-13 11:46:24.257 DEBUG 20824 --- [nio-8080-exec-4] com.example.demo.feign.FeignDemo : [FeignDemo#test]
©2017 Baidu 使用百度前必读 意见反馈 京ICP证030173号
3、所有FeignClient接口 开启日志
上面的方法,只能开启单个FeignClient接口,如果项目里有10个接口,那么要在yml里配置10项,而且以后添加新的FeignClient,还要记得去修改yml配置,太麻烦。
所以,下面是开启所有FeignClient接口日志的配置:
3.1、修改FeignConfiguration
自定义feign.Logger,如下:
package com.example.demo.cacheDemo;
import feign.slf4j.Slf4jLogger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfiguration {
@Bean
public feign.Logger logger() {
return new Slf4jLogger();
}
}
3.2、还是修改 application.yml 配置
logging:
level:
# 删除具体的FeignClient接口配置,只保留这一个就好了
feign.Logger: debug
# 也可以写代码代替
# @Bean
# public Logger.Level level() { return Logger.Level.FULL; }
feign:
client:
config:
default:
loggerLevel: full
3.3、OK了,此时项目里
不管新增多少个 FeignClient,都会输出日志。
4、重写FeignClient输出日志
根据上面输出的日志,可以看到是多条INFO日志,在并发时,很有可能会互相干扰,而且格式也无法调整。
我们知道,Feign默认情况下,是使用 feign.Client.Default 发起http请求;
我们可以重写Client,并注入Bean来替换掉 feign.Client.Default,从而实现日志记录,当然也可以做其它任意事情了,比如添加Header。下面是注入Bean的代码:
// 默认不注入,如果yml配置里有 logging.level.beinet-.demostudy.MyClient 才注入
@Bean
@ConditionalOnProperty("logging.level.beinet-.demostudy.MyClient")
MyClient getClient() throws NoSuchAlgorithmException, KeyManagementException {
// 忽略SSL校验
SSLContext ctx = SSLContext.getInstance("SSL");
X509TrustManager tm = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
ctx.init(null, new TrustManager[]{tm}, null);
return new MyClient(ctx.getSocketFactory(), (hostname, sslSession) -> true);
}
下面是重写的Client完整代码:
package beinet-.demostudy;
import feign.Client;
import feign.Request;
import feign.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StreamUtils;
import javax-.ssl.HostnameVerifier;
import javax-.ssl.SSLSocketFactory;
import java.io.*;
import java.util.Collection;
import java.util.Map;
@Slf4j
public class MyClient extends Client.Default {
public MyClient(SSLSocketFactory socketFactory, HostnameVerifier hostnameVerifier) {
super(socketFactory, hostnameVerifier);
}
@Override
public Response execute(Request request, Request.Options options) throws IOException {
StringBuilder sb = new StringBuilder("[log started]\r\n");
sb.append(request.httpMethod()).append(" ").append(request.url()).append("\r\n");
CombineHeaders(sb, request.headers()); // 请求Header
CombineBody(sb, request.body());
long costTime = -1;
Exception exception = null;
BufferingFeignClientResponse response = null;
long begin = System.currentTimeMillis();
try {
response = new BufferingFeignClientResponse(super.execute(request, options));
costTime = (System.currentTimeMillis() - begin);
} catch (Exception exp) {
costTime = (System.currentTimeMillis() - begin);
exception = exp;
throw exp;
} finally {
sb.append("\r\nResponse cost time(ms): ").append(String.valueOf(costTime));
if (response != null)
sb.append(" status: ").append(response.status());
sb.append("\r\n");
if (response != null) {
CombineHeaders(sb, response.headers()); // 响应Header
sb.append("Body:\r\n").append(response.body()).append("\r\n");
}
if (exception != null) {
sb.append("Exception:\r\n ").append(exception.getMessage()).append("\r\n");
}
sb.append("\r\n[log ended]");
log.debug(sb.toString());
}
Response ret = response.getResponse().toBuilder()
.body(response.getBody(),
response.getResponse().body().length()).build();
response.close();
return ret;
}
private static void CombineHeaders(StringBuilder sb, Map
if (headers != null && !headers.isEmpty()) {
sb.append("Headers:\r\n");
for (Map.Entry
for (String val : ob.getValue()) {
sb.append(" ").append(ob.getKey()).append(": ").append(val).append("\r\n");
}
}
}
}
private static void CombineBody(StringBuilder sb, byte[] body) {
if (body == null || body.length <= 0)
return;
sb.append("Body:\r\n").append(new String(body)).append("\r\n");
}
static final class BufferingFeignClientResponse implements Closeable {
private Response response;
private byte[] body;
private BufferingFeignClientResponse(Response response) {
this.response = response;
}
private Response getResponse() {
return this.response;
}
private int status() {
return this.response.status();
}
private Map
return this.response.headers();
}
private String body() throws IOException {
StringBuilder sb = new StringBuilder();
try (InputStreamReader reader = new InputStreamReader(getBody())) {
char[] tmp = new char[1024];
int len;
while ((len = reader.read(tmp, 0, tmp.length)) != -1) {
sb.append(new String(tmp, 0, len));
}
}
return sb.toString();
}
private InputStream getBody() throws IOException {
if (this.body == null) {
this.body = StreamUtils.copyToByteArray(this.response.body().asInputStream());
}
return new ByteArrayInputStream(this.body);
}
@Override
public void close() {
this.response.close();
}
}
}
输出日志示例:
2020-10-15 16:48:26.081 DEBUG 15664 --- [ main] beinet-.demostudy.MyClient : [log started]POST https://baidu.com?flg=3Headers: Content-Length: 14 Content-Type: text/plain;charset=UTF-8Body:abcde我是ddd
Response cost time(ms): 207 status: 200Headers: content-length: 2443 content-type: text/html date: Thu, 15 Oct 202DzEvA0 08:48:27 GMT server: bfeBody: 百度的html
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~