コンテンツにスキップ

ログ

ログは、イベントまたはアプリケーションの正常性に関する 1 行以上の詳細を表すメッセージのシリーズであり、アプリケーションまたはアプライアンスによって送信されます。通常、ログはファイルに記録されますが、時には分析や集計を実行するコレクターに送信されることもあります。メガバイト/日からテラバイト/時間までのあらゆるボリュームのログデータを生成、取り込み、管理するための多機能なログアグリゲーター、フレームワーク、製品が数多く存在します。

ログは一度に 1 つのアプリケーションから発行され、通常その 1 つのアプリケーション の範囲に関連しています。ただし、開発者はログを任意の複雑さとニュアンスを持たせることができます。当社では、ログをトレースとは基本的に異なるシグナルとみなしています。トレースは複数のアプリケーションまたはサービスからのイベントで構成され、レスポンス待ち時間、サービス障害、リクエストパラメータなどのサービス間のコンテキストに関する情報が含まれます。

ログ内のデータは、期間をまたいで集計することもできます。たとえば、過去 1 分間に処理されたリクエスト数などの統計情報である場合があります。構造化されている場合もあればフリーフォームの場合もあり、詳細であったり、任意の言語で書かれている場合もあります。

ログの主なユースケースは以下の通りです。

  • イベント自体の説明。ステータスと期間などの重要な統計情報を含む
  • そのイベントに関連するエラーや警告(スタックトレース、タイムアウトなど)
  • アプリケーションの起動、開始、シャットダウンメッセージ

Note

ログは イミュータブル(不変) であることを目的としており、多くのログ管理システムには、ログデータの変更を防止し、変更の試みを検出するメカニズムが含まれています。

ログに対する要件は何であれ、特定したベストプラクティスは次のとおりです。

構造化ログが成功の鍵

多くのシステムは半構造化形式でログを出力します。 たとえば、Apache Web サーバーは、各行が 1 つの Web リクエストに対応するようにこのようにログを書き込む場合があります。

192.168.2.20 - - [28/Jul/2006:10:27:10 -0300] "GET /cgi-bin/try/ HTTP/1.0" 200 3395
127.0.0.1 - - [28/Jul/2006:10:22:04 -0300] "GET / HTTP/1.0" 200 2216

一方、Java のスタックトレースは、複数行にまたがる1つのイベントで、構造化されていない場合があります。

Exception in thread "main" java.lang.NullPointerException
    at com.example.myproject.Book.getTitle(Book.java:16)
    at com.example.myproject.Author.getBookTitles(Author.java:25)
    at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

Python のエラーログイベントは次のようになる場合があります。

Traceback (most recent call last):
  File "e.py", line 7, in <module>
    raise TypeError("Again !?!")
TypeError: Again !?!

これら 3 つの例のうち、人間とログ集約システムの両方で簡単に解析できるのは最初の例だけです。 構造化ログを使用すると、ログデータを迅速かつ効果的に処理できるため、人間とマシンの両方が即座に探しているものを見つけるために必要なデータが得られます。

最も一般的に理解されているログ形式は JSON で、イベントの各コンポーネントがキー/値のペアとして表されます。 JSON では、上記の Python の例は次のように書き換えることができます。

{
    "level", "ERROR"
    "file": "e.py",
    "line": 7,
    "error": "TypeError(\"Again !?!\")"
}

構造化ログを使用すると、データを一つのログシステムから別のログシステムに転送できるようになり、開発が簡素化され、運用上の診断がより速く(エラーも少なく)行えるようになります。 また、JSON を使用すると、実際のデータとともにログメッセージのスキーマが埋め込まれるため、高度なログ分析システムがメッセージを自動的にインデックス化できるようになります。

ログレベルを適切に使用する

ログには、レベル を持つものと、一連のイベントから成るものの 2 種類があります。レベルを持つものは、成功したログ戦略にとって極めて重要なコンポーネントです。ログレベルはフレームワークによって若干異なりますが、概して次の構造に従っています。

レベル 説明
DEBUG アプリケーションのデバッグに最も有用な詳細な情報イベント。これらは通常、開発者にとって価値があり、非常に詳細です。
INFO アプリケーションの進捗を粗く示す情報メッセージ。
WARN アプリケーションへのリスクを示す、潜在的に有害な状況。これらはアプリケーション内のアラームをトリガーできます。
ERROR アプリケーションの実行を継続できる可能性のあるエラーイベント。これらは注意が必要なアラームをトリガーする可能性が高いです。
FATAL おそらくアプリケーションのアボートを引き起こす、非常に重大なエラーイベント。

Info

明示的なレベルを持たない暗黙的なログは、INFO と見なされる場合がありますが、この動作はアプリケーションによって異なる場合があります。

