Spring Boot Actuator HTTPトレースを使用したHTTP要求のログ記録

1. 前書き

一般にマイクロサービスまたはWebサービスを使用する場合、ユーザーがサービスとどのように対話するかを知ることは非常に役立ちます。 これは、サービスにヒットするすべてのリクエストをトレースし、この情報を収集して後で分析することで実現できます。
link:/tracing-services-with-zipkin[Zipkin]のように、これを支援し、Springと簡単に統合できるシステムがいくつかあります。 ただし、* Spring Boot Actuatorにはこの機能が組み込まれ*、すべてのHTTP要求をトレースする_httpTrace_エンドポイントを通じて使用できます。 このチュートリアルでは、要件に合わせて使用​​する方法とカスタマイズする方法を示します。

2. _HttpTrace_エンドポイントのセットアップ

このチュートリアルでは、https://www.baeldung.com/spring-boot [Maven Spring Bootプロジェクト]を使用します。
最初に行う必要があるのは、https://search.maven.org/search?q = a:spring-boot-starter-actuator%20AND%20g:org.springframework.boot [Spring Boot Actuator依存関係]を追加することです私たちのプロジェクトに:
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
その後、アプリケーションで_httpTrace_エンドポイントを有効にする必要があります。
そのためには、application.propertiesファイルを変更して、_http Trace_エンドポイントを含める必要があります*:
management.endpoints.web.exposure.include=httptrace
さらにエンドポイントが必要な場合は、カンマで区切って連結するか、ワイルドカード_ * _を使用してすべてのエンドポイントを含めることができます。
これで、_httpTrace_エンドポイントがアプリケーションのアクチュエータエンドポイントリストに表示されます。
{
  "_links": {
    "self": {
      "href": "http://localhost:8080/actuator",
      "templated": false
    },
    "httptrace": {
      "href": "http://localhost:8080/actuator/httptrace",
      "templated": false
    }
  }
}
Webサービスの_ / actuator_エンドポイントに移動して、有効なすべてのアクチュエータエンドポイントを一覧表示できることに注意してください。

3. トレースの分析

_httpTrace_アクチュエータエンドポイントが返すトレースを分析しましょう。
サービスにいくつかのリクエストを作成し、_ / actuator / httptrace_エンドポイントを呼び出して、返されたトレースの1つを取得します。
{
  "traces": [
    {
      "timestamp": "2019-08-05T19:28:36.353Z",
      "principal": null,
      "session": null,
      "request": {
        "method": "GET",
        "uri": "http://localhost:8080/echo?msg=test",
        "headers": {
          "accept-language": [
            "en-GB,en-US;q=0.9,en;q=0.8"
          ],
          "upgrade-insecure-requests": [
            "1"
          ],
          "host": [
            "localhost:8080"
          ],
          "connection": [
            "keep-alive"
          ],
          "accept-encoding": [
            "gzip, deflate, br"
          ],
          "accept": [
            "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"
          ],
          "user-agent": [
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36 OPR/62.0.3331.66"
          ]
        },
        "remoteAddress": null
      },
      "response": {
        "status": 200,
        "headers": {
          "Content-Length": [
            "12"
          ],
          "Date": [
            "Mon, 05 Aug 2019 19:28:36 GMT"
          ],
          "Content-Type": [
            "text/html;charset=UTF-8"
          ]
        }
      },
      "timeTaken": 82
    }
  ]
}
ご覧のとおり、応答はいくつかのノードに分割されています。
  • timestamp:リクエストが受信された時刻

  • principal:要求を実行した認証済みユーザー(該当する場合)

  • session:リクエストに関連付けられたセッション

  • request:メソッドなどのリクエストに関する情報、フル
    URIまたはヘッダー

  • response:ステータスや
    ヘッダー

  • timeTaken:リクエストの処理にかかった時間

    冗長すぎると感じた場合は、この応答をニーズに適合させることができます。 _application.properties_の_management.trace.http.include_プロパティ*でフィールドを指定することで、返されるフィールドをSpringに伝えることができます。
