メインコンテンツまでスキップ

ログ

ログは、アプリケーションやアプライアンスから送信される一連のメッセージで、イベントに関する詳細や、時にはそのアプリケーションの健全性について、1 行以上の詳細で表されます。通常、ログはファイルに配信されますが、分析や集計を行うコレクターに送信されることもあります。ログデータの生成、取り込み、管理を、1 日あたり数メガバイトから 1 時間あたり数テラバイトまで、あらゆる量で行うことを目的とした、多くの機能を備えたログアグリゲーター、フレームワーク、製品が存在します。

ログは一度に 1 つのアプリケーションから発行され、通常は その 1 つのアプリケーション の範囲に関連しています。ただし、開発者は自由に、ログを望むだけ複雑で微妙なものにすることができます。ここでは、ログを トレース とは根本的に異なるシグナルと考えています。トレースは複数のアプリケーションやサービスからのイベントで構成され、応答遅延、サービス障害、リクエストパラメータなど、サービス間の接続に関するコンテキストを持っています。

ログ内のデータは、一定期間にわたって集計することもできます。例えば、統計的なもの(前の 1 分間に処理されたリクエスト数など)である場合があります。構造化されたもの、自由形式のもの、詳細なもの、どの言語で書かれたものでもあり得ます。

ログの主な使用例は、以下を記述することです。

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

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

ログに関する要件に関わらず、以下は我々が特定したベストプラクティスです。

構造化ログは成功の鍵

多くのシステムは、半構造化された形式でログを出力します。例えば、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 のスタックトレースは、複数行にまたがる単一のイベントで、構造化が少ないかもしれません:

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 !?!\")"
}

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

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

ログには、レベル を持つものとイベントのシリーズの 2 種類があります。レベルを持つログは、成功的なロギング戦略の重要な要素です。ログレベルはフレームワークによって若干異なりますが、一般的に以下のような構造になっています:

レベル説明
DEBUGアプリケーションのデバッグに最も役立つ、詳細な情報イベント。これらは通常、開発者にとって価値があり、非常に詳細です。
INFOアプリケーションの進行状況を大まかなレベルで強調する情報メッセージ。
WARNアプリケーションにリスクを示す、潜在的に有害な状況。これらはアプリケーションでアラームを引き起こす可能性があります。
ERRORアプリケーションの実行を継続させる可能性のあるエラーイベント。これらは注意が必要なアラームを引き起こす可能性が高いです。
FATALアプリケーションを中断させる可能性が高い、非常に深刻なエラーイベント。
備考

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

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

ログレベルは、環境の健全性についてモニタリングおよびオブザーバビリティソリューションに知らせるために重要であり、ログデータは論理的な値を使用してこのデータを容易に表現する必要があります。

ヒント

WARN レベルで多すぎるデータをログに記録すると、価値の限られたデータでモニタリングシステムが満たされ、大量のメッセージの中で重要なデータが失われる可能性があります。

ログのフローチャート

備考

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

警告

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

ソースに近い場所でログをフィルタリングする

可能な限り、ソースに近い場所でログの量を削減してください。この最良の実践を行う理由は多数あります:

  • ログの取り込みには常に時間、コスト、リソースがかかります。
  • 下流のシステムから機密データ(個人を特定できるデータなど)をフィルタリングすることで、データ漏洩のリスクを軽減できます。
  • 下流のシステムは、データソースと同じ運用上の懸念事項を持っていない場合があります。例えば、アプリケーションからの INFO ログは、CRITCALFATAL メッセージを監視する監視・アラートシステムにとっては関心がないかもしれません。
  • ログシステムやネットワークに過度のストレスやトラフィックをかける必要はありません。
備考

コストを抑え、データ露出のリスクを減らし、各コンポーネントを重要な事項に集中させるために、ソースに近い場所でログをフィルタリングしてください。

ヒント

アーキテクチャによっては、Infrastructure as Code (IaC) を使用して、アプリケーション環境の変更を一度の操作でデプロイすることをお勧めします。このアプローチにより、ログフィルターパターンをアプリケーションと一緒にデプロイでき、同じ厳密さと扱いを与えることができます。

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

管理者がよく行うパターンとして、すべてのログデータを単一のシステムにコピーし、1 か所からすべてのログを照会することを目指すというものがあります。 これには手動ワークフローの面で利点がありますが、このパターンは追加のコスト、複雑さ、障害ポイント、運用オーバーヘッドをもたらします。

ログの二重取り込み

備考

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

備考

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

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

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

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

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

stdout へのログ出力

可能な限り、アプリケーションはファイルやソケットなどの固定の場所ではなく、stdout にログを出力すべきです。これにより、ログエージェントは独自のオブザーバビリティソリューションに適したルールに基づいてログイベントを収集およびルーティングできます。すべてのアプリケーションで可能というわけではありませんが、これはコンテナ化されたワークロードにとってのベストプラクティスです。

注記

アプリケーションはログ記録の実践においてシンプルで汎用的であり、ログソリューションから疎結合を保つべきですが、ログデータの送信には依然として ログコレクターstdout からファイルにデータを送信する必要があります。重要な概念は、アプリケーションとビジネスロジックがログインフラストラクチャに依存しないようにすることです。つまり、関心の分離に努めるべきです。

備考

アプリケーションをログ管理から切り離すことで、コード変更なしにソリューションを適応および進化させることができ、環境に加えられた変更の潜在的な Blast Radius を最小限に抑えることができます。