その他一般的なログレベルには、ニーズ、プログラミング言語、フレームワークに応じて、CRITICALNONE があります。ALLNONE も一般的ですが、すべてのアプリケーションスタックで見つかるわけではありません。

ログレベルは、環境の健全性についてモニタリングおよび可観測性ソリューションに通知するために不可欠であり、ログデータは論理値を使用してこのデータを簡単に表現できる必要があります。

Tip

WARN で大量のデータをログに記録すると、限られた価値しかないデータでモニタリングシステムが溢れ、メッセージの膨大な量の中で重要なデータを失う可能性があります。

ログフローチャート

Success

標準化されたログレベル戦略を使用することで自動化が容易になり、開発者が問題の根本原因をすばやく特定できるようになります。

Warning

ログレベルに対する標準的なアプローチがないと、ログのフィルタリングは大きな課題となります。

ログはできるだけソース近くでフィルタリングする

可能であれば、ログ量をできるだけソース近くで削減してください。このベストプラクティスにはさまざまな理由があります。

  • ログの取り込みには常に時間、コスト、リソースがかかります。
  • ダウンストリームシステムからの個人情報などの機密データのフィルタリングは、データ漏洩からのリスクエクスポージャーを減らします。
  • ダウンストリームシステムは、データソースと同じ運用上の関心事を持っているとは限りません。たとえば、アプリケーションからの INFO ログは、CRITICALFATAL メッセージを監視する監視・アラートシステムにとって関心の対象ではないかもしれません。
  • ログシステムやネットワークが不要なストレスやトラフィックにさらされる必要はありません。

Success

ソース近くでログをフィルタリングすることでコストを下げ、データ露出のリスクを減らし、各コンポーネントを重要事項に集中させることができます。

Tip

アーキテクチャによっては、アプリケーションと環境の両方を1つの操作でデプロイできるインフラストラクチャ・アズ・コード(IaC) を使用したい場合があるでしょう。このアプローチにより、アプリケーションとともにログフィルタパターンを同じ厳密さと処理でデプロイできます。

二重取り込みのアンチパターンを避ける

管理者がしばしば追求するパターンは、すべてのログデータを単一のシステムにコピーし、すべてのログを単一の場所からクエリできるようにすることです。これには手動のワークフロー上のいくつかの利点がありますが、このパターンはコスト、複雑さ、障害点、運用上のオーバーヘッドを増加させます。

二重のログ取り込み

Success

可能な限り、ログレベルログフィルタリングの組み合わせを使用して、環境からのログデータの全面的な伝播を避けてください。

Info

一部の組織やワークロードでは、規制要件を満たしたり、ログを安全な場所に保存したり、否認防止を提供したり、その他の目的を達成するために、ログ出荷が必要です。これは、ログデータを再取り込む一般的なユースケースです。適切なログレベルログフィルタリングの適用は、これらのログアーカイブに入る不要なデータの量を減らす上でも適切です。

ログからメトリクスデータを収集する

ログには、収集を待っているメトリクスが含まれています。自分で書いていない ISV ソリューションやアプリケーションでも、貴重なデータがログに出力されており、これを抽出することで、全体的なワークロードの健全性について意味のある洞察を得ることができます。一般的な例を以下に示します。

  • データベースの遅いクエリ時間
  • Web サーバーのアップタイム
  • トランザクション処理時間
  • 時間経過とともにの ERROR または WARNING イベントのカウント
  • アップグレード可能なパッケージの生のカウント

Tip

このデータは、静的なログファイルに閉じ込められているとあまり役に立ちません。ベストプラクティスは、重要なメトリクスデータを特定し、それをメトリクスシステムにパブリッシュすることで、他のシグナルと相関付けできるようにすることです。

stdout にログ出力

可能な場合は、アプリケーションはファイルやソケットなどの固定の場所ではなく、stdout にログを出力する必要があります。これにより、ログ エージェントがあなたの可観測性ソリューションにとって意味のあるルールに基づいて、ログ イベントを収集およびルーティングできるようになります。すべてのアプリケーションで可能というわけではありませんが、これがコンテナ化ワークロードにおけるベスト プラクティスです。

Note

アプリケーションは、ロギングの慣行において汎用的でシンプルである必要があり、ロギング ソリューションとの結合度を低く保つ必要がありますが、ログデータの送信には、stdout からファイルへデータを送信する ログコレクター が必要です。重要な概念は、アプリケーションとビジネス ロジックがロギング インフラストラクチャに依存しないようにすることです。つまり、懸念事項を分離する必要があります。

Success

アプリケーションとログ管理を切り離すことで、コード変更を必要とせずにソリューションを適応および進化させることができるため、環境への変更による blast radius の最小化が可能になります。