management.trace.http.include=RESPONSE_HEADERS
この場合、応答ヘッダーのみが必要であることを指定しました。 したがって、要求ヘッダーや所要時間など、以前に含まれていたフィールドが、応答に存在しないことがわかります。
{
  "traces": [
    {
      "timestamp": "2019-08-05T20:23:01.397Z",
      "principal": null,
      "session": null,
      "request": {
        "method": "GET",
        "uri": "http://localhost:8080/echo?msg=test",
        "headers": {},
        "remoteAddress": null
      },
      "response": {
        "status": 200,
        "headers": {
          "Content-Length": [
            "12"
          ],
          "Date": [
            "Mon, 05 Aug 2019 20:23:01 GMT"
          ],
          "Content-Type": [
            "text/html;charset=UTF-8"
          ]
        }
      },
      "timeTaken": null
    }
  ]
}
含めることができるすべての可能な値は、https://github.com/spring-projects/spring-boot/blob/8bc780762a44c7d57e6ddf15abb7071f499857ce/spring-boot-project/spring-boot-actuator/src/main/javaにあります。 /org/springframework/boot/actuate/trace/http/Include.java [ソースコード]およびデフォルトのソース。

*4. HttpTraceRepository *のカスタマイズ

*デフォルトでは、_httpTrace_エンドポイントは最後の100リクエストのみを返し、それらをメモリに保存します*。 幸いなことに、独自の_HttpTraceRepository_を作成して、これをカスタマイズすることもできます。
リポジトリを作成しましょう。 _HttpTraceRepository_インターフェイスは非常にシンプルであり、2つのメソッドを実装するだけで済みます。すべてのトレースを取得する__findAll()__; __add()__を使用して、リポジトリにトレースを追加します。
簡単にするために、リポジトリはトレースもメモリに保存し、サービスにヒットする最後のGETリクエストのみを保存します。
@Repository
public class CustomTraceRepository implements HttpTraceRepository {

    AtomicReference<HttpTrace> lastTrace = new AtomicReference<>();

    @Override
    public List<HttpTrace> findAll() {
        return Collections.singletonList(lastTrace.get());
    }

    @Override
    public void add(HttpTrace trace) {
        if ("GET".equals(trace.getRequest().getMethod())) {
            lastTrace.set(trace);
        }
    }

}
この簡単な例はあまり役に立たないかもしれませんが、これがどれほど強力で、どこにログを保存できるかがわかります。

5. トレースするパスのフィルタリング

最後に説明するのは、トレースするパスをフィルタリングする方法です。したがって、興味のない要求を無視できます。
サービスにいくつかのリクエストを行った後、_httpTrace_エンドポイントを少し操作すると、アクチュエーターリクエストのトレースも取得されることがわかります。
{
  "traces": [
    {
      "timestamp": "2019-07-28T13:56:36.998Z",
      "principal": null,
      "session": null,
      "request": {
        "method": "GET",
        "uri": "http://localhost:8080/actuator/",
         // ...
}
これらのトレースは役に立たない可能性があるため、除外することをお勧めします。 その場合、独自の_HttpTraceFilter_ *を作成し、_shouldNotFilter_メソッドで*無視するパスを指定するだけです。*
@Component
public class TraceRequestFilter extends HttpTraceFilter {

  public TraceRequestFilter(HttpTraceRepository repository, HttpExchangeTracer tracer) {
      super(repository, tracer);
  }

  @Override
  protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
      return request.getServletPath().contains("actuator");
  }
}
_HttpTraceFilter_は、通常のSpringフィルターですが、トレース固有の機能を備えていることに注意してください。

6. 結論

このチュートリアルでは、_httpTrace_ Spring Boot Actuatorエンドポイントを紹介し、その主な機能を示しました。 また、もう少し掘り下げて、特定のニーズに合わせてデフォルトの動作を変更する方法を説明しました。
いつものように、例の完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/spring-boot-management[over on GitHub]で入手できます。