반응형
Feign Client 를 사용하던 중 구현해야 할 사항 중 하나가 모든 요청, 응답에 대한 로깅이었다.
그러면서 알게된 Feign Client Logging 방법 정리
간단하게 interceptor를 사용할까! 하다가 feign의 Logger를 커스터마이징 할 수 있길래 오! 더 간단하지 않을까 해서 사용해보았다.
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);
}
}
코드는 링크의 예시 코드로 대체
로깅은 성공적으로 잘 되었다. 문제는 feign client의 logging level을 none으로 설정하니 동작하지 않는다..
그렇다고 basic으로 설정하자니 feign의 기본 로깅도 추가되어서 다시 interceptor를 사용하려고 했다.
하지만 놀랍게도 feign은 response interceptor를 제공하지 않는다. 그래서 stackoverflow의 어떤 답변에선 resttemplate을 사용하라고..
그래도 해결책은 있었는데 Client 를 override 하는 방식이었다.
public class CustomFeignClient extends Client.Default {
public CustomFeignClient(SSLSocketFactory sslContextFactory, HostnameVerifier hostnameVerifier) {
super(sslContextFactory, hostnameVerifier);
}
@Override
public Response execute(Request request, Request.Options options) throws IOException {
Response response = super.execute(request, options);
InputStream bodyStream = response.body().asInputStream();
String responseBody = StreamUtils.copyToString(bodyStream, StandardCharsets.UTF_8);
//TODO do whatever you want with the responseBody - parse and modify it
return response.toBuilder().body(responseBody, StandardCharsets.UTF_8).build();
}
}
이렇게 하면 feign client의 logging level을 none으로 설정해도 모든 요청과 응답에 대해 로깅 할 수 있다.
하지만 4xx, 5xx 에러 발생 시 execute 이후 코드는 실행되지 않아 error decoder에 따로 로깅을 추가해야 한다.
그래서 간단하게 말하면 Feign Client에서 로깅 커스터마이징 할 수 있는 방식이
- Logger extends 후 logRequest, logAndRebufferResponse 메소드 override (log level이 basic 이상 일때만 동작)
- RequestInterceptor implements 후 apply override (이건 직접 안해봄, request만 사용 가능)
- Client.Default extends하여 execute override (4xx, 5xx 에러에 대해선 error decoder에 추가해야 함)
가 있다. 물론 3개 다 Bean으로 등록해서 Configuration 등록해주어야 한다.
반응형
'Java > spring' 카테고리의 다른 글
[Spring] WireMock 을 사용한 HTTP Client 유닛테스트 (0) | 2022.12.11 |
---|---|
[Spring] Spring Batch에 Hexagonal Architecture를 적용해보자 (0) | 2022.06.06 |
[Spring] Log4j2를 이용해 로깅해보자 (0) | 2022.05.29 |
[Spring Security] FormLogin에서 Custom Filter 처리 이슈 (0) | 2022.02.21 |
[Spring Security] LoginSuccessHandler와 FailureHandler 호출 원리 (0) | 2022.02.19 |