背景
pythonでdfをfor文で扱うことが多く、デバッグ用にログを残すために下記を実現したく調査した。
- エラーが出ても全dfの処理を行う
- ログ名には、上書きされないようにタイムスタンプを付与したい
- エラー処理で終了しても、正常処理時と同様の処理を行いたい
- エラーはログに出力する。INFOログも残す
それぞれの解決策
- エラーが出ても全dfの処理を行う
⇒ try-exceptを使用 - エラーはログに出力する。INFOログもの残す
⇒ datetimeを使用して付与したファイル名をlogging.basicConfigで設定 - エラー処理で終了しても、正常処理時と同様の処理を行いたい
⇒ finallyを使用
⇒ loggingモジュールのlogging.exceptionを使用。ログレベルをINFOにする。 - ログ名には、上書きされないようにタイムスタンプを付与したい
試しに作成したコード(err_test.py)
import logging
import pandas as pd
import matplotlib.pyplot as plt
import os
import datetime
# ログファイル名に実行ファイル名と日時を追加する
def get_log_filename():
# 実行ファイル名を取得
script_name = os.path.splitext(os.path.basename(__file__))[0]
# 日時を取得
timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
# ログファイル名を作成
log_filename = f"{script_name}_{timestamp}.log"
return log_filename
# ログ設定
logging.basicConfig(filename=get_log_filename(), format='%(levelname)s:%(message)s', level=logging.INFO)
fname_list = ["test1.csv", "test2.csv", "test3.csv"]
result = True
for fname in fname_list:
try:
logging.info(f"{fname}のグラフ化処理を実行します")
df = pd.read_csv(fname)
plt.plot(df["a"], df["b"]) # A列をx軸、B列をy軸としてプロット
plt.show() # グラフ表示
result = True
except Exception as e:
logging.exception(f"{e}")
result = False
finally:
plt.close()
logging.info(f"{fname}のグラフ化処理が完了しました({result})")
出力したエラーファイル例:err_test_20241029225500.log
※test2.csvだけ”b”の列が存在しないように作成した
INFO:test1.csvのグラフ化処理を実行します
INFO:test1.csvのグラフ化処理が完了しました(True)
INFO:test2.csvのグラフ化処理を実行します
ERROR:'b'
Traceback (most recent call last):
File "/home/shou10254/y311/lib/python3.11/site-packages/pandas/core/indexes/base.py", line 3805, in get_loc
return self._engine.get_loc(casted_key)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "index.pyx", line 167, in pandas._libs.index.IndexEngine.get_loc
File "index.pyx", line 196, in pandas._libs.index.IndexEngine.get_loc
File "pandas/_libs/hashtable_class_helper.pxi", line 7081, in pandas._libs.hashtable.PyObjectHashTable.get_item
File "pandas/_libs/hashtable_class_helper.pxi", line 7089, in pandas._libs.hashtable.PyObjectHashTable.get_item
KeyError: 'b'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/shou10254/study/err_test.py", line 25, in <module>
plt.plot(df["a"], df["b"]) # A列をx軸、B列をy軸としてプロット
~~^^^^^
File "/home/shou10254/y311/lib/python3.11/site-packages/pandas/core/frame.py", line 4102, in __getitem__
indexer = self.columns.get_loc(key)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/shou10254/y311/lib/python3.11/site-packages/pandas/core/indexes/base.py", line 3812, in get_loc
raise KeyError(key) from err
KeyError: 'b'
INFO:test2.csvのグラフ化処理が完了しました(False)
INFO:test3.csvのグラフ化処理を実行します
INFO:test3.csvのグラフ化処理が完了しました(True)
デバッグの効率化
問題発生箇所の特定
エラー発生時のスタックトレースや変数の状態などがログとして残るため、問題の原因究明をスムーズに行えます。
デバッグ作業の効率UP
print文デバッグと違い、ログレベルを調整することで、必要な情報だけを効率的に確認できます。
print文デバッグとの違い
ログレベルによる出力制御
loggingでは、DEBUG, INFO, WARNING, ERROR, CRITICALなど、ログレベルを設定できる。状況に応じて出力内容を制御することで、見たい情報だけを効率的に確認可能。
出力先の柔軟性
loggingでは、ファイル、コンソール、データベースなど、ログの出力先を自由に設定可能。状況に応じて使い分けることで、ログ管理を効率化可能。
フォーマットの統一
loggingでは、ログの出力形式を統一可能。これにより、ログ解析ツールとの連携や自動処理が容易になる。
参考url