概要
Springフレームワークで提供されているRestTemplate
によるWebAPIの実行をログ出力したい。
環境
- Java 8
- SpringBoot 2.1.3.RELEASE
- Spring 5.1.5.RELEASE
- Lombok 1.18.6
RestTemplate
にClientHttpRequestInterceptor
を差し込む
-
RestTemplate
のリクエスト・レスポンスに介入するインターセプタを利用する
ログ出力を行うインターセプタ
-
注意点
- レスポンスボディは一回しか読めない。ログ出力のためにインターセプタでレスポンスボディを読み込むと、
RestTemplate
の呼び出し元には空のボディが返ってしまう。- 後述のBean定義における
BufferingClientHttpRequestFactory
の設定で回避する。
- 後述のBean定義における
- レスポンスボディは一回しか読めない。ログ出力のためにインターセプタでレスポンスボディを読み込むと、
RestTemplateのインターセプタ
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.StreamUtils;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
@Slf4j
public class RestTemplateLoggingInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution) throws IOException {
val requestUuid = UUID.randomUUID();
logRequest(requestUuid, request, body);
val response = execution.execute(request, body);
logResponse(requestUuid, response);
return response;
}
private void logRequest(UUID requestUuid, HttpRequest request, byte[] body) {
if (log.isInfoEnabled()) {
log.info("[API:Request({})] Request=[{}:{}], Headers=[{}], Body=[{}]",
requestUuid,
request.getMethod(),
request.getURI(),
request.getHeaders(),
new String(body)
);
}
}
private void logResponse(UUID requestUuid, ClientHttpResponse response) throws IOException {
if (log.isInfoEnabled()) {
log.info("[API:Response({})] Status=[{}:{}], Headers=[{}], Body=[{}]",
requestUuid,
response.getStatusCode().value(),
response.getStatusText(),
response.getHeaders(),
StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8)
);
}
}
}
RestTemplate
のBean定義
- ログ出力を行うインターセプタを設定した
RestTemplate
をBean定義する。-
BufferingClientHttpRequestFactory
を利用し、ログ出力インターセプタの問題を回避する。
-
@Configuration
public class ExternalApiConfig {
@Bean
RestTemplate restTemplate() {
return new RestTemplateBuilder()
.requestFactory(() -> new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()))
.additionalInterceptors(new RestTemplateLoggingInterceptor())
.build();
}
}