いつ、何をログに残すべきか?

Article by: (読了時間:8分)

 

本記事は、Sergiy による投稿「【エラー・トレース・ログ・メトリクス】いつ何を使うか」の続編です。

Sentry のようなモダンなオブザーバビリティプラットフォームは、開発者に多くの選択肢を与えてくれます。発生した問題に対して、トレース、プロファイル、メトリクス、ログのどれを使うべきでしょうか。

この記事から1つだけ持ち帰ってもらえるとしたら、迷ったら、まずは狙いを定めたログ行をいくつか追加することから始める ということです。

ログはアプリケーションに追加するのが簡単で、ソフトウェアが本番環境でどのように動いているかについての実際の情報を集め始める、手早い方法でもあります。新しい機能を書くときには、デプロイなしでデバッグできる程度に十分なログを追加するようにしています。ログは一時的なインストルメンテーションであってかまいません。問題を調査するときや機能を検証するときに追加し、役に立たなくなったら削除すればよいのです。

ここからは、アプリケーションをデバッグしやすく、また理解しやすくするために、ログを活用するためのベストプラクティスをいくつか紹介します。

ログに残すことを検討する良い対象

アプリケーションが行う重要な実行時の判断

ユーザーによって、目にするフローが異なることはよくあります。予期しない挙動をデバッグするときには、あるリクエストがどのように処理されたのかを決定づけた、さまざまな判断のすべてを知りたくなります。

例をいくつか挙げます。

  • あるユーザーにはページの実験的なバージョンを表示する feature flag が有効になっている。
  • モバイルユーザーは別の体験へとリダイレクトされる。
  • 有料ユーザーと無料ユーザーとで提供される機能が異なる。

 

アプリケーションが複数のコードパスから選択を行うときには、なぜその判断がなされたのか、そしてその結果どのような挙動になったのかの両方をログに残すことを検討しましょう。

こうしたログがあると、2人のユーザーがアプリケーションを異なる形で体験した理由を理解しやすくなり、特定のコホートだけに影響するバグを再現しやすくなります。

機能やアルゴリズムが期待どおりに動作しているか

機能が複数のステップを実行する場合、ログが役立ちます。途中の結果を記録しておくことで、処理がどこで、なぜ破綻しているのかを把握できます。

実際の例を挙げましょう。私のサイト allaboard.dev では、ユーザーが外部サービスからクライミングのログブックをインポートできます。インポート処理の結果をログに残すことで、元データが正しくパースされていることを確認でき、どこで失敗しているか(そもそも失敗しているか)を特定できます。

 

監査・アクセスイベント(作成・更新・削除・アクセス・権限)

監査ログは、「これを変更したのは誰か」「それはいつ起きたのか」「そのアクションは想定されたものだったか」といった問いに答える助けになります。

この種のログは、サポート案件の根本原因を突き止めるのに大いに役立ちます。

たとえば、あるユーザーから「うちのチームの週次ダッシュボードが、いったいどこに消えたんだ?」という問い合わせが来たとします。アプリケーションが変更を伴う操作(作成・削除・更新)をログに残しているおかげで、数日前に同じチームの別のメンバーが誤ってそのダッシュボードを削除していたことが分かります。あなたはダッシュボードを復元し、何が起きたのかをユーザーに正確に伝え、そしてアプリケーションが勝手に何かを削除しているわけではないという安心感を得られます。

アクセスや権限をログに残すことは、HIPAA のような一部の標準では要件になっていることもあります。

注: 監査ログは、コンプライアンス要件を満たすための一部分にすぎません。Sentry が提供するプライバシーとセキュリティの制御については、Sentry and Your Data をご覧ください。複雑なコンプライアンスやプライバシーの要件がある場合は、ぜひご相談ください

 

エラーや失敗の周辺コンテキスト

例外については、ログ行を追加するよりも、Sentry の Capture Error 機能を使う方がよい場合が多くあります。そうすることで、Issue Grouping、トリアージのワークフロー、Autofix、その他 Issue に焦点を当てた機能の恩恵を受けられます。

