问题描述
我如何记录伪装客户请求,响应和URL的有效负载.我必须实现拦截器吗?因为我的要求是将请求和响应记录在数据库的特殊表上.
How I can log the payload of Feign client request, response and URL. do I have to Implement an Interceptor? Because my requirement is logging the request and response on a special table on the database.
推荐答案
Feign具有开箱即用的日志记录机制,可以通过简单的步骤来实现.
Feign has out of box logging mechanism and it can be achieved through simple steps.
如果您使用的是spring-cloud-starter-feign
使用Slf4jLogger
伪装进行日志记录.伪装日志文档
Feign using Slf4jLogger
for logging.Feign logging documentation
根据文档,可以配置以下日志记录级别,
As per doc, the below logging levels are available to configure,
-
NONE
-无日志记录(默认). -
BASIC
-仅记录请求方法和URL以及响应状态代码和执行时间. -
HEADERS
-记录基本信息以及请求和响应标头. -
FULL
-记录请求和响应的标头,正文和元数据.
NONE
- No logging (DEFAULT).BASIC
- Log only the request method and URL and the response status code and execution time.HEADERS
- Log the basic information along with request and response headers.FULL
- Log the headers, body, and metadata for both requests and responses.
注入Logger.Level
bean就足够了.
Injecting the Logger.Level
bean is enough.
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.BASIC;
}
OR
如果您希望使用配置属性来配置所有@FeignClient
,则可以使用默认伪名称创建配置属性.
If you prefer using configuration properties to configured all @FeignClient
, you can create configuration properties with default feign name.
feign:
client:
config:
default:
loggerLevel: basic
如果您使用的是'io.github.openfeign:feign-core'
If you are using 'io.github.openfeign:feign-core'
如果您要构建Feign构建器,则可以将logLevel(Level.BASIC)
称为
If you are constructing the Feign builder then you can mention logLevel(Level.BASIC)
as
Feign.builder()
.logger(new Slf4jLogger())
.logLevel(Level.BASIC)
.target(SomeFeignClient.class, url);
我们可以灵活地自定义日志消息
默认的伪装请求和响应日志记录
The default feign request and response logging
我们可以通过覆盖Logger#logRequest
和Logger#logAndRebufferResponse
方法来自定义伪装请求,响应日志记录模式.在以下示例中,我们定制了请求记录模式
we can customize the feign request, response logging pattern by overriding Logger#logRequest
and Logger#logAndRebufferResponse
methods. In the following example, we have customized request logging pattern
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
but be careful writing the response payload after you are reading the input stream Util.toByteArray(response.body().asInputStream())
then you have to construct the response again like response.toBuilder().body(bodyData).build()
. Otherwise, you will end up with the expection. The reason is response streams are read and always closed before returning, thats why the method is named as logAndRebufferResponse
这篇关于伪装客户端请求和响应以及URL记录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!