logging - Feign 客户端请求和响应以及 URL 日志记录
问题描述
我如何记录Feign客户端请求、响应和 URL 的负载。我必须实现拦截器吗?因为我的要求是在数据库的特殊表上记录请求和响应。
解决方案
Feign 具有开箱即用的日志记录机制,可以通过简单的步骤来实现。
如果您使用的是 spring-cloud-starter-feign
FeignSlf4jLogger
用于记录。Feign 日志记录文档
根据文档,可以配置以下日志记录级别,
NONE
- 不记录(默认)。BASIC
- 仅记录请求方法和 URL 以及响应状态代码和执行时间。HEADERS
- 记录基本信息以及请求和响应标头。FULL
- 记录请求和响应的标头、正文和元数据。
注入Logger.Level
bean就足够了。
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.BASIC;
}
或者
如果您更喜欢使用配置属性来配置 all @FeignClient
,您可以使用默认的 feign 名称创建配置属性。
feign:
client:
config:
default:
loggerLevel: basic
如果您正在使用'io.github.openfeign:feign-core'
如果您正在构建 Feign 构建器,那么您可以提及logLevel(Level.BASIC)
为
Feign.builder()
.logger(new Slf4jLogger())
.logLevel(Level.BASIC)
.target(SomeFeignClient.class, url);
我们可以灵活地自定义日志消息
默认的 feign 请求和响应日志
Logger#logRequest
我们可以通过覆盖和Logger#logAndRebufferResponse
方法自定义 feign 请求、响应日志记录模式。在以下示例中,我们自定义了请求日志记录模式
log(configKey, "---> %s %s HTTP/1.1 (%s-byte body) ", request.httpMethod().name(), request.url(), bodyLength);
和响应记录模式
log(configKey, "<--- %s %s HTTP/1.1 %s (%sms) ", request.httpMethod().name(), request.url(), status, elapsedTime);
完整的例子是
import feign.Logger;
import feign.Request;
import feign.Response;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import static feign.Logger.Level.HEADERS;
@Slf4j
public class CustomFeignRequestLogging extends Logger {
@Override
protected void logRequest(String configKey, Level logLevel, Request request) {
if (logLevel.ordinal() >= HEADERS.ordinal()) {
super.logRequest(configKey, logLevel, request);
} else {
int bodyLength = 0;
if (request.requestBody().asBytes() != null) {
bodyLength = request.requestBody().asBytes().length;
}
log(configKey, "---> %s %s HTTP/1.1 (%s-byte body) ", request.httpMethod().name(), request.url(), bodyLength);
}
}
@Override
protected Response logAndRebufferResponse(String configKey, Level logLevel, Response response, long elapsedTime)
throws IOException {
if (logLevel.ordinal() >= HEADERS.ordinal()) {
super.logAndRebufferResponse(configKey, logLevel, response, elapsedTime);
} else {
int status = response.status();
Request request = response.request();
log(configKey, "<--- %s %s HTTP/1.1 %s (%sms) ", request.httpMethod().name(), request.url(), status, elapsedTime);
}
return response;
}
@Override
protected void log(String configKey, String format, Object... args) {
log.debug(format(configKey, format, args));
}
protected String format(String configKey, String format, Object... args) {
return String.format(methodTag(configKey) + format, args);
}
}
注意: 请求有效负载可以很容易地通过
String bodyText =
request.charset() != null ? new String(request.body(), request.charset()) : null;
但是在读取输入流之后要小心编写响应有效负载,Util.toByteArray(response.body().asInputStream())
然后您必须再次构造响应,例如response.toBuilder().body(bodyData).build()
. 否则,你最终会得到期望。原因是响应流被读取并在返回之前总是关闭,这就是为什么该方法被命名为logAndRebufferResponse
如何使用自定义CustomFeignRequestLogging
?
如果您正在使用仅构建假装客户端'io.github.openfeign:feign-core'
Feign.builder()
.logger(new CustomFeignRequestLogging())
.logLevel(feign.Logger.Level.BASIC);
如果您正在使用'org.springframework.cloud:spring-cloud-starter-openfeign'
@Configuration
public class FeignLoggingConfiguration {
@Bean
public CustomFeignRequestLogging customFeignRequestLogging() {
return new CustomFeignRequestLogging();
}
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.BASIC;
}
}
推荐阅读
- javascript - 像 doX(doY(doZ(data))) 这样的链接函数是不好的做法吗?
- php - SendGrid - 电子邮件不发送 / PHP
- neo4j - Neo4j: How Can I display the row position?
- google-apps-script - 将 Gmail api 与 Google 应用程序制造商集成
- r - 如何在 R 中更改箱线图的 x 轴(以便缩放)
- ios - iOS 请求始终授权仅首次显示权限警报
- html - 未能使投资组合响应
- amazon-ec2 - MiNiFi - NiFi 连接失败:未知主机异常:能够从运行 MiNiFi 的机器远程登录主机
- c++ - 如何在构造函数中初始化结构数据成员?
- javascript - 随机函数在 JavaScript 中不起作用