pythonのロギングに関するメモ
logging
たいていは単にlogger = logging.getLogger(__name__)
をそれぞれのスクリプトで行って、メインスクリプトでbasicConfig()
で必要に応じて設定を変えればOK。
print()
に似た情報を出力できる。違いは、情報に重要度の違いを持たせられること。デバッグの時にのみ、出力することができたりする
ここの”基本ロギングチュートリアル”を見よ
if __name__ == '__main__'
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s- %(name)s - %(levelname)s - %(message)s')
logging.debug('this is debug message')
logging.info('this is info message')
logging.warning('this is warning message')
logging.error('this is error message')
logging.critical('this is critical message')
デフォルトだと、ログレベルがloggin.WARNING
になっているためlogging.debug()
やlogging.info()
の内容は出力されない。
http://pieces.openpolitics.com/2012/04/python-logging-best-practices/
loggingパッケージでは4つのタイプのオブジェクトが作れる。
- Loggers … 後述
- Formatters … メッセージをフォーマットする
- Filters … outputをコントロールする。重要度は低い
- Handlers … Fileなど、出力先を変更する
basicConfigの設定が大量にあるときは 1. yamlからロードして辞書し、 2. logging.config.dictConfig()で読み込む とよい
loggerはシングルトンなので、モジュールにつき一つ用意する。
loggerは階層的である
例えばfoo.bar
とfoo.baz
というライブラリがあった場合,
from logging import getLogger
getLogger('foo').setLevel(logging.DEBUG)
すると、上述の二つのライブラリのロギングレベルを同時にDEBUGに設定できる。
logger.****()
にはフォーマット記法が使える
logger.debug('Records: %s', records) #recordsを埋め込む
loggingのベストプラクティス
結論から言うと
from logging import getLogger,StreamHandler,DEBUG
logger = getLogger(__name__) #以降、このファイルでログが出たということがはっきりする。
handler = StreamHandler()
handler.setLevel(DEBUG)
logger.setLevel(DEBUG)
logger.addHandler(handler)
こう書けばよい
なんで?
logging.debug()
logging.basicConfig(lovel = loggin.DEBUG)
を指定すると、使用しているモジュール内のすべてのデバッグレベルが変更されてしまい、いらない情報まで出てきてしまう。
logger = logging.getLogger(__name__)
logger.debug()
が混ざる危険があるのでlogger()
のみを使う
まず初めに以下のように書く
from logging import getLogger
logger = getLogger(__name__)
複数のファイルにまたがるモジュールで共通のlogger
を使用する場合
__init__.py
に、以下のように書いておく。
import logging
def get_module_logger(modname):
logger = logging.getLogger(modname)
handler = logging.StreamHandler()
formatter = logging.Formatter('my-format')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
return logger
そしてそれぞれのクラスでloggerが必要になったら。
from <modname> import get_module_logger
logger = get_module_logger(__name__)
logger
logger.info()
… プログラムの通常の操作中に発生したイベントの報告。
logger.warn()
… アプリケーションのユーザーに対して渡す警告
logger.exception()
… except:
内でのみ使用する。以下が例
try:
#hogehoge
except Exception as e:
logger.exception("hogehoge {}".format(e))
logger.error()
に似るが、スタックトレースを一緒にダンプする。例外ハンドラだけで使用するべき(?)
handler
出力先を指定するオブジェクト。logger.addHandler()
によってlogger
オブジェクトにくっつく。
logger.hadlers
… 現在のハンドラ一覧。デフォルトは空
ハンドラを追加する場合は
fh = logging.FileHandler('test.log', 'a+')
logger.addHandler(fh) #追加
インタラクティブモードで実行されたなら、以降の出力はコンソールとファイルの両方に出るようになる。
そうでない場合(モジュールとして実行された場合)は、コンソールに出力するためには上記のFilehandler('test.log', 'a+')
をStreamHandler()
に変更する必要がある
他にもSMTPでメールを送ったり、Syslogへの出力もできる
QueueHandler、QueueListener
python 3.2以降で追加、リモートジョブのロギングをする。
Formatter
logging.Formatter()
でフォーマッタを生成し、それをhandler.formatter
に代入することで使用可能になる。フォーマッタの例
import logging
logger = logging.getLogger('simple_example')
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name) - %(Levelname)s - %(message)s') #%()内に入る属性はLogRecordと呼ばれる
ch.setFormatter(formatter)
logger.addHandler(ch)
logger.debug('debug message')
コマンドラインには2005-03-19 15:10:26,618 - simple_example - DEBUG - debug message
とでる
Filter
あんまり使わない