paint-brush
ログ記録を正しく行う: Observability Foundation@feddena
695 測定値
695 測定値

ログ記録を正しく行う: Observability Foundation

Fedor Denisov6m2024/06/22
Read on Terminal Reader

長すぎる; 読むには

ログ記録は、アプリケーション開発において非常に重要でありながら、しばしば過小評価されるコンポーネントです。適切なログ記録の実施により、アプリケーションの可視性が向上し、内部の仕組みに対する理解が深まります。このガイドの目的は、サービスをより効果的に監視およびトラブルシューティングできるようにするための基本的な洞察と実践を提供することです。
featured image - ログ記録を正しく行う: Observability Foundation
Fedor Denisov HackerNoon profile picture

このガイドの目的は、サービスをより効果的に監視およびトラブルシューティングできるようにするための基本的な洞察と実践を提供することです。


アプリケーション開発では、ログ記録は見落とされがちですが、堅牢で監視可能なシステムを構築する上で重要な要素です。適切なログ記録を実践することで、アプリケーションの可視性を高め、内部の仕組みに対する理解を深め、アプリケーション全体の健全性を向上させることができます。


デフォルトのログ記録

アプリケーションのエントリ ポイントにデフォルトのログ記録メカニズムを組み込むことは、非常に有益です。この自動ログ記録により、重要なやり取りをキャプチャし、エントリ ポイントの引数を含めることができます。ただし、パスワードなどの機密情報をログに記録すると、プライバシーやセキュリティ上のリスクが生じる可能性があるため、注意が必要です。

一般的なエントリポイント

  • APIエンドポイント: 受信リクエストとレスポンスの詳細をログに記録する
  • バックグラウンドジョブ: ジョブの開始ポイント、実行の詳細、結果をログに記録します
  • 非同期イベント: 非同期イベントと関連するインタラクションの処理をログに記録します。

包括的なログ記録

アプリケーションが実行するすべての重要なアクション、特に状態を変更するアクションは、ログ エントリを生成する必要があります。この徹底的なログ記録アプローチは、問題が発生したときに迅速に特定して対処するための鍵であり、アプリケーションの健全性と機能性を透過的に把握できます。ログ記録をこのように入念に行うことで、診断とメンテナンスが容易になります。

適切なログレベルの選択

アプリケーションによって生成される膨大な量のデータを管理および解釈するには、適切なログ レベルを採用することが重要です。ログを重大度と関連性に基づいて分類することで、重要な問題を迅速に特定して対処できると同時に、監視作業に負担をかけずに、それほど緊急でない情報にもアクセスできるようになります。


以下はログ レベルを効果的に活用するためのガイドラインです。

レベル

説明と例

承認された使用

受け入れられません

ERROR

システム操作を停止させる致命的なイベント。例: データベース接続の喪失

重大なシステムエラー

ユーザーのログイン試行の失敗などの重大でないエラー

WARN

問題はありますが、システムは実行を続行し、要求された操作を完了できます。

問題につながる潜在的な問題

定期的な状態の変化

INFO

ユーザーアカウントの作成やデータの書き込みなど、通常のアプリケーション機能に関する洞察

状態の変化

変更なしの読み取り専用操作

DEBUG

プロセスの開始/終了などの詳細な診断情報

プロセスステップのログ記録はシステム状態を変更しない

定期的な状態変更または高頻度の操作

TRACE

メソッドのエントリ/終了を含む最も詳細なレベル

プロセスの流れと詳細を理解する

機密情報の記録

ログに記録する ID - 階層的アプローチ

アプリケーションでアクションをログに記録する場合、直接関係するエンティティの ID を含めることは、ログ情報をデータベース データにリンクするために重要です。階層的なアプローチでは、項目を親グループまたはカテゴリにリンクすることで、アプリケーションの特定の部分に関連付けられているすべてのログをすばやく見つけることができます。


たとえば、メッセージの送信に失敗したときにチャットの ID のみを記録するのではなく、チャット ルームの ID とそれが属する会社の ID も記録する必要があります。こうすることで、より多くのコンテキストが得られ、問題のより広範な影響を把握できます。

ログエントリの例:

Failed to send the message - chat=$roomId, chatRoomId=chatRoomId, company=$companyId

生産ログの例

以下は、階層的アプローチを使用した場合の運用ログの例です。

Datadog は、提案された階層的アプローチを使用したログを UI に記録します。

一貫性と標準化

標準プレフィックス

すべてのチームでログ形式を標準化すると、ログの読みやすさと理解しやすさが大幅に向上します。検討すべき標準化されたプレフィックスをいくつか示します。

  • 何かを始める
  • 何かに失敗しました
  • 何かを完了した
  • 何かを省略した
  • 何かをやり直してみる

