WebApiに対するRequestとResponseをログに出したい。WebApiを叩く処理でログ出力するのが面倒なので、SpringのRestTemplateにログを出力するInterceptorを足して対応してみた。

試してないですが logging: level: org.springframework.web.client.RestTemplate: DEBUG でDebugにするとRequestとResponseがログに出せたりするらしい。ただ、ログに出したいだけならこっちのほうが簡単かも。

Java8でSpring boot 1.5.6を使ってます。

RestTemplateの設定

ログ出力をする様にClientHttpRequestInterceptorを実装して、RestTemplateに設定します。ログ出力はお好みで。

clientHttpRequestExecution.execute(httpRequest, bytes) の結果が1度しか読めないのでWrapperを定義してます。

@Configuration
public class WebApiClientConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplateBuilder().additionalInterceptors(
Collections.singletonList(new LoggingClientHttpRequestInterceptor())).build();
}

@Slf4j
private static class LoggingClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
log.info("Request: URI={}, Headers={}, Body={}", httpRequest.getURI(), httpRequest.getHeaders(), new String(bytes));
ClientHttpResponse response = new BufferingClientHttpResponseWrapper(clientHttpRequestExecution.execute(httpRequest, bytes));
if (!response.getStatusCode().is2xxSuccessful()) {
throw new RuntimeException("Api failed. Response: Status=" + response.getStatusCode() +
", Body=" + StreamUtils.copyToString(response.getBody(), Charset.defaultCharset()));
}
log.info("Response: Body={}", StreamUtils.copyToString(response.getBody(), Charset.defaultCharset()));
return response;
}
}

private static class BufferingClientHttpResponseWrapper implements ClientHttpResponse {
private final ClientHttpResponse response;
private byte[] body;

public BufferingClientHttpResponseWrapper(ClientHttpResponse response) {
this.response = response;
}

public HttpStatus getStatusCode() throws IOException {
return this.response.getStatusCode();
}

public int getRawStatusCode() throws IOException {
return this.response.getRawStatusCode();
}

public String getStatusText() throws IOException {
return this.response.getStatusText();
}

public HttpHeaders getHeaders() {
return this.response.getHeaders();
}

public InputStream getBody() throws IOException {
if (this.body == null) {
this.body = StreamUtils.copyToByteArray(this.response.getBody());
}
return new ByteArrayInputStream(this.body);
}

public void close() {
this.response.close();
}
}
}

使ってみる

ログが出るか確認するだけの適当なクラスとメソッドを作る。

@Component
public class GithubClient {
@Autowired
private RestTemplate restTemplate;

public String getHome() {
return restTemplate.getForObject("https://github.com/ishiis", String.class);
}
}

テストする。

@RunWith(SpringRunner.class)
@SpringBootTest
public class GithubClientTest {
@Autowired
private GithubClient githubClient;

@Test
public void testGetHome() {
Assert.assertNotNull(githubClient.getHome());
}
}

テストを実行すると、

Request: URI=https://github.com/ishiis, Headers={Accept=[text/plain, application/json, application/*+json, */*], Content-Length=[0]}, Body=

といった感じのログが出るはず。

おわり。

参考

  1. https://stackoverflow.com/questions/7952154/spring-resttemplate-how-to-enable-full-debugging-logging-of-requests-responses