初めに
Springでのサーバ内のHTTP通信の際にRestTemplateを使用するケースの際に
フォーマットを統一するためにHTTP通信毎に毎回同じログ出力のコードをコピペして貼っている現場があったので
少しでも同じ悲しみを背負わなくてもいいようにオンラインに実装例を残しておきます。
実装
自作インターセプターRestTemplate DIに設定
@Configuration
public class RestClientConfig {
/**
* RestTemplate
*/
@Bean
public RestTemplate restTemplate() {
return new RestTemplateBuilder()
// ここでインターセプター追加 (RestTemplateLoggingInterceptorは自作)
.additionalInterceptors(new RestTemplateLoggingInterceptor())
.build();
}
}
org.springframework.http.client.ClientHttpRequestInterceptorの実装クラス RestTemplateLoggingInterceptor を作成します
この際、ClientHttpRequestExecution#executeの内容が1度のみしか取得ができないため
BufferingClientHttpResponseWrapperのような形式で一度ラップします。
public class RestTemplateLoggingInterceptor implements ClientHttpRequestInterceptor {
public static final Logger logger = LoggerFactory.getLogger(RestTemplateLoggingInterceptor.class);
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
throws IOException {
/*
* リクエスト処理
*/
logger.info("RestTemplate Request: URI={}, Headers={}, Body={}",
request.getURI(), request.getHeaders(), new String(body));
/*
* レスポンス バッファリング
*/
ClientHttpResponse response = new BufferingClientHttpResponseWrapper(execution.execute(request, body));
StringBuilder inputStringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), "UTF-8"));
String line = bufferedReader.readLine();
while (line != null) {
inputStringBuilder.append(line);
inputStringBuilder.append('\n');
line = bufferedReader.readLine();
}
/*
* レスポンス処理
*/
if (HttpStatus.OK.equals(response.getStatusCode())) {
logger.info("RestTemplate Response: StatusCode={} {}, Headers={}, Body={}",
response.getStatusCode(),
response.getStatusText(),
response.getHeaders(),
inputStringBuilder.toString());
} else {
logger.warn("RestTemplate Response: StatusCode={} {}, Headers={}, Body={}",
response.getStatusCode(),
response.getStatusText(),
response.getHeaders(),
inputStringBuilder.toString());
}
return response;
}
private static class BufferingClientHttpResponseWrapper implements ClientHttpResponse {
private final ClientHttpResponse response;
@Nullable
private byte[] body;
BufferingClientHttpResponseWrapper(ClientHttpResponse response) {
this.response = response;
}
@Override
public HttpStatus getStatusCode() throws IOException {
return this.response.getStatusCode();
}
@Override
public int getRawStatusCode() throws IOException {
return this.response.getRawStatusCode();
}
@Override
public String getStatusText() throws IOException {
return this.response.getStatusText();
}
@Override
public HttpHeaders getHeaders() {
return this.response.getHeaders();
}
@Override
public InputStream getBody() throws IOException {
if (this.body == null) {
this.body = StreamUtils.copyToByteArray(this.response.getBody());
}
return new ByteArrayInputStream(this.body);
}
@Override
public void close() {
this.response.close();
}
}
}
これで@Autowiredで取得してきたRestTemplateは通信毎にログを吐いてくれます。
一応Githubに
サンプルを置いておきます。
スニペットとしておいてあるコードなので多少不要なコードが混じっているのでご了承ください。