私は最近、大規模エンタープライズアプリケーションの現場の問題を調査する必要がありました。 ログに恐怖を感じました問題を見つけるために徹底的に調査する必要があり、1日の終わりにログはバグの特定/隔離にまったく役立ちませんでした。
注:すべてのバグがログで発見できるわけではないことを理解しています。これは、ログが恐ろしいという事実を変更しません。
すでに修正を試みている可能性のある、ロギングに関するいくつかの明らかな問題があります。ここではそれらを一覧にしたくありません。ログファイルを単に表示することはできないので、何をすべきかについてアドバイスを与えることができます。
代わりに、私たちがロギングの最前線でどれほど悪いかを評価するために、私は知りたいと思います:
注意:log4jを使用します
私の実践が役立つことが判明したいくつかの点:
すべてのロギングコードをプロダクションコードに保持します。プロダクションで、できればサブシステムごとに、プログラムを再起動せずに、詳細なログを記録できるようにします。
grep
および目でログを解析しやすくします。各行の先頭にあるいくつかの共通フィールドに固執します。すべての行の時間、重大度、およびサブシステムを特定します。メッセージを明確に定式化します。すべてのログメッセージをソースコード行に簡単にマッピングできます。
エラーが発生した場合は、できるだけ多くの情報を収集して記録してください。時間がかかるかもしれませんが、とにかく通常の処理が失敗したので問題ありません。デバッガーが接続された本番環境で同じ条件が発生したときに待機する必要がないことは、非常に貴重です。
ログは主に監視とトラブルシューティングに必要です。トラブルシューティング担当者の立場に立って、何か問題が発生した場合や真夜中に発生した場合にどのようなログを取得したいかを考えてください。
私は安全性が重要なリアルタイムシステムを使用しており、53火曜日に満月のブルームーンに一度出現するまれなバグを見つける唯一の方法は、ロギングを行うことです。こういうのはあなたがこのテーマにこだわるようになるので、口から泡立ち始めたら申し訳ありません。以下はネイティブコードのデバッグログ用に記述されていますが、そのほとんどは管理対象の世界にも適用されます...
テキストログファイルを使用します。当たり前のようですが、バイナリログファイルを生成しようとする人もいます。野外にいるときにリーダーツールを探す必要がないため、それはばかげています。さらに、テキストでデバッグが冗長である場合、フィールドエンジニアがファイルを読み取って問題を診断できる可能性が高くなります。誰もが勝つ。
ほぼすべてをログに記録できるシステムを設計していますが、デフォルトではすべてをオンにしていません。デバッグ情報は非表示のデバッグダイアログに送信され、タイムスタンプが付けられてリストボックスに出力されます(削除前は約500行に制限されています)。このダイアログを使用して、停止、ログファイルへの自動保存、または宛先変更を行うことができます。付属のデバッガ。その迂回により、複数のアプリケーションからのデバッグ出力をすべてきれいにシリアル化することができます。 I 使用数値ログレベルを使用します(レベルを高く設定するほど、より多くキャプチャします):
off
errors only
basic
detailed
everything
しかし、これは柔軟性に欠けます。バグに向かって作業する場合、大量の破片を処理することなく、必要なものだけにログインに集中できるようにする方がはるかに効率的です。これは、特定の種類のトランザクションまたは操作になる場合があります。それがエラーの原因です。すべてをオンにする必要がある場合は、自分の仕事を難しくしています。きめの細かいものが必要です。
だから今私はフラグシステムに基づいてロギングに切り替える過程にあります。ログに記録されるすべてのものには、その操作の種類を詳細に示すフラグがあり、ログに記録されるものを定義できる一連のチェックボックスがあります。通常、そのリストは次のようになります。
#define DEBUG_ERROR 1
#define DEBUG_BASIC 2
#define DEBUG_DETAIL 4
#define DEBUG_MSG_BASIC 8
#define DEBUG_MSG_POLL 16
#define DEBUG_MSG_STATUS 32
#define DEBUG_METRICS 64
#define DEBUG_EXCEPTION 128
#define DEBUG_STATE_CHANGE 256
#define DEBUG_DB_READ 512
#define DEBUG_DB_WRITE 1024
#define DEBUG_SQL_TEXT 2048
#define DEBUG_MSG_CONTENTS 4096
このロギングシステムはreleaseビルドで出荷され、デフォルトでオンになってファイルに保存されます。バグが発生してから平均して6か月に1回しか発生せず、再現する方法がない場合は、ログが記録されている必要があることを確認するには遅すぎます。デバッグビルドでのみ機能するロギングは、まさにその通りです。明白。ダム。
通常、ソフトウェアはERROR、BASIC、STATE_CHANGE、EXCEPTIONをオンにして出荷されますが、これはデバッグダイアログ(またはこれらが保存されるレジストリ/ ini/cfg設定)を介してフィールドで変更できます。
ああ、1つのこと-私のデバッグシステムは1日に1つのファイルを生成します。要件は異なる場合があります。しかし、デバッグコードが開始することを確認してください 毎 日付、実行しているコードのバージョン、可能であれば顧客IDのマーカー、システムの場所などを記述したファイル。現場から入ってくるログファイルのマッシュマッシュを取得することができ、実際にデータ自体にある、どこから来たのか、彼らが実行していたシステムのバージョンのいくつかの記録が必要であり、顧客を信頼できない/ fieldエンジニアは、どのバージョンを持っているかを教えてくれます-彼らは彼らが持っていると思っているバージョンを教えてくれるかもしれません。さらに悪いことに、ディスク上にあるexeバージョンを報告することがありますが、交換後に再起動するのを忘れたため、古いバージョンがまだ実行されています。コードに自分自身を教えてもらいます。
最後に、コードで独自の問題を生成したくないので、タイマー機能を使用して、数日または数週間後にログファイルをパージします(現在の時刻とファイル作成の時刻の差を確認してください)。これは、常時実行されるサーバーアプリでは問題ありません。クライアント側のアプリでは、起動時に古いデータをパージすることで取得できます。通常、30日程度でパージされます。エンジニアが頻繁に訪問することのないシステムでは、長期間放置することをお勧めします。もちろん、これはログファイルのサイズにも依存します。
ロギングガイドラインで私のお気に入りの公開リソースは Apache JCLベストプラクティス です。
JCLのベストプラクティスは、一般とエンタープライズの2つのカテゴリに分類されます。一般原則はかなり明確です。企業慣行はもう少し複雑で、なぜそれらが重要なのかについて必ずしも明確ではありません。
エンタープライズのベストプラクティスの原則は、「エンタープライズ」レベルの環境での実行が期待されるミドルウェアコンポーネントとツールに適用されます。これらの問題は、国際化としてのロギング、および障害検出に関連しています。企業はより多くの労力と計画を必要としますが、実稼働レベルのシステムでは(必要でない場合)強く推奨されます。異なる企業/環境には異なる要件があるため、柔軟であることは常に役立ちます...
JCLを対象としていますが、これらは一般的なロギングに採用するのに十分汎用的です。
最も有名なアンチパターンはおそらく「例外を飲み込む」ことです-それをウェブで検索してください。
巨大なログファイルに関しては、私の実践では、これはほとんど通常のケースでした。そして、はい、補足スクリプトと呼んでいます、そして/または チェーンソー のようなツールも私には普通に見えます。
PS。アンチパターンに関して、頭に浮かぶのは「洪水」と意味のないメッセージです。
繰り返しの多いループから複数の同様のメッセージが表示されるのを見ると、floodingと呼びます。私にとって、フラッディングは、ソースコードでそれを検出したときにそれを取り除こうとするのに十分に迷惑です。通常、それを改善するにはいくつかの芸術が必要です。なぜなら、ループ内で発生することは興味深いかもしれないからです。私はそれをより深く改善する時間がないときは、少なくともそのようなメッセージのロギングレベルを最低のものに変更して、フィルターをかけやすくすることを試みます。
無意味なメッセージはかなり人気のあるゴミのようです。これらはソースコードで読むと無害に見えます-デバッグ出力を次のように分析するという苦痛を経験する必要があると思います...
step #1
step #2
step #3
...彼らの固有の醜さを深く感謝します。この種の問題をソースコードレベルで検出するための私のお気に入りのヒューリスティック(過去のプロジェクトの1つで同僚が提案)は、スペースシンボルの発生数を計算することですロギングで使用される文字列リテラル。私の経験では、ゼロのスペースは基本的にロギングステートメントが無意味であることを保証し、1つのスペースも潜在的な問題の良い指標です。
例外を1回だけ記録してください!
私が気付いた一般的な問題点の1つは、例外のロギングと再スローです。その結果、ログファイルには、いくつかのスタックレベルで同じ例外が数回含まれています。
これがアンチパターンです。データベーステーブルに20の「汎用変数」フィールドを作成して、考えられるあらゆるものを追跡し、さまざまなタイプのログに88の(およびカウントする)異なる列挙値を設定します。
ログに関する私の経験は大きいほど良いです()十分に一貫性があり、マシンでフィルターできるようにして、アプリケーションのすべてのコンポーネントの重大度レベルを個別に構成できます。
また、将来のバグを見つけるために必要なロギングを予測することは非常に困難です。バグをログに記録する明らかな場所のほとんどは、製品が出荷される前に修正されます。バグレポートの結果として、ログが再度発生した場合の診断に役立つログを追加したことは珍しくありません。
家の運営側からのメモのカップル:
1)ログがローカルで構成可能であることを確認します。できれば、テキストエディターよりも重いツールは使用しないでください。ほとんどの場合、TRACEレベルのログを取得する必要はありませんが、有効にできるようになっています。
2)可能な限り、テキストエディタよりも重いツールでログを読み取れないことを確認してください。本番システムに障害が発生したときに、奇妙な時間にツールを探す必要があることほど悪いことはありません。
スタックトレースとは別に、現在のアプリケーションの状態と入力を記録します。
ソフトウェアは確定的です。通常、これら2つだけがバグを再現するために必要なものです。完全な状態を保存するのが面倒な場合があるので、たとえば以前の入力によって現在の状態を再現する方法もよいでしょう。
もちろん、より多くのデータが常に優れていますが、最低でもこれら2つは、最も簡単なクラッシュの良い出発点です。
私のWebアプリケーションの使用経験から:
(&ストレージを考えると、今日は非常に安いです)
ログ文字列と一致している。私はいつもこの種のパターンを使用しているので: