Webアプリケーションのログ出力について指針を考えてみた
こんにちは、下條です。最近、Webアプリケーションのログ出力の指針について改めて考えてみる機会がありました。弊社ではインフラはほぼAWSを利用していることから、多少汎用的でない記述もありますが、ある程度まとまってきたことからひとつの指針として公開いたします。
はじめに
システム開発をする際、ログ設計は非常に重要な工程です。
しかしながら、ログというものは実運用に入って障害などがあってからようやく役に立ってくるもので、開発時には意識が向きにくいという部分があるのも事実です。
ログを適切に出力し、最大限に活用することで、障害時の調査コスト減、システム運用コストを抑えたり、よりよいサービスを提供する手掛かりにもなります。
アプリケーションや開発言語・フレームワークなどにより例外もあると思いますので本ドキュメントはあくまでサンプルとしてご利用ください。また、本ドキュメントはサーバサイドWebアプリケーションを想定しています。
出力先
以下のいずれかに永続化することが望ましい。
- CloudWatch Logs
- S3 (Fluentdなどにより転送)
ただし、何かしらの事情により上記が難しい場合はディスクへの出力のみでもかまわない。その場合、ログでディスク圧迫しないようローテーションや圧縮などの対応を実施する。
ログレベル
当然ながらできるかぎり詳細なログがあったほうが望ましい。しかし、本番環境などではログの出力コストが発生するため、ログレベルを分類し、環境によって適切にログを出し分ける。
ログレベル | ログレベル(日本語) | 説明 |
---|---|---|
ERROR | エラー | 本来発生せず調査が必要な事象について用いる。 |
WARN | 警告 | 非推奨となったAPIの使用、APIの不適切な使用、エラーに近い事象など。即時調査が必要ではないが完全に正常とも異なる事象について用いる。 |
INFO | 情報 | 本番環境で最低限必要なレベル。外部API呼び出しのパラメータ・復帰値など。具体例は後述。 |
DEBUG | デバッグ | 発行されるSQL文やデバッグ用ログ。 |
- 開発環境ではDEBUG以上、ステージング環境ではDEBUGもしくはINFO以上、本番環境ではINFO以上を出力することを基本とする。
- ERRORレベルはログ出力する他、Slack等で通知し、即時に異常を検知できるようにする。
具体的な例
- 例外がある言語の場合、予期せぬ例外が発生した場合、例外内容を出力する。 (ERRORレベル)
- HTTPのリクエストパラメータは基本的に全て出力する。ただし、パスワードなどの機密情報や個人情報は出力しない。Ruby on Railsなどフレームワーク側でマスキング機能を提供してくれているものもあるが、そうでない場合はがんばる。 (INFOレベル)
- 外部APIをコールする場合、障害時の原因切り分けを容易にするためエンドポイント・リクエスト内容・レスポンス内容を出力する。 (INFOレベル)
- OSコマンドを実行する場合、障害時の原因切り分けを容易にするためコマンドをパラメータ含め全て出力、復帰値を出力する。 (INFOレベル)
- 発行したSQLを全て出力する。 (DEBUGレベル)
ログフォーマット
- 各ログには日時 (年月日日時分秒ミリ秒) を出力する。
ログローテーション
- ディスクにログを保存する場合にはディスク容量の枯渇を防ぐためログローテーションの仕組みを導入する。フレームワークで機能が提供されていない場合は、logrotateを用いることを基本とする。
ログに出力すべきでない情報について
最近、Twitter社でパスワードがログに平文で保存されていたというニュースが話題になった。また、EU一般データ保護規則 (GDPR) も本日 (2018/05/25) から施行となり、個人情報の保護の重要性は増している。以下はログに出すべきでない情報である。
- パスワードがログに残らないよう、パスワードはマスキングもしくはログ出力しない。
- 個人情報もマスキングもしくはログに出力しないようにする。個人情報の定義は個人情報の定義について - 経済産業省を参照のこと。なお、個人情報はSQL文含めて注意すること。
ELBのログ
- ELBはログ出力を有効に設定すること。 (デフォルトでは無効なので注意。)
おわりに
他にもいろいろとあると思いますので、さらにブラッシュアップしてまた後日公開できたらと思います。本ドキュメントが少しでも開発者の皆様のお役に立てば幸いです。