とはいえ、あらゆる失敗をすぐさま Sentry のエラーにすべきというわけではありません。たとえば、動作の不安定な上流の API に依存していて、特定の HTTP ステータスコードについては N 回までリトライを許容している、というケースが考えられます。N 回に達したときには、Sentry にエラーを上げたいでしょう。しかし N 回に達する前の試行については、なぜリトライループが起きているのかを説明するログ行が、デバッグ時に役立ちます。

では、どのようなコンテキストをログに残したいでしょうか。

  • リトライ回数や試行番号
  • 上流サービスが返すステータスコード、エラーコード、その他の機密でない詳細情報
  • 失敗の説明に役立つ、機密でないリクエスト/レスポンスの属性
  • feature flag や設定など、失敗に関連する実行時の状態

 

何をログに残すべきかについていくつか推奨事項を挙げたところで、次はログメッセージをどのように構造化するかを見ていきましょう。

ログメッセージの書き方

構造化されたログメッセージを使う

"DID I GET HERE" のようなプレーンテキストのログではなく、情報を一貫したキー/バリューのペアとして捉える構造化ログを使いましょう。

構造化ログは人間にとっても機械にとっても有益です。user_idrequest_idfeature_flagaction といった一貫したフィールドはデバッグを容易にし、ログプラットフォームによる検索、可視化、アラートにも利用できます。

良いログメッセージは、たいてい次の3つの問いに答えます。

  • 誰がそのアクションを行ったか(たとえば、認証済みのユーザー)
  • 何が起きたか(人間が読めるメッセージと、それを補足するメタデータ)
  • いつ起きたか(通常はログシステムによって自動的に付与される)


注:
現在認証されているユーザーに関するコンテキストを含めるために、Sentry は setUser メソッドを提供しています。

 

リクエストの進行に応じてコンテキストを追加する

ログはリクエストがアプリケーションの中を進んでいくにつれて、コンテキストを積み重ねていくべきです。そのコンテキストを、イベント固有のメタデータと一緒にログメッセージとして出力しましょう。たとえば、認証前に出力されるログには、ユーザー情報は含まれません。リクエストのライフサイクルの後半、認証が済んだ後には、ログ対象のイベントに固有のコンテキストと並べて、ユーザー固有の詳細情報を含めるべきです。

とりわけ価値の高いコンテキストの1つが Trace ID です。これによって、ログエントリを分散トレースへとたどってつなげられるようになり、そのログメッセージが出力されるに至った一連の出来事を理解しやすくなります。

うれしいことに、Sentry のログは追加設定なしでトレースに接続されているため、トレースのコンテキストは利用可能なときに自動的に含まれます。

適切なログレベルを選ぶ

適切なログレベルを使うことは、ログメッセージに意味を持たせるもう1つの方法です。

debug は開発中や特定の調査時に役立つ、詳細な診断情報に使います。デバッグログは本番環境では無効化されていることが多く、問題のトラブルシューティング時に一時的に有効化されます。

注: Sentry の beforeSendLog メソッドを使うと、level プロパティを見て debug レベルのログを除外できます。beforeSendLog(log) {return log.level !== 'debug'}

 

info は通常のアプリケーションイベントに使います。実行時に行われる判断、アルゴリズムの挙動、監査ログ、これらはいずれも info レベルのログの候補です。

warn は注意が必要かもしれない、回復可能なイベントに使います。良い例としては、外部サービスへの API 呼び出しがレイテンシのしきい値に達したとき、などが挙げられます。

error は適切に処理される予期しない失敗に使います。失敗が例外につながる場合は、重複するエラーログよりも、Sentry の Capture Error を使うほうが望ましいです。

 

ログに残すべきでないもの

アプリケーション内のあらゆる関数呼び出しやコード行

