https://rarejob-tech-dept.hatenablog.com/entry/2020/03/19/190000#リクエストにユニークなIDを付与し紐付けができるようにする

マイクロサービスにおけるロギングの方針に関して記載している日本語の記事が少なく感じたので、はじめに調べた結果のまとめを記載します。

リクエストにユニークなIDを付与し紐付けができるようにする

マイクロサービスでは、あるサービスAがサービスBを呼びさらにサービスCを呼ぶといった形になるので、呼び出しチェーンにユニークなIDを与えることで調査の見通しが良くなります。

このとき、アプリケーションがHTTPレスポンスなどでエラーを返す場合にもリクエストのユニークIDを入れると良いようです。そうすることで、問題が発生し際ユーザが受け取ったエラーとユニークIDを素早く紐付けて調査を開始することができます。

ユニークなIDをどこでどのように生成かということも重要なポイントでしょう。原則としてはユニークIDでの追跡範囲のエントリーポイントとなる箇所で生成します。そしてそういった箇所で利用されるロードバランサのサービス(AWSではELB)やKongなどのAPI Gatewayミドルウェアプラグイン的にCorrelation ID(ユニークID)生成の機能を提供しているので、それを利用するのが一般的なようです。そういった機能では、生成したユニークIDをオリジナルのHTTPヘッダーへ挿入します。

ログは一箇所に集める

上述での各サービスが出力するユニークID付きのログを横断的に調査するために、各サービスのログを一箇所に集中させることが次に重要になります。

このとき、アプリケーションがPush型として能動的にHTTPリクエストなどを使って集約場所へ登録するのではなく、ローカルストレージのファイルやAmazon Elastic File Systemといったクラウドのストレージに一旦預けた後に、LogstashFluentdといったツールで集約場所へ連携することが望ましいとのことです。そうすることで、アプリケーションからログ集約という役割を切り離すことができます。

以下の図はここまでの2つのポイントを踏まえた構成の一例です。Amazon ELBがCorrelation ID(ユニークID)を生成しマイクロサービスサービス間で伝搬され、出力されたログはCloudWatch Logs Subscriptionの機能でElasticsearch Serviceへと集約させています。

ログデータを構造化する

マイクロサービスではログに持たせるフィールドは柔軟にしておきたい一方で、サービス共通でロギングデータのパースができるようにもしておきたいです。

そこでサービス共通でログデータのフォーマットを合わせましょう。JSONやLTSVといった構造化の形式を統一させることで持たせるフィールドも柔軟になり、共通で必須なフィールドを容易にパースすることができます。

ログに有益な情報を持たせる

マイクロサービスアーキテクチャにおいてログ情報として持つことが望ましいフィールドが以下になります。

どのサービスでも共通で持つのが望ましいフィールド

リクエストのエントリーポイントとなるサービスで持つのが望ましいフィールド

Go言語での実装例