変数値を個別にログに記録する

変数名と値をログ メッセージの本文から分離すると、次のようないくつかの利点があります。

  • ログの検索と解析を簡素化:特定の情報をフィルタリングして見つけやすくします
  • ログメッセージの作成を効率化:ログメッセージの作成プロセスをシンプルに保ちます
  • メッセージの乱雑さを防止:大きな値でもログメッセージの読みやすさが損なわれることはありません

ログ形式の例:

 Log message - valueName=value

提案されたプラクティスを使用したログの例

理論的な例

以下に、説明したベスト プラクティスに従って適切に構造化されたログ エントリの例を示します。

 2023-10-05 14:32:01 [INFO] Successful login attempt - userId=24543, teamId=1321312 2023-10-05 14:33:17 [WARN] Failed login attempt - userId=536435, teamId=1321312

これらの例は以下を示しています。

  • 標準化されたログ プレフィックス: 「ログイン試行成功」や「ログイン試行失敗」などの明確で一貫性のあるプレフィックスにより、ログを理解しやすくなります。


  • 分離された変数値: 変数名と値はログ メッセージから分離され、明確さが維持され、検索が簡素化されます。


  • 読みやすさと一貫性: 構造化された形式により、ログの読み取りと解析が容易になり、効率的なトラブルシューティングと監視に役立ちます。

生産ログの例

以下は、提案されたプラクティスを使用した場合の運用ログの例です。

Datadog は、「開始」プレフィックスによるフィルターを備えた UI をログに記録します。

トレースID

ログを特定のユーザー アクションに効果的に関連付けるには、ログにtraceId ( correlationIdとも呼ばれます) を含めることが重要です。ID は、そのエントリ ポイントによってトリガーされるロジックによって生成されるすべてのログで一貫している必要があり、イベントのシーケンスを明確に把握できます。

実装例

Datadog などの一部の監視サービスでは、ログのグループ化がすぐに使用できますが、手動で実装することもできます。Spring を使用する Kotlin アプリケーションでは、HandlerInterceptor を使用して REST リクエストのトレース ID を実装できます。

 @Component class TraceIdInterceptor : HandlerInterceptor { companion object { private const val TRACE_ID = "traceId" } override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean { val traceId = UUID.randomUUID().toString() MDC.put(TRACE_ID, traceId) return true } override fun afterCompletion(request: HttpServletRequest, response: HttpServletResponse, handler: Any, ex: Exception?) { MDC.remove(TRACE_ID) } }

このインターセプターは、リクエストごとに一意のtraceIdを生成し、リクエストの開始時にそれを MDC に追加し、リクエストの完了後にそれを削除します。

traceId を含むログの例

このようなログ集約を実装すると、以下の例のようにログをフィルタリングできるようになります。


資産削除リクエストの処理中に生成されたログ

ログでの UUID と長い ID の使用

多くのシステムでは、エンティティはUUIDまたはLong ID のいずれかを主要な識別子として使用しますが、一部のシステムでは、異なる目的で両方のタイプの ID を使用する場合があります。ログ記録の目的で各タイプが及ぼす影響を理解することは、情報に基づいた選択を行うために重要です。


考慮すべき事項の内訳は次のとおりです。


読みやすさ: Long ID は、特にLong範囲の上限にない場合は、読みやすく、かなり短くなります。


一意の値: UUID ID はシステム全体で一意性を提供し、ID の衝突の問題に直面することなく ID を使用してログを検索できるようにします。ここでの衝突とは、関連のない DB テーブルの 2 つのエンティティが同じLong ID を持つ可能性があることを意味します。


システムの制限: 長い主キーをエンティティ ID として使用するシステムでは、ランダムなUUID ID を追加するのは通常簡単ですが、 UUIDエンティティ ID を持つ分散システムでは、ログ記録専用のLong ID を持つことは困難またはコストがかかる可能性があります。


既存のログ:ログで使用される ID の種類の一貫性は、少なくともエンティティごとに重要です。システムがすでに一部のエンティティのログを生成していて、それらすべてを変更することを検討していない場合は、エンティティを識別するためにすでに使用されている種類を維持する方がよいでしょう。移行期間中は両方の ID をログに記録することを検討できますが、複数の ID を永続的に保持すると、ログが不必要に乱雑になります。


結論

適切なログ記録方法は、効果的なサービス監視に不可欠です。包括的なログ記録、適切なログ レベル、トレース ID、標準化されたログ形式を組み込むことで、アプリケーションの監視とトラブルシューティングの能力を大幅に強化できます。これらの方法により、ログの明瞭性と一貫性が向上し、問題を迅速に診断して解決しやすくなります。


この投稿を読んでいただきありがとうございます。