エラーとログとメッセージ処理
問題
漠然と「エラーチェック、入力チェック、検証、整合性チェック、例外、ログ」という曖昧な言葉で括られてしまって、それぞれの意味とポリシーが定まっていない。
技術者がその場その場で判断し、実装したりしなかったり、実装しても各人で大幅に違いが出るという問題が発生している。
システムエラーでもビジネス制約などでも、似たような処理を行うために、何でも「入力チェック」「ログ出力」「エラー処理」「メッセージ出力」として混在したまま取り扱われてしまっている。
「入力チェック」という言葉が曖昧であるため、入力値の書式や値域チェックとビジネスロジックとしての制約チェックとが混在されたまま扱われてしまっている。
チェックした後どうするかが不明瞭なことが多い。
「ログ」という言葉が曖昧であるため、状態通知用のログと、その他の履歴の記録などが混同されている。
いつどこで何を記録するべきか? 何のために?
誰がそれを見るのか? 何のために?
程度はどのくらいか?
状況確認のために所々でログ出力をするのは望ましいが、むやみにログ出力するとコストがかかる。
デバッグ時には1行単位でのログが欲しくなることもある。
プログラムの見通しをよくするために分割してサブルーチン化したのに、分割点に場当たり的な入力チェックとログ出力が入って台無しになる。
関数の入り口で常に入力チェックするのは望ましいが、むやみにチェックするとコストがかかる。
細かな問題(思い付くものを列挙)
エラー処理はエラーが起きない限り実行されず、正常な運用の範囲では問題にならない場合が多い。このため書き漏らしが発生する。
サンプルソースなどはエラー処理を行わない事が多く、単純なコピーペーストを行うと書き漏らしになる。
例外をどこで受け取るべきかが不明瞭である。
場当たり的にあちこちに例外処理をコピーペーストする。
多くの場合、ログを残す以外のことをやらない。
エラー、例外を捕まえても、何もせずに潰してしまうことがある。
プログラマが対処方法を思いつかなかった時に場当たり的に行われることがある。
コーディングにはコストがかかる。(開発時間)
APIのドキュメントにどんな時にどんなエラーが返ってくるのか記述していない。
ソースを読むことができれば分かるが、読めないこともある。
プログラマが、APIからどんなエラーが返ってくるのか熟知していない。
どのタイミングで判定すればいいのかが分からない。
処理の開始時、終了時、下層APIの呼び出し時
入力チェックが必要かどうかが判断できない。
null チェック、空文字列チェックは必要か? 誰がどこでやるべきか?
関数の実行開始時に「ありえないケース」を取り除くのはよい方策だが、コストが高い。
エラー判定にはコストがかかる。(実行時間、CPU、メモリリソースなど)
下層から得られるエラーをどう判定して、自分の上層にどう返すのかを考えるのが難しい。
下層から得られるエラーを変換してよいか? そのまま返すか?
誰が利用者向けのメッセージを組立てるのか?
どのレベルまでエラーに対処すればいいのか分からない。単純にシステムエラーでおしまいでよいのか?
エラーを見つけたら即終了でよいのか?
下層はその上層のことを知らない。
本来、その層で出せるエラーは、その層(かそれ以下)で知り得ることでしかない。
関数は、渡された入力しかわからない。呼び出された上のことはわからない。
利用者が受け取るべきメッセージなのかどうかを下層で判断するのは難しい。
利用者が受け取るべきメッセージかどうかはアプリケーション層(UI層)で判断されるべき。
場当たり的にダイアログやログを出してアプリケーションが終了してしまう。
「システムエラーです」
「エラーが発生しました」
メッセージの決定が難しい。恣意的に決定されてしまう。
プログラマは分かるがユーザーは分からないメッセージ
エラーコードの決定が難しい。恣意的に決定されてしまう。
メッセージを取り扱う方法が不明瞭である。
思い思いの方法で文字列組み立てをしてしまい、変更・保守が困難になる。
エラーコードを取り扱う方法が不明瞭である。
ログを出す方法が不明瞭である。
エラーコードとメッセージコードとを混同する。
意図的に区別しないというポリシーはある。
どの関数がログを出すべきかが不明瞭である。
どういうログを出力すべきかが不明瞭である。
ログに原因究明に必要な詳細な情報が残らない。
不具合が起きても、情報が不足していて、何が起きたのか再現不可能になる。
ログとメッセージとを混同する。
利用者に見せるだけでよいメッセージをログに出してしまう。
管理者、提供者に見せるべきログを利用者にメッセージで出してしまう。
ログを出力するのにはコストがかかる。
ログの生成と記録にリソースが使われる。
ログが母国語でないと読めない人がいる。
口頭での伝達で読み上げられないなど。
ログを母国語でないと書けない人がいる。
開発時におかしな英語で書いてしまうなど。
文書での伝達で書けないなど。
ビジネス制約とシステム上のエラーとを混同する。
不整合なデータがシステム内に入ってしまった場合の対処方法が不明瞭である。
そもそも、不整合になった場合、システムでは対処困難な場合がほとんどである。
不具合が起きても、何が起きたのか再現不可能である。
異常系のテストは単純に異常が再現できないので困難である。
syslog で扱える文字数は1000文字程度が限界であるが、それを超えるようなログが出ることがある。
ログの保管期間(あるいは容量)が不明瞭である。
このためログでディスクがパンクすることがある。
ログが大量に発生することがある。
異常時にはエラーが各所に波及するために大量のエラーが発生する。このためログも大量に発生する。
大量のクライアントからのリクエストにより、同じエラーが大量に発生することがある。
このため、「同じログ」を抑制する必要が出てくる。
しかしアプリケーションが「気を利かせて」抑制させるのは一般に困難である。
一度そのログが出たかどうかを記憶しておく必要が出てくる。
ログローテーションができていないことがある。
ログローテーションで、ファイルがオープンしたままになっていてローテーションできないことがある。
システム内外から出るログが正確に把握されていないことがある。
いつ誰がどこでどんなログを出すのかを全部把握するのは困難である。
未知のログが常にある。
ログの書式がはっきりしないことがある。
特にシステム外のログはまったくわからない。
エラーチェックが単発だと、訂正しても次のエラーで引っかかってしまう。
各ステップがログに残っていれば、どのステップでエラーになったのかは分かるかも知れないが、そもそもアプリケーションの内部構成を知らなければ、ステップ毎のログには余り意味がない。
デバッグ時には役に立つかもしれない。
アプリケーション的に正常終了だったか異常終了だったかをアプリケーションがログで判断している。
ログは必ずしも完全に取られないので不安定になる。
サードパーティのライブラリやドライバなどが、異なるログAPIを使用している、あるいは異なるログ形式で出力することがある。
ログをどの段階で出すのが望ましいのかがわからない。
処理の受付時(この後、拒否する可能性がある。)
処理の実施前(この後、処理が失敗、中止されることがある。)
処理の実施後
処理の成功時
処理の失敗時