pythonの公式ドキュメントはどうにも不自由な日本語なのでまとめ直し
あわせて読みたい:
Contents
Loggingモジュールのイメージ
Loggerオブジェクト
loggerオブジェクトを各モジュールに明示する( logging.getLogger(“hogehoge”) )ことで、ログを収集する。
loggerは名前で管理され、違うモジュールでも同じ名前を指定すると同じloggerになる。
木構造
loggerは階層構造を持ち、名前をピリオドで分割することで表現する。
Python パッケージ名前空間におけるモジュール名は __name__
で取得できるので、
logging.getLogger(__name__)
を使ってloggerをモジュール単位で構成することが推奨される。
loggerとhandlerを組み合わせて君だけの最強のloggingを手に入れろ!
loggerがログを収集するものだとすれば、handlerはログを吐き出すオブジェクトである。
loggerとhandlerは多対多で紐付けることが可能である。
標準出力用のhandlerとログファイル出力用のhandlerを用意してどちらもルートロガーに紐付ければ、そのアプリケーションの全loggerの出力を標準出力&ログファイルに出力できる。
複数モジュールでstdoutとファイルにログを吐き出すサンプル
- 構成例
# 実行ファイル
cook_sukiyaki.py
# 設定ファイル
settings.py
# モジュール群
Models
|- Nabe.py
|- Cooker.py
|- SukiyakiGuzai.py
|- Soup.py
# サブモジュール群
AussieBeef.py # SukiyakiGuzai.pyでimport
Gas.py # Cooker.pyでimport
:
:
- settings.py
#!/usr/bin/env python
# coding: utf-8
import os
import argparse
import logging
import logging.handlers
# デバッグか否かをコマンドラインオプションで指定
parser = argparse.ArgumentParser(description="Sukiyaki tsukuruyo!")
parser.add_argument("-d", "--debug", action="store_true", help="Debug mode.")
parser.add_argument("-b", "--beef", type=str, default="aussie", choices=["aussie", "koube"], help="Beef choice.")
# 引数のparse
args = parser.parse_args()
if args.debug:
LOG_LEVEL = logging.DEBUG
else:
LOG_LEVEL = logging.INFO
logger = logging.getLogger("") # root loggerに対して設定することで、これ以後使うloggerすべてに共通の設定が適用される。
formatter = logging.Formatter(
fmt="%(asctime)s:[%(name)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
logger.setLevel(LOG_LEVEL)
# stdout出力
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(formatter)
stream_handler.setLevel(LOG_LEVEL)
logger.addHandler(stream_handler)
# ログ出力
file_handler = logging.handlers.RotatingFileHandler(
os.path.join(os.path.abspath(os.path.dirname(__file__)), "log", "app.log"),
maxBytes=50000000, backupCount=5)
file_handler.setFormatter(formatter)
file_handler.setLevel(LOG_LEVEL)
logger.addHandler(file_handler)
BEEF = args.beef
- cook_sukiyaki.py
#!/usr/bin/env python
# coding: utf-8
import settings
from Nabe import Nabe
from Cooker import Cooker
from SukiyakiGuzai import SukiyakiGuzai
from Soup import Soup
from logging import getLogger
# __name__でloggerを指定することで、pythonの階層構造と同じようにloggerの名前が付与される。
logger = getLogger(__name__)
def cook_sukiyaki(nabe, cooker, guzai, soup):
logger.info("Sukiyaki tsukuruyo!")
logger.debug("Beef: " + guzai.beef)
:
:
if __name__ == "__main__":
nabe = Nabe()
cooker = Cooker()
guzai = SukiyakiGuzai(beef=settings.BEEF)
soup = Soup()
- モジュール、サブモジュールでのloggingでの呼び出し(例: Nabe.py)
#!/usr/bin/env python
# coding: utf-8
# これを書くだけでモジュールごとにloggerが作られる。
from logging import getLogger
logger = getLogger(__name__)
class Nabe:
pass
- log例
2016-07-04 18:26:51:[cook_sukiyaki.py] Sukiyaki tsukuruyo!
2016-07-04 18:26:56:[cook_sukiyaki.py] Beef: aussie
2016-07-04 18:27:00:[Models.Nabe] Nabe oitayo!
ハマりがちな落とし穴
なんか実行してもstdoutに表示されないんだけど
- handlerだけでなくloggerにもsetLevelを忘れずに: http://stackoverflow.com/questions/17523173/python-logging-streamhandler-is-not-sending-logs-to-stdout
参考
- 16.6. logging — Python 用ロギング機能 — Python 3.5.1 ドキュメント: http://docs.python.jp/3.5/library/logging.html
- ログ出力のための print と import logging はやめてほしい – Qiita: http://qiita.com/amedama/items/b856b2f30c2f38665701
- Pythonのロギングについてお勉強したメモ: http://note.crohaco.net/2014/python-logging/
コメント