仕様で規定されているものは別として、プログラムの問題分析にはどのようなログが理想的かは経験に基づく状況判断に依存するところが大きいところです。ここではチーム開発におけるログ出力の方針などについて説明します。
チーム開発の問題分析
一般的なシステム開発では統合テスト付近から後は開発物が開発者本人の手を離れてテストされることになります。同時に開発者は目の前で問題の発生を見られないまま分析しなければならない状況が多くなってきます。
基本的にテスターなどからの状況説明、ログ、画面キャプチャなどから推測されるプログラムの動きをソースコード上で追う事になるわけですが、問題の報告には主観や個人の能力、勘違い、先入観などが入りやすいことも事実です。このような中で客観性の高いログはとても重要です。
ソースデバッガやプロファイラは問題の詳細を調査するために大変有用なツールですが、システム開発で使用するログとは目的が違うことに注意してください。これらのツールに慣れてしまったプログラマはトレースやデバッグレベルのログを省略する傾向にあります。しかしそれは単に問題分析の経験が浅いと言わざるを得ません。
数百万の損失や訴訟のリスクがあるバグを「再現待ちです」などとは誰も言えません。障害分析とは、発生した時が最大にして最後のチャンスであることをよく肝に銘じてください。
誰のためのログか
開発から実運用まで、ログはさまざま立場の人が問題を調査するために利用します。開発の組織構成によってもさまざまですが、大まかには以下の 4 つに分類できます。
- 開発担当者
-
ソースコードを書いた本人、あるいはそれを引き継いだ人。問題の報告内容からすぐに調査にかかれる (あるいは原因を即答できる) 必要があります。プログラミング言語についての知識を持ち、ログからソースを追って問題を分析できますが、システム全体の設計までは知らないかもしれません。
- 開発チーム
-
開発に携わっているチームの人。プログラミングの知識を持ち、ログやソースの分析が行え、システム設計上その動きが正しいかどうかを判断できる人たちです。しかしソース個別で「何を意図してこう書いたか」などは担当者レベルでしか分からない可能性があります。
- 開発以外の技術者
-
例えば製品の問題分析やパフォーマンスチューニングなどを行うために現場で作業を行うエンジニアです。言語やシステムの知識はあっても、対象の開発物に対する設計や諸事情までは知らないかも知れません。
- エンドユーザやシステム管理者
-
システムを利用する人、あるいはその中でもシステム管理を行う人です。システム全体の構築と運用を行う人たちであって、基本的にソースを追って問題を分析する立場ではありません。「シェルを組む」「設定ファイルを記述する」「ログで見当をつける」という知識を持ちます。また「この動きが要件的に正しいか」を判断できます。
同じ状況を説明にするにしても見る人の立場によって適切な表現が変わってくることに注意してください。例えば「該当するレコードが存在しない」というメッセージは開発者がコードの動きを知る上で適切かもしれませんが、運用者からすれば「認証に失敗しました」の方が ID かパスワードを間違えただけとすぐに分かるため適切です。
ログレベル再考
誰に宛てたログかをはっきり意識することはログを挿入する時に重要な点のひとつです。そして、誰が見るかを想定することでそのログの出力レベルが決定します。これは同時にそのログをどのフェーズまで出すかという事につながります。
ログを挿入するときに一番重要な点がこれです。開発時に挿入するログは開発者本人に向けた情報になりがちですが、後で問題分析をする他人に理解できるか、誤解を与えないか
- トレース
-
見やすさよりも情報量優先。担当外の人間が読むことまで配慮しなくても良いが、少なくともこのログレベルで発生した問題は速やかに原因を特定 (あるいは切り分け) できなくてはならない。また出力抑止した時にパフォーマンスに影響の無いよう if で囲むなどの配慮が必要。
デバッグとの使い分けに迷うかもしれないが、他人に常時見せ付けるには冗長だがいざ問題の焦点になったら参考になるようなものはトレースで。例えばリクエストごとのセッション内容のダンプなど。
- デバッグ
-
プログラムの知識のある第三者が問題の原因分析のために読む事を想定する。読む人間が多数のソースに渡って調査していることが予想されるため、ログのみである程度の動作状況が分からなければならない。従って少なすぎるのはもちろんの事、冗長すぎてもいけない。
入出力値や条件分岐に使用した値などは最低限出したいところだが、例えばデータファイルを 1 文字ずつ解析する処理はトレースレベルにすべきである。また実動作にあまり関係のない部分のログは、問題発生時にソースコードと付き合わせて論理的にフローや状態が判断できるなら省略してもかまわない。
出力している値が何であるか分かる程度のテキストが必要である。また状態を知る上で注目すべきメッセージには●や【】などで特徴付ける工夫も有用である。
エラーを検知した時、特に例外を throw する時のログは冗長になってもかまわない。これから throw する例外がなぜ起きたのか、それを見た分析者がどこから調べれば良いのかを、実際に該当ソースを読まなくても推測できる程度の説明でなければならない。
トレースと同様に、ソースと付き合わせて原因の切り分けができなければならないし、実運用時のパフォーマンスに影響を与えてもいけない。
- 情報・警告・エラー
-
これらのレベルは、見ている人がプログラムの知識を持っていない可能性があるという事も配慮する。ログを見た運用者が、自分たち宛てのメッセージなのか開発側に回さなければいけないメッセージなのかを的確に判断できなければならない。
システム環境や配備、設定に関連する問題─つまり運用者だけで解決できる問題に関しては適切な情報を与えて解決を促す必要がある。例えば、どの設定ファイルの何の値がどうおかしいのかを知らせれば運用者だけですぐにリカバリできるが (それが本来の姿だが)、例外のスタックトレースしか出なければ開発側に回され問題解決までに無駄な時間を費やすことになるだろう。
運用に絡む問題については、検知した箇所で適切な情報を漏れ無く出せるようフレームワークがきちんと設計されていることも重要である。通常、アプリケーションからでは設定ファイルの物理的な配置や通信先のサーバがどれなのか知る由も無い。すべては無理であるとしても、運用絡みの問題はフレームワークで検知し、報告する事を基本として設計されているべきである。
逆に開発側に向けたメッセージは、運用者が一目見て手に負えないと分かるものでなければならない。特にエラーのログは表現ひとつ誤るだけで分析者に誤解を与えて何日も遠回りをさせたり、ありもしない疑いをかけられたり、最悪原因不明に陥る可能性がある。
実運用環境 (本番) ではディスク容量の見積もりなども関係してくるため、開発者が特定以上のレベルで好き勝手に出さないようルールを設けているのが一般的です。またそういったログはどこでどう出すかが要件定義書や設計書に盛り込まれている必要があり、実装面でもフレームワークで規定される必要があります (例えばフレームワークまで catch されなかった例外はすべて出す、ユーザ認証ログはこのクラスを使う、など)。
まとめ
システム文化や運用などの要因も絡んで来るため明確な指針というのは存在しませんので、状況にあわせて適切に当てはめてください。
|
トレース |
デバッグ |
情報 |
警告 |
エラー |
| 対象者 |
| 開発担当者 |
○ |
○ |
○ |
○ |
○ |
| 開発チーム |
△ |
○ |
○ |
○ |
○ |
| 開発以外の技術者 |
- |
△ |
○ |
○ |
○ |
| システム管理者 |
- |
- |
△ |
○ |
○ |
| 開発フェーズ*1 |
コーディング 単体テスト |
○ |
○ |
○ |
○ |
○ |
| 統合テスト |
- |
○ |
○ |
○ |
○ |
| システムテスト |
- |
- |
○ |
○ |
○ |
| 実運用 |
- |
- |
○ |
○ |
○ |
- 何を出すか・どう出すか
-
- 処理の流れはデータに依存する。どこを通ったかでなく、なぜ通ったかを客観的に説明すること。
- 迅速な問題対応のためにもソースを読まなくてもある程度の切り分けができる状態にしておく。
- 特にレアケースのエラーを扱う時は一発で原因を特定できるだけの情報を出すこと。
- 見る人間に対して徹底的に配慮する
-
- 対象者を想定する。自分か他人か、ソースコードやデータベースを追って原因を調査できる人間か。
- このメッセージで原因を推測できるか。あるいは誰の担当なのかすぐ判断できるか。
- 見た人が次に何をすべきかが明確であること。
- 問題特定の遠回りになるような誤解を与えてはいけない。
*1 テスト環境ならスポット的な問題分析などで出力も可