あらゆる関数呼び出しをインストルメントするのは、たいていプロファイリングとトレーシングに任せたほうがうまくいきます。Sentry にプロファイリングトレーシングがあるのをご存じでしたか?(Rahul に言わされています。

 

PIIやその他の機密情報

何かの情報をログに残すときには、いつも自分にこう問いかけてみてください。「もし不適切な人物がこの情報にアクセスできてしまったら、どんな影響があるだろうか。」

いくつかのガイドラインを挙げます。

  • 可能な場合は、メールアドレスやフルネームよりも、不透明なユーザー ID を使うほうが望ましいです。
  • パスワード、アクセストークン、API キー、およびそれに類するシークレットは、決してログに現れてはなりません。これらは、シークレットの保管用に設計されたシステムにのみ保存してください。
  • 年齢、性別、郵便番号など、その他の種類の個人情報も、法域によっては規制の対象になる場合があります。
  • PCI、GDPR、CCPA、HIPAA といった国内外の法律や標準にも注意してください。これらは何をログに残し、保持し、公開してよいか(あるいはよくないか)についての指針を示しています。

 

注: Sentry には Server-Side Data Scrubbing があります。構造化ログを使っている場合、これは PII やパスワードにまつわるよくある落とし穴のいくつかを防ぐのに役立ちます。設定可能なので、アプリケーションに応じて追加のフィールドを含めることもできます。また、beforeSendLog を使って、機密情報のクライアント側でのフィルタリングを行うこともできます。

 

まとめ:何をログに残すかについては、意図的であること。アプリケーションのデバッグと運用に必要な最小限の情報だけをログに残し、業界や国、顧客の国に適用される要件を理解しておきましょう。

大きなデータの塊(明確な目的のないもの)

大きく構造化されていないデータの塊をログに残すことには、正当な理由もあります。

  • LLM のプロンプトとレスポンスの全体を見ることで、プロダクトが期待どおりに動作しているかどうかを把握できる場合があります。
  • webhook のボディをログに残すことで、外部連携の問題をデバッグできる場合があります。

 

ただし、この種のデータをログに残すことには、コストとリスクの両方が伴います。

  • ユーザーが LLM のプロンプトに個人情報や機密情報を含めてしまうことがあります。
  • HTTP のリクエストやレスポンス全体には、アクセストークンやシークレット、その他の機密データが含まれていることがあります。
  • Sentry を含む多くのログ製品は、量に応じて課金します。保存しようとしている情報を、自分が実際に使うのかどうかを問い直してみてください。

 

AI アシスタントについては、会話全体をログに残すよりも、Sentry の Conversations 機能のような専用のソリューションを使うほうがよい場合もあります。

PII の話と同じく、大切な要点は何をログに残すかについて意図的であることです。そのデータに伴うコストとリスクを考え、可能な場合は、リクエストやレスポンス、ドキュメント全体ではなく、必要な特定のフィールドだけをログに残すようにしましょう。

これらの提案を allaboard.dev に適用する

この記事のアドバイスに従って、先ほど触れた私のサイドプロジェクト bcoe/allaboard.dev に追加したログの例をいくつか挙げます。

 

おかげで今では、何か問題が起きたときにも、ウェブサイトの新しいバージョンをデプロイすることなく問題をデバッグできるだけの十分なコンテキストが手元にある、とずっと自信を持てるようになりました。

次のステップ

この記事がログの何をそしてどのようにについての何かしらのヒントになり、次に本番環境で厄介なことが起きたときのデバッグを速める助けになればうれしいです。

始めるにあたってサポートが必要な場合は、getsentry/sentry-for-ai を試してみてください。あなたのコードベースを解析し、最初に追加すべき価値の高い構造化ログメッセージの一式を提案してくれます。

試してみる

まず、次のコマンドを実行して Sentry プラグインをインストールします。

続いて、お好みのエージェントに次の内容を貼り付けます。

注: getsentry/sentry-for-ai は急速に改良が進められており、一部のスキルのパスは変わる可能性があります。最新のインストール手順については、リポジトリを随時ご確認ください。

フィードバックがある方や、ログについてもっと話したいという方は、Discord でお待ちしています。

 

 

Original Page: When and what should I be logging?

 

 




IchizokuはSentryと提携し、日本でSentry製品の導入支援、テクニカルサポート、ベストプラクティスの共有を行なっています。Ichizokuが提供するSentryの日本語サイトについてはこちらをご覧ください。またご導入についての相談は「お問い合わせ」からお気軽にお問い合わせください。

 

シェアする

Recent Posts

;