夜に動かしたPythonが止まっていても、画面に出したprintだけでは原因を追えないことがあります。開始、どこまで進んだか、完了か失敗かをファイルへ残しておくと、次に調べる場所を絞れます。
ログへ残す項目
最初は時刻、処理名、段階、件数、成功か失敗かを記録します。入力行の全文やAPIキーを出す必要はありません。件数やファイル名も共有相手によっては業務情報になるため、ログの保存先と読める人を決めます。
loggingにはDEBUG、INFO、WARNING、ERROR、CRITICALなどの重要度があります。普段の進行はINFO、継続できない処理の失敗はERRORのように、運用で読む基準をそろえます。
CSV処理の開始と失敗を残す例
amounts.csvに、amount_yenという見出しと、1200、300の二行を用意します。架空の入力です。次をsum_with_log.pyとして保存します。
import csv
import logging
from pathlib import Path
log_path = Path(__file__).resolve().parent / "run.log"
logging.basicConfig(
filename=log_path, encoding="utf-8", level=logging.INFO,
format="%(asctime)s %(levelname)s %(name)s %(message)s",
)
logger = logging.getLogger("amount_summary")
logger.info("start")
try:
with open("amounts.csv", encoding="utf-8-sig", newline="") as src:
reader = csv.DictReader(src)
if reader.fieldnames != ["amount_yen"]:
raise ValueError("必要な列がありません")
amounts = []
for row in reader:
value = row.get("amount_yen")
if not value or not value.isascii() or not value.isdecimal():
raise ValueError("金額は空欄なしの半角数字にしてください")
amounts.append(int(value))
logger.info("complete rows=%s", len(amounts))
print(sum(amounts))
except (OSError, ValueError, csv.Error):
logger.exception("CSV集計を中断しました")
raise SystemExit(1)
この入力の期待値は1500です。run.logにstartとcompleteが残ります。金額を空欄へ変えると、エラーと例外の情報を記録して終了コード1で終わります。空欄の試験は、CSVのデータ行を""と書きます。何もない空行は読み飛ばされるため、同じ試験にはなりません。ログへエラーを書くだけで、処理全体が自動的に失敗扱いになるわけではないため、終了の仕方も指定しています。
この例は0以上の整数表記だけを受け付けます。負数、カンマ、小数を扱う業務では、入力ルールを別に決めます。空欄を0へ置き換えて続行する処理にはしていません。ただし、データ行が0件なら合計0で完了します。入力が必須の業務では、0件の扱いを別に決めます。
保存先と文字コード
run.logはスクリプトのあるフォルダーへ保存します。一方、入力のamounts.csvは実行時の作業フォルダーを基準にしています。この違いを残したまま定期実行へ移すと、入力が見つからないことがあります。実務では入力場所も設定で明示します。
encoding="utf-8"はログファイルの文字コードです。既に別の設定でログ出力が初期化されている環境では、basicConfigの設定がそのまま適用されるとは限りません。この例は単独のスクリプトとして実行する前提です。
失敗時に読む順序
失敗した時刻のstartを探し、その後のERRORと例外を読みます。最後の一行だけでなく、どの段階まで進んだかも確認します。logger.exceptionは例外の情報を含めるので、例外文に業務データが入らないかも見直してください。
ログが増え続ける運用では、保存期間とローテーションも必要です。上の例は追記型の小さな記録で、古いログを自動整理する機能は含みません。処理の成否と、通知メールが届いたかは別々に確認するようにします。
関連する作業
例外処理の組み方と、定期実行でログを読む方法は次の記事が関連します。
