トレースバックから計装まで
目標
トレースバックから原因を3分で特定し、直して終わりにせず、次回のための計装まで埋め込めるようになります。
なぜ重要なのか
トレースバックは下から上へ読みます。最下行が例外の種類と理由を語り、そのすぐ上が実際に落ちたコード行で、上のほうはそこまで至った経路です。そして、例外メッセージにはたいてい問題を起こした実際の値が入っているので、その値で元データを検索すれば、数秒で犯人の行が見つかります。
もう1つ重要なのは、トレースバックが標準出力ではなく標準エラー出力に出るという事実です。顧客企業のバッチジョブのcron設定に2>&1が抜けていて、何か月も失敗の原因がどこにも残っていないケースが本当によくあります。「ログに何もない」と言われたら、まずこれを確認してください。
最後に、直して終わりにすると、来週同じことが繰り返されます。読み飛ばした行を記録するようにする1行が、次回の調査時間を30分から1分に縮めます。これが計装の埋め込みであり、再現しない問題を扱う正攻法でもあります。
ステップ
/root/traceを作成し、/opt/app/report.pyを/root/trace/report.pyにコピーしてください。- 失敗する実行の出力を、標準エラー出力まで含めて
/root/trace/traceback.txtに保存してください。 - 発生した例外の名前だけを
/root/trace/error_type.txtに書いてください。 - 実行を最初に止めた行の
idの値を/root/trace/bad_row.txtに書いてください。 /root/trace/report.pyを仕様どおりに直し、終了コード0で終わるようにしてください。- 直したスクリプトの出力を
/root/trace/out.txtに保存してください。rows=18 total=130400と出力されるはずです。 - 読み飛ばした行を、1行に1つずつ
/root/trace/skipped.logに残すよう、計装を入れてください。 - 同じスクリプトを
/opt/data/orders_api.csvに対して実行し、出力を/root/trace/out2.txtに保存してください。
参考
python3 report.py > /root/trace/traceback.txt 2>&1grep -n abc /opt/data/orders.csvで、例外メッセージの値を元データから探せます。report.pyは引数にファイルパスを受け取ります。ステップ8はpython3 report.py /opt/data/orders_api.csvの形になります。- 診断出力は標準エラー出力に出し、リダイレクトでファイルに受ける方式が最もすっきりします。例:
python3 report.py > out.txt 2> skipped.log - ステップ8のファイルには、読み飛ばす行がありません。ステップ8の実行が
skipped.logを上書きしないよう、別のパスに出力するか、捨ててください。 - よくあるミス1: ステップ2で
2>&1を忘れて、空のファイルになってしまうことです。 - よくあるミス2: ステップ7で、読み飛ばした行を画面にだけ出力してしまうことです。ファイルに残らないと、次の人が見られません。
作業用コピーを作る
/root/traceを作成し、/opt/app/report.pyを/root/trace/report.pyにコピーしてください。
/root/traceを作成し、/opt/app/report.pyをその中にコピーしてください。
失敗の原文を確保する
失敗する実行の出力を、標準エラー出力まで含めて/root/trace/traceback.txtに保存してください。
トレースバックは標準出力ではなく標準エラー出力に出ます。リダイレクトに2>&1が必要です。
例外の種類を書く
発生した例外の名前だけを/root/trace/error_type.txtに書いてください。
トレースバックの最下行で、コロンの前の部分が例外の名前です。名前だけを書いてください。
最初に失敗した行を特定する
実行を最初に止めた行のidの値を/root/trace/bad_row.txtに書いてください。
例外メッセージに実際の値が入っています。元のCSVで、その値を持つ行のidを探してください。
終了コード0にする
/root/trace/report.pyを仕様どおりに直し、終了コード0で終わるようにしてください。
docstringの仕様に、有効な行の条件が3つ書かれています。条件に合わない行は読み飛ばして、処理を続ける必要があります。
集計結果を保存する
直したスクリプトの出力を/root/trace/out.txtに保存してください。rows=18 total=130400と出力されるはずです。
直したスクリプトの出力を、そのままファイルに渡してください。rows=とtotal=の2つの値が両方必要です。
読み飛ばした行を記録する
読み飛ばした行を、1行に1つずつ/root/trace/skipped.logに残すよう、計装を入れてください。
次回同じことが起きたときに1分で終わるよう、計装を埋め込むステップです。読み飛ばした行1つにつき1行ずつ残してください。
別の入力で実行してみる
同じスクリプトを/opt/data/orders_api.csvに対して実行し、出力を/root/trace/out2.txtに保存してください。
今日のデータにだけ合わせた修正は、修正ではありません。/opt/data/orders_api.csvで同じスクリプトを実行し、結果を保存してください。