[Python]loggingについて勉強したので汎用モジュールを作成
- 2021.08.20
- Python
![[Python]loggingについて勉強したので汎用モジュールを作成](https://kocoffy.com/programmer_cat/wp-content/uploads/2021/08/python_104451-512x500.png)
今までprintで雑なログしか吐いたことがなく、そろそろこの非効率から脱したいと思い、これを機にインプットしました.
そもそもloggingとは何か、については他の良書に譲るとして(都度参考リンクを紹介していきます)、今回汎用的に使えるログ出力機能を作ったのでまとめます.
はじめに
インプットとして以下のサイトを読みました.
【Python】仕組みを理解してログ出力を使いこなす
https://hackers-high.com/python/logging-overview/
⇒「ログとはそもそも何か」から導入していて特にわかりやすかったです.
Pythonでprintを卒業してログ出力をいい感じにする
https://qiita.com/FukuharaYohei/items/92795107032c8c0bfd19
【Python】loggingを使ってログを出力する
https://www.rk-k.com/archives/3993
ロガーの生成
loggingの中核となる部分.
以下のように名前を付けて生成できる.
(「name」は「main」という名前になる)
1 2 3 4 |
from logging import getLogger logger = getLogger(__name__) print(__name__) print(logger.name) |
※「from logging import getLogger 」としているのはlogging.info()の誤作動を避けるため. logging.info()はルートロガーに直接レコードを送るため他のロガーにも影響が出てしまう.
また、実際に出力する場合にはロガーに紐づくハンドラーを利用する.
ちなみにロガーは階層構造となっている.
生成されたロガーは親ロガーを伝播していき、最終的にはルートロガーにたどり着くが、途中でコンソール出力、ファイル出力に枝分かれさせたり、そもそも出力しないようにもできる.
ハンドラ
ログレコードを出力できる.
先ほど生成したロガーに紐づけ、ハンドラの内容に沿ったログレコードをそのロガーから取得します.
1 2 3 4 5 6 7 8 |
# 標準出力(コンソール)にログを出力するハンドラを生成する. from logging import getLogger logger = getLogger(__name__) sh = logging.StreamHandler(sys.stdout) sh.setLevel(logging.WARNING) logger.addHandler(sh) logger.warning("test") |
フォーマッタ
ハンドラが受け取ったログレコードをフォーマットする.
1 2 3 4 5 6 7 8 9 |
from logging import getLogger import sys logger = getLogger(__name__) sh = logging.StreamHandler(sys.stdout) sh.setLevel(logging.WARNING) fmt = logging.Formatter("%(asctime)s - [%(name)s ]- %(levelname)s: %(message)s", "%Y-%m-%d %H:%M:%S") sh.setFormatter(fmt) logger.addHandler(sh) logger.warning("test") |
ログレベル
1 |
logger.setLevel(logging.ERROR ) |
こんな感じで設定するとそれ以下のログレベルは処理されなくなる.
ログレベルの優先順位:
CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET
ログフロー
以下、公式のフローチャートを参照.
https://docs.python.org/ja/3/howto/logging.html#logging-flow
いざ作る
以上を踏まえて以下のようなlogger.pyを作成した.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
from logging import FileHandler, StreamHandler, getLogger import logging import os def init(): """汎用ロガー Returns: [type]: [description] """ # ディレクトリ作成 log_dir = "LOG_OUTPUT" os.makedirs(log_dir, exist_ok=True) logger = getLogger(None) logger.setLevel(logging.DEBUG) # ファイル出力 file = FileHandler(filename=log_dir + '/log_txt.log') file.setLevel(logging.INFO) fmt = logging.Formatter("%(asctime)s - [%(name)s ]- \ %(levelname)s: %(message)s", "%Y-%m-%d %H:%M:%S") file.setFormatter(fmt) # コンソール出力 ch = StreamHandler() ch.setLevel(logging.INFO) ch.setFormatter(fmt) # ハンドラの登録 logger.addHandler(file) logger.addHandler(ch) return logger |
実際に利用する際は以下のような感じで使用するクラスに記述する.
1 2 3 4 5 |
import logger from logging import getLogger logger.init() logger = getLogger(__name__) |
吐かせるログはこんな感じ.
1 |
logger.info("col:{}".format(変数とか)) |
終わりに
今回のインプットおよび汎用モジュール(logger.py)を作成したことで、全体的なコードが綺麗になったのはもちろん、理解度が深まったこともあって作業が円滑になったのが実感できる.
特にターミナルでは追えない、探すのも面倒なときもファイル出力しておけば容易に問題点のチェックもできる.(作ったプロジェクトに雑にこいつを忍ばせておけば心強い…はず)
正直、C#におけるVisualStudioやjavaやkotlinで利用するAndroidStudioなど、IDEが優秀なおかげ(主にデバッグ)で今まで気にもかけていなかったんですよね…よくない.
それでもpython触るようになってからこういった細かな点にも自然と手が伸びるようになるのは良いことですね.これからも精進します.
-
前の記事
Play-yanでゲームボーイミクロをゲーム音楽専用ミュージックプレイヤーにしたい 2021.06.23
-
次の記事
【JupyterLab Desktop App】Jupyter notebookのデスクトップアプリがリリースされたので早速使ってみました 2021.10.08