Spring Boot で HTTP リクエスト ログを適切に出力する方法


序文

プロジェクト開発中、HTTP プロトコルを使用してサードパーティのインターフェイスを要求する必要があることがよくありますが、サードパーティへのすべての要求については、問題追跡のために要求ログを出力することを強くお勧めします。最も一般的なアプローチは、HTTP リクエスト ツール クラスをカプセル化し、その中でログ出力をカスタマイズすることですが、このアプローチは非常に低レベルであり、この記事では Spring Boot で HTTP リクエスト ログをエレガントに出力する方法を共有します。


1. 実際の Spring-rest-template-logger

まず、github にある一般的なログ出力コンポーネント spring-rest-template-logger の使用方法を示します。

Github アドレス: Spring RestTemplate Logger

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);
        //创建请求实体
        HttpEntity<String> entity = new HttpEntity<>(params.toString(), headers);
        //执行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 をカスタマイズできます。

2. 原理分析

まず、LoggingCustomizer クラスを分析します。ソース コードを見ると、LoggingCustomizer が RestTemplateCustomizer から継承していることがわかりました。RestTemplateCustomizer は、RestTemplate のカスタマイザーを表します。RestTemplateCustomizer は、カスタマイズされた RestTemplate のプロパティを拡張するために使用される、customize という 1 つのメソッドのみを備えた関数インターフェイスです。

@FunctionalInterface
public interface RestTemplateCustomizer {
    
    
    void customize(RestTemplate restTemplate);
}

LoggingCustomizer のコア メソッドのカスタマイズ:

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;
    }
}

原則の概要:
カスタム ログ インターセプター LoggingInterceptor をrestTemplate オブジェクトに追加することで、カスタム書式設定クラス DefaultLogFormatter を使用して http 要求ログを出力します。

3. 最適化と改善

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;
    }
}

要約する

ここでのエレガントな印刷は、http リクエストのログ印刷の形式ではなく、RestTemplate にインターセプターを挿入することによる、高い汎用性、低いコード侵入、カスタマイズ性を備えたログ印刷方法です。

  • 在Spring Boot中http请求都推荐采用RestTemplate模板类、HttpUtil などの http リクエスト用の静的ツール クラスをカスタマイズする必要はありません。
  • 構成クラスで @Bean を使用して、RestTemplate クラスを統一されたユニバーサル シングルトン オブジェクトに構成し、使用するたびに再宣言するのではなく、それを Spring コンテナーに注入することをお勧めします。
  • http リクエスト ログの一般的な出力を実現するには、インターセプタを使用することをお勧めします。

おすすめ

転載: blog.csdn.net/w1014074794/article/details/131371860