问题
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.
回答1:
Feign has out of box logging mechanism and it can be achieved through simple steps.
If you are using spring-cloud-starter-feign
Feign using Slf4jLogger
for logging.Feign logging documentation
As per doc, the below logging levels are available to configure,
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.
Injecting the Logger.Level
bean is enough.
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.BASIC;
}
OR
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
If you are using 'io.github.openfeign:feign-core'
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);
We have the flexibility to customize the logging message
The default feign request and response logging
Request logging
Resopnse logging
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);
and response logging pattern
log(configKey, "<--- %s %s HTTP/1.1 %s (%sms) ", request.httpMethod().name(), request.url(), status, elapsedTime);
The Full example is
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);
}
}
NOTE: Request payload can be easily logged through
String bodyText =
request.charset() != null ? new String(request.body(), request.charset()) : null;
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 ready fully and always closed before returning, thats why the method is named as logAndRebufferResponse
回答2:
There is no interceptor for Feign client response. The request interceptor the only available for Feign client.
The best solution will be by using RestTemplate rather than Feign:
@Configuration
public class RestConfiguration {
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate
= new RestTemplate(
new BufferingClientHttpRequestFactory(
new SimpleClientHttpRequestFactory()
)
);
List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
if (CollectionUtils.isEmpty(interceptors)) {
interceptors = new ArrayList<>();
}
interceptors.add(new UserRestTemplateClientInterceptor());
restTemplate.setInterceptors(interceptors);
return restTemplate;
}
}
And the @Autowire the restTemplate where you want to use as the following:
@Autowire
RestTemplate restTemplate;
回答3:
Feign provides a Logger
interface that can log the full Request and Response. You will need to set the Logger.Level
in the Feign Builder or Configuration.
Feign.builder()
.logLevel(Logger.Level.FULL) // this will log the request and response
.target(MyApi, "my host");
来源:https://stackoverflow.com/questions/55624692/feign-client-request-and-response-and-url-logging