lesson 039-loggingモジュール

59470 ワード

lesson 039-loggingモジュール
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:指定されたstreamStreamHandlerが作成されます.sys.stderr, sys.stdoutまたはファイル(f=open('test.log','w'))への出力を指定できます.デフォルトはsys.stderrです.filenamestreamの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:ユーザが出力メッセージ
  • loggerオブジェクト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はツリー階層であり、情報を出力する前にLoggerを取得しなければならない(明示的な取得がなければroot Loggerを自動的に作成し、前例のように使用する).logger = logging.getLogger()は、デフォルトのLogger、すなわちroot Loggerを返し、デフォルトのログ・レベル、Handler、Formatter設定を適用します.すなわち、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()は、異なるレベルのログを出力し、設定されたログレベル以上のログのみが出力されます.
  • は2つのloggerオブジェクトを作成しようと試みる:
    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の出力は後に設定されたログレベルに従います.
  • loggerを作成して
    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を設定します.設定しない場合は継承された値を使用します.