SpringBoot中如何打印Http請求日志
前言
在項目開發(fā)過程中經常需要使用Http協議請求第三方接口,而所有針對第三方的請求都強烈推薦打印請求日志,以便問題追蹤。最常見的做法是封裝一個Http請求的工具類,在里面定制一些日志打印,但這種做法真的比較low,本文將分享一下在Spring Boot中如何優(yōu)雅的打印Http請求日志。
一、spring-rest-template-logger實戰(zhàn)
1、引入依賴
<dependency>
<groupId>org.hobsoft.spring</groupId>
<artifactId>spring-rest-template-logger</artifactId>
<version>2.0.0</version>
</dependency>
2、配置RestTemplate
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplateBuilder()
.customizers(new LoggingCustomizer())
.build();
return restTemplate;
}
}
3、配置RestTemplate請求的日志級別
logging.level.org.hobsoft.spring.resttemplatelogger.LoggingCustomizer = DEBUG
4、單元測試
@SpringBootTest
@Slf4j
class LimitApplicationTests {
@Resource
RestTemplate restTemplate;
@Test
void testHttpLog() throws Exception{
String requestUrl = "https://api.uomg.com/api/icp";
//構建json請求參數
JSONObject params = new JSONObject();
params.put("domain", "www.baidu.com");
//請求頭聲明請求格式為json
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
//創(chuàng)建請求實體
HttpEntity<String> entity = new HttpEntity<>(params.toString(), headers);
//執(zhí)行post請求,并響應返回字符串
String resText = restTemplate.postForObject(requestUrl, entity, String.class);
System.out.println(resText);
}
}
5、日志打印
2023-06-25 10:43:44.780 DEBUG [Sleuth,b6ac76a169b1af33,b6ac76a169b1af33] 63501 --- [ main] o.h.s.r.LoggingCustomizer : Request: POST https://api.uomg.com/api/icp {"domain":"www.baidu.com"}
2023-06-25 10:43:45.849 DEBUG [Sleuth,b6ac76a169b1af33,b6ac76a169b1af33] 63501 --- [ main] o.h.s.r.LoggingCustomizer : Response: 200 {"code":200901,"msg":"查詢域名不能為空"}
{"code":200901,"msg":"查詢域名不能為空"}
可以看見,我們只是簡單的向RestTemplate中配置了LoggingCustomizer,就實現了http請求的日志通用化打印,在Request和Response中分別打印出了請求的入參和響應結果。
6、自定義日志打印格式
可以通過繼承LogFormatter接口實現自定義的日志打印格式。
RestTemplate restTemplate = new RestTemplateBuilder() .customizers(new LoggingCustomizer(LogFactory.getLog(LoggingCustomizer.class), new MyLogFormatter())) .build();
默認的日志打印格式化類DefaultLogFormatter:
public class DefaultLogFormatter implements LogFormatter {
private static final Charset DEFAULT_CHARSET;
public DefaultLogFormatter() {
}
//格式化請求
public String formatRequest(HttpRequest request, byte[] body) {
String formattedBody = this.formatBody(body, this.getCharset(request));
return String.format("Request: %s %s %s", request.getMethod(), request.getURI(), formattedBody);
}
//格式化響應
public String formatResponse(ClientHttpResponse response) throws IOException {
String formattedBody = this.formatBody(StreamUtils.copyToByteArray(response.getBody()), this.getCharset(response));
return String.format("Response: %s %s", response.getStatusCode().value(), formattedBody);
}
……
}
可以參考DefaultLogFormatter的實現,定制自定的日志打印格式化類MyLogFormatter。
二、原理分析
首先分析下LoggingCustomizer類,通過查看源碼發(fā)現,LoggingCustomizer繼承自RestTemplateCustomizer,RestTemplateCustomizer表示RestTemplate的定制器,RestTemplateCustomizer是一個函數接口,只有一個方法customize,用來擴展定制RestTemplate的屬性。
@FunctionalInterface
public interface RestTemplateCustomizer {
void customize(RestTemplate restTemplate);
}
LoggingCustomizer的核心方法customize:
public class LoggingCustomizer implements RestTemplateCustomizer{
public void customize(RestTemplate restTemplate) {
restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(restTemplate.getRequestFactory()));
//向restTemplate中注入了日志攔截器
restTemplate.getInterceptors().add(new LoggingInterceptor(this.log, this.formatter));
}
}
日志攔截器中的核心方法:
public class LoggingInterceptor implements ClientHttpRequestInterceptor {
private final Log log;
private final LogFormatter formatter;
public LoggingInterceptor(Log log, LogFormatter formatter) {
this.log = log;
this.formatter = formatter;
}
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
if (this.log.isDebugEnabled()) {
//打印http請求的入參
this.log.debug(this.formatter.formatRequest(request, body));
}
ClientHttpResponse response = execution.execute(request, body);
if (this.log.isDebugEnabled()) {
//打印http請求的響應結果
this.log.debug(this.formatter.formatResponse(response));
}
return response;
}
}
原理小結:
通過向restTemplate對象中添加自定義的日志攔截器LoggingInterceptor,使用自定義的格式化類DefaultLogFormatter來打印http請求的日志。
三、優(yōu)化改進
可以借鑒spring-rest-template-logger的實現,通過Spring Boot Start自動化配置原理, 聲明自動化配置類RestTemplateAutoConfiguration,自動配置RestTemplate。
這里只是提供一些思路,搞清楚相關組件的原理后,我們就可以輕松定制通用的日志打印組件。
@Configuration
public class RestTemplateAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplateBuilder()
.customizers(new LoggingCustomizer())
.build();
return restTemplate;
}
}
總結
這里的優(yōu)雅打印并不是針對http請求日志打印的格式,而是通過向RestTemplate中注入攔截器實現通用性強、代碼侵入性小、具有可定制性的日志打印方式。
在Spring Boot中http請求都推薦采用RestTemplate模板類,而無需自定義http請求的靜態(tài)工具類,比如HttpUtil- 推薦在配置類中采用@Bean將RestTemplate類配置成統一通用的單例對象注入到Spring 容器中,而不是每次使用的時候重新聲明。
- 推薦采用攔截器實現http請求日志的通用化打印
到此這篇關于SpringBoot中如何打印Http請求日志的文章就介紹到這了,更多相關SpringBoot打印Http請求日志內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
基于Springboot執(zhí)行多個定時任務并動態(tài)獲取定時任務信息
這篇文章主要為大家詳細介紹了基于Springboot執(zhí)行多個定時任務并動態(tài)獲取定時任務信息,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-04-04

