lesson 039-loggingモジュール
lesson 039-loggingモジュール
loggingモジュールについて簡単に紹介します.
単純な使用
pythonのloggingモジュールは、デフォルトで標準出力にログを印刷し、WARNINGレベル以上のログのみを表示します.これは、デフォルトのログ・レベルがWARNING(ログ・レベルCRITICAL>ERROR>WARNING>INFO>DEBUG>NOTSET)に設定されていることを示しています.デフォルトのログ・フォーマットは
高度な構成
出力結果logger.log
loggingではデフォルトでは、追加( を設定する. がない場合があります. . を表す です はないかもしれません はないかもしれません はないかもしれません loggerオブジェクト
loggingライブラリには、 Loggerはツリー階層であり、情報を出力する前にLoggerを取得しなければならない(明示的な取得がなければroot Loggerを自動的に作成し、前例のように使用する).logger = logging.getLogger()は、デフォルトのLogger、すなわちroot Loggerを返し、デフォルトのログ・レベル、Handler、Formatter設定を適用します.すなわち、 は2つのloggerオブジェクトを作成しようと試みる: loggerを作成して
loggingモジュールについて簡単に紹介します.
単純な使用
>>> import logging
>>> logging.debug('debug messaage')
>>> logging.info('info message')
>>> logging.warning('warning message')
WARNING:root:warning message
>>> logging.error('error message')
ERROR:root:error message
>>> logging.critical('critical message')
CRITICAL:root:critical message
pythonのloggingモジュールは、デフォルトで標準出力にログを印刷し、WARNINGレベル以上のログのみを表示します.これは、デフォルトのログ・レベルがWARNING(ログ・レベルCRITICAL>ERROR>WARNING>INFO>DEBUG>NOTSET)に設定されていることを示しています.デフォルトのログ・フォーマットは
Logger :
です.高度な構成
import logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S',
filename='logger.log',
filemode='w',
)
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
出力結果logger.log
Sun, 27 Jan 2019 20:04:24 test.py[line:11] DEBUG debug message
Sun, 27 Jan 2019 20:04:24 test.py[line:12] INFO info message
Sun, 27 Jan 2019 20:04:24 test.py[line:13] WARNING warning message
Sun, 27 Jan 2019 20:04:24 test.py[line:14] ERROR error message
Sun, 27 Jan 2019 20:04:24 test.py[line:15] CRITICAL critical message
loggingではデフォルトでは、追加(
a
)でファイルを開きます.logging.basicConfig()
関数では、logging
モジュールのデフォルト動作を特定のパラメータで変更できます.使用可能なパラメータは次のとおりです.filename
:指定したファイル名でFiledHandler
を作成します(handlerの概念は後述します).これにより、ログが指定したファイルに格納されます.filemode
:ファイルの開き方filenameが指定されている場合にこのパラメータを使用します.デフォルト値はa
で、w
も指定できます.format
:handler
で使用されるログ表示フォーマットを指定します.datefmt
:日付時刻フォーマットを指定します.level
:rootlogger
(詳細は後述)のログレベルstream
:指定されたstream
でStreamHandler
が作成されます.sys.stderr, sys.stdout
またはファイル(f=open('test.log','w')
)への出力を指定できます.デフォルトはsys.stderr
です.filename
とstream
の2つのパラメータが同時にリストされている場合、stream
のパラメータは無視されます.format
パラメータで使用可能なフォーマット列:%(name)s
:Loggerの名前%(levelno)s
:数値形式のログ・レベル%(levelname)s
:テキスト形式のログ・レベル%(pathname)s
:ログ出力関数を呼び出すモジュールの完全なパス名.%(filename)s
:ログ出力関数を呼び出すモジュールのファイル名%(module)s
:ログ出力関数を呼び出すモジュール名%(funcName)s
:ログ出力関数を呼び出す関数名%(lineno)d
:ログ出力関数を呼び出す文が存在するコード行%(created)f
:現在時間、UNIX標準の時間を表す浮動小数点数で%(relativeCreated)d
:ログ情報の出力時のロガー作成以降のミリ秒数%(asctime)s
:文字列形式の現在時刻.デフォルトのフォーマットは「2003-07-08 16:49:45896」です.カンマの後ろにあるのはミリ秒%(thread)d
:スレッドID.%(threadName)s
:スレッド名.%(process)d
:プロセスID.%(message)s
:ユーザが出力メッセージlogging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical()
(それぞれ異なるレベルのログ情報を記録するために使用される)、logging.basicConfig()
(デフォルトのログフォーマット(Formatter
)でログシステムにデフォルトのストリームプロセッサ(StreamHandler
)を確立し、ログレベルなどのインフラストラクチャを設定し、root logger(ルートLogger)に追加する)のいくつかのloggingモジュールレベルの関数を理解しました.もう1つのモジュールレベルの関数はlogging.getLogger([name])
です(loggerオブジェクトを返し、名前が指定されていない場合はroot loggerを返します)import logging
#
def create_logger():
###
logger = logging.getLogger()
# handler,
fh = logging.FileHandler('test.log')
# handler,
ch = logging.StreamHandler()
#
fm = logging.Formatter('%(asctime)s %(filename)s[%(lineno)d] %(levelname)s %(message)s')
#
fh.setFormatter(fm)
ch.setFormatter(fm)
# Filter
filt = logging.Filter('mylogger')
fh.addFilter(filt)
ch.addFilter(filt)
#
logger.setLevel('DEBUG') # logger.setLevel(logging.DEBUG)
# ;logger fh ch
logger.addHandler(fh)
logger.addHandler(ch) # ,
return logger
###
#
logger = create_logger()
# ,
# test.log
logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')
loggingライブラリには、
Logger、Handler、Filter、Formatter
という複数のコンポーネントがあります.Loggerオブジェクトはアプリケーションが直接使用できるインタフェースを提供し、Handlerは適切な宛先にログを送信し、Filterはログ情報をフィルタする方法を提供し、Formatterはログ表示フォーマットを指定する.Filter
:フィルタルールを満たすログのみが出力されることを制限します.例えば、filter = logging.Filter('mylogger')
を定義し、このFilterを1つのHandlerに追加すると、このHandlerを使用するLoggerの中でmylogger
という名前のLoggerだけがログを出力することができます.filter = logging.Filter('mylogger'); logger.addFilter(filter)
これはloggerというオブジェクトのみをフィルタリングします.すべてのオブジェクトをフィルタリングしたい場合は、filter = logging.Filter('mylogger'); fh.addFilter(filter); ch.addFilter(filter)
です.これにより、fhまたはchを追加したすべてのloggerオブジェクトがフィルタリングされます.logger = logging.getLogger()
が返すLogger名はroot、ログのデフォルト出力名はrootである.もちろん、Logger.setLevel(lel)
で最も低いログ・レベルを指定することもできます.使用可能なログ・レベルはlogging.DEBUG、logging.INFO、logging.WARNING、logging.ERROR、logging.CRITICAL
です.Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical()
は、異なるレベルのログを出力し、設定されたログレベル以上のログのみが出力されます.import logging
fh = logging.FileHandler('test.log')
ch = logging.StreamHandler()
fm = logging.Formatter('%(asctime)s %(filename)s[%(lineno)d] %(levelname)s %(message)s')
fh.setFormatter(fm)
ch.setFormatter(fm)
logger1 = logging.getLogger('mylogger')
logger1.setLevel(logging.DEBUG)
logger2 = logging.getLogger('mylogger')
logger2.setLevel(logging.INFO)
logger1.addHandler(fh)
logger1.addHandler(ch)
logger2.addHandler(fh)
logger2.addHandler(ch)
logger1.debug('logger1 debug message')
logger1.info('logger1 info message')
logger1.warning('logger1 warning message')
logger1.error('logger1 error message')
logger1.critical('logger1 critical message')
logger2.debug('logger2 debug message')
logger2.info('logger2 info message')
logger2.warning('logger2 warning message')
logger2.error('logger2 error message')
logger2.critical('logger2 critical message')
出力結果:2019-01-27 22:27:35,210 test.py[22] INFO logger1 info message
2019-01-27 22:27:35,228 test.py[23] WARNING logger1 warning message
2019-01-27 22:27:35,236 test.py[24] ERROR logger1 error message
2019-01-27 22:27:35,246 test.py[25] CRITICAL logger1 critical message
2019-01-27 22:27:35,256 test.py[28] INFO logger2 info message
2019-01-27 22:27:35,266 test.py[29] WARNING logger2 warning message
2019-01-27 22:27:35,277 test.py[30] ERROR logger2 error message
2019-01-27 22:27:35,287 test.py[31] CRITICAL logger2 critical message
はlogger 1を通過しているのに.setLevel(logging.DEBUG)はlogger 1のログレベルをDEBUGに設定していますが、なぜ表示時にDEBUGレベルのログ情報が表示されず、INFOレベルのログから表示されるのでしょうか?本来logger 1とlogger 2は同一のLoggerインスタンスに対応しており、logging.getLogger(name)
の名称パラメータnameが同一であれば返されるLoggerインスタンスは同一であり、1つのみ、すなわちnameがLoggerインスタンスに1つずつ対応している.logger 2の例では、myloggerのログレベルをlogger2.setLevel(logging.INFO)
でloggingとする.INFOなので、最後にlogger 1の出力は後に設定されたログレベルに従います.import logging
# logger
logger = logging.getLogger()
logger1 = logging.getLogger('mylogger')
logger1.setLevel(logging.DEBUG)
logger2 = logging.getLogger('mylogger')
logger2.setLevel(logging.INFO)
logger3 = logging.getLogger('mylogger.child1')
logger3.setLevel(logging.WARNING)
logger4 = logging.getLogger('mylogger.child1.child2')
logger4.setLevel(logging.DEBUG)
logger5 = logging.getLogger('mylogger.child1.child2.child3')
logger5.setLevel(logging.DEBUG)
# handler,
fh = logging.FileHandler('test_xxx.log')
# handler,
ch = logging.StreamHandler()
# handler formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)
# logger handler
logger.addHandler(fh)
logger.addHandler(ch)
logger1.addHandler(fh)
logger1.addHandler(ch)
logger2.addHandler(fh)
logger2.addHandler(ch)
logger3.addHandler(fh)
logger3.addHandler(ch)
logger4.addHandler(fh)
logger4.addHandler(ch)
logger5.addHandler(fh)
logger5.addHandler(ch)
#
##logger.debug('logger debug message')
##logger.info('logger info message')
##logger.warning('logger warning message')
##logger.error('logger error message')
##logger.critical('logger critical message')
##
##logger1.debug('logger1 debug message')
##logger1.info('logger1 info message')
##logger1.warning('logger1 warning message')
##logger1.error('logger1 error message')
##logger1.critical('logger1 critical message')
##
##logger2.debug('logger2 debug message')
##logger2.info('logger2 info message')
##logger2.warning('logger2 warning message')
##logger2.error('logger2 error message')
##logger2.critical('logger2 critical message')
##
##logger3.debug('logger3 debug message')
##logger3.info('logger3 info message')
##logger3.warning('logger3 warning message')
##logger3.error('logger3 error message')
##logger3.critical('logger3 critical message')
##
##logger4.debug('logger4 debug message')
##logger4.info('logger4 info message')
##logger4.warning('logger4 warning message')
##logger4.error('logger4 error message')
##logger4.critical('logger4 critical message')
logger5.debug('logger5 debug message')
logger5.info('logger5 info message')
logger5.warning('logger5 warning message')
logger5.error('logger5 error message')
logger5.critical('logger5 critical message')
の実行結果を試してみましょう.2019-01-27 22:39:20,120 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
2019-01-27 22:39:20,120 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
2019-01-27 22:39:20,120 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
2019-01-27 22:39:20,120 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
2019-01-27 22:39:20,120 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
2019-01-27 22:39:20,204 - mylogger.child1.child2.child3 - INFO - logger5 info message
2019-01-27 22:39:20,204 - mylogger.child1.child2.child3 - INFO - logger5 info message
2019-01-27 22:39:20,204 - mylogger.child1.child2.child3 - INFO - logger5 info message
2019-01-27 22:39:20,204 - mylogger.child1.child2.child3 - INFO - logger5 info message
2019-01-27 22:39:20,204 - mylogger.child1.child2.child3 - INFO - logger5 info message
2019-01-27 22:39:20,252 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
2019-01-27 22:39:20,252 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
2019-01-27 22:39:20,252 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
2019-01-27 22:39:20,252 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
2019-01-27 22:39:20,252 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
2019-01-27 22:39:20,310 - mylogger.child1.child2.child3 - ERROR - logger5 error message
2019-01-27 22:39:20,310 - mylogger.child1.child2.child3 - ERROR - logger5 error message
2019-01-27 22:39:20,310 - mylogger.child1.child2.child3 - ERROR - logger5 error message
2019-01-27 22:39:20,310 - mylogger.child1.child2.child3 - ERROR - logger5 error message
2019-01-27 22:39:20,310 - mylogger.child1.child2.child3 - ERROR - logger5 error message
2019-01-27 22:39:20,377 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
2019-01-27 22:39:20,377 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
2019-01-27 22:39:20,377 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
2019-01-27 22:39:20,377 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
2019-01-27 22:39:20,377 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
logger 5に対応する出力ごとに5回表示されたのはなぜですか.これはlogger=loggingを介してgetLogger()はroot Loggerが作成されたことを示し、logger1 = logging.getLogger('mylogger')
はroot Loggerが作成された子供(root.)mylogger,logger2
と同じである.子供、孫、重孫......メッセージを彼のhandlerに配布して処理するだけでなく、すべての祖先Loggerにも処理します.では、##logger.addHandler(fh)
##logger.addHandler(ch)
logger1.addHandler(fh)
logger1.addHandler(ch)
##logger2.addHandler(fh)
##logger2.addHandler(ch)
##
##logger3.addHandler(fh)
##logger3.addHandler(ch)
##
##logger4.addHandler(fh)
##logger4.addHandler(ch)
logger5.addHandler(fh)
logger5.addHandler(ch)
注釈を外して結果を見てみましょう.2019-01-27 22:44:49,567 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
2019-01-27 22:44:49,567 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
2019-01-27 22:44:49,593 - mylogger.child1.child2.child3 - INFO - logger5 info message
2019-01-27 22:44:49,593 - mylogger.child1.child2.child3 - INFO - logger5 info message
2019-01-27 22:44:49,608 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
2019-01-27 22:44:49,608 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
2019-01-27 22:44:49,624 - mylogger.child1.child2.child3 - ERROR - logger5 error message
2019-01-27 22:44:49,624 - mylogger.child1.child2.child3 - ERROR - logger5 error message
2019-01-27 22:44:49,639 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
2019-01-27 22:44:49,639 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
はloggerオブジェクトが表示する位置を注釈しているので、デフォルト方式、すなわち標準出力方式を使用しています.親はlogger 1設定ファイル表示方式のみなので、ここでは2回しか印刷されません.子供、孫、重孫…先祖からのログレベル、Handler、Filter設定を階層的に継承したり、Logger.setLevel(lel)、Logger.addHandler(hdlr)、Logger.removeHandler(hdlr)、Logger.addFilter(filt)、Logger.removeFilter(filt)
を通過したりすることができます.独自のログ・レベル、Handler、Filterを設定します.設定しない場合は継承された値を使用します.