pythonノート_loggingモジュール(一)

9384 ワード

loggingモジュールはpythonでよく使われるモジュールで、このモジュールの使い方を2~3つの文章で詳しく紹介する予定です.最初の文章は主にloggingのメインソースを話して、もし直接loggingの使い方を見たいならば、第2編を待つことができます.
参照するloggingバージョンはpython 2です.7.3、私はloggingソースコードに中国語の注釈を加えて私のgithubに置いた.https://github.com/Stan-He/python_learn/tree/master/learn_logging
1.開始
最初は、loggingの基本機能を最短のコードで体験してみましょう
import logging

loger=logging.getLoger()
logging.basicConfig()
loger.setLevel('DEBUG')
loger.debug('logsomething')
#  
out>>DEBUG:root:logsomething
  • 最初のステップはloggingを通過する.getLoger関数は、logerオブジェクトを取得しますが、このオブジェクトは一時的に使用できません.
  • 第2ステップ、logging.basicConfig関数は、format、handlerなど、デフォルトの構成を行います.
  • ステップ3、loger呼び出しsetLevel関数定義ログレベルDEBUG
  • 最後に、loggerはdebug関数を呼び出し、標準出力
  • に表示されるdebugレベルのmessageを出力する.
    2.loggingのログ・レベル
    loggingはログを生成する際に、ログ・レベルのメカニズムがあり、デフォルトでは以下のログ・レベルがあります.
    CRITICAL = 50
    ERROR = 40
    WARNING = 30
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    

    各loggerオブジェクトには、levelより高いログのみを出力するログ・レベルがあります.loggerのレベルがINFOの場合、loggerが呼び出されます.debug()はログを出力できませんが、logger.warning()は出力できます.
    一般的に、以上の6つのログ・レベルは、私たちの日常的な使用を完全に満たしています.
    3.loggingのベースクラス
    loggingはpythonのベースモジュールであり、pythonのソースコードの位置は以下の通りです.
    #    
    /usr/lib/python2.7/logging/__init__.py 
    #   handler config
    /usr/lib/python2.7/logging/config.py
    /usr/lib/python2.7/logging/handlers.py
    

    ロゴを構成する主幹のいくつかの基礎クラスはすべて__にありますinit__.py:
    3.1最初の基礎クラスLogRecord
    ログ内の1行のデータに対応するLogRecordオブジェクト.通常は、時間、ログ・レベル、メッセージ情報、現在実行されているモジュール、行番号、関数名などが含まれます.これらの情報は、LogRecordオブジェクトに含まれます.LogRecordオブジェクトは大きな辞書として想像できます
    class LogRecord(object):
        #        
        def getMessage(self):
            #  self.msg
    
    def makeLogRecord(dict):
        #       ,      LogRecord,        ,    LogRecord      
        rv = LogRecord(None, None, "", 0, "", (), None, None)
        rv.__dict__.update(dict)
        return rv    
    

    3.2 2番目の基礎クラスFormatter
    Formatterオブジェクトはログフォーマットを定義するために使用され、LogRecordは多くの情報を保存していますが、ログを打つときにいくつかしか必要ありません.Formatterはpythonの機能に依存する機能を提供しています.
    #       ,        
    print '%(name)s:%(num)d' % {'name':'my_name','num': 100}
    out>>my_name:100
    

    LogRecordが後の辞書なら、Formatterは前のフォーマット文字列・・・の抽象です
    重要なコードは次のとおりです.
    class Formatter(object):
        def __init__(self,fmt=None,datefmt=None):
            if fmt:
                self._fmt = fmt
            else:
                #   format
                self._fmt = "%(message)s"
        def format(self,record)
            #  self._fmt     
            s=self._fmt % record.__dict__
            return s
    

    3.3 3番目のベースクラスFilterとFilterer
    Filterクラス、機能は簡単です.Flter.フィルタ()関数はLogRecordオブジェクトを入力し、フィルタで1を返します.そうしないと0を返します.コードから分かるように、実はLogRecordです.nameのフィルタリング.
    Filtererクラスには、Filterの抽象的なセットであるFilterオブジェクトのリストがあります.
    重要なコードは次のとおりです.
    class Filter(object):
        def __init__(self,name=''):
            self.name=name
            self.nlen=len(name)
        def filter(self,record)
            #  1  record  ,0  record   
            if self.nlen==0:
                return 1
            elif self.name==record.name:
                return 1
            #record.name   filter  
            elif record.name.find(self.name,0,self.nlen) !=0:
                return 0
            #       .
            return (record.name[self.nlen] == ".") 
    
    class Filterer(object):
        #           self.filters=[]       filter
        def addFilter(self,filter)
        def removeFilter(self,filter)
        def filter(self,record):
            #        filter    ,          0
            #  :
            #filter1.name='A',filter2.name='A.B',filter3.name='A.B.C'
            #  record.name='A.B.C.D'   record      filter   
    

    4.loggingの上級クラス
    以上の3つの基礎のクラスがあれば、より重要な高級クラスを組み合わせることができ、高級クラスはloggingの重要な機能を実現することができます.
    4.1 Handler——logの出力過程を抽象化
  • HandlerクラスはFiltererから継承されます.Handlerクラスはlog出力というプロセスの抽象である.
  • 同時にHandlerクラスは1つのメンバー変数selfを持つ.level,第2節で論じたログレベルのメカニズムは,Handlerで実現される.
  • Handlerには、logの出力を担当するemit(record)関数があり、Handlerのサブクラスで実装する必要があります.

  • 重要なコードは次のとおりです.
    class Handler(Filterer):
        def __init__(self,level=NOTSET):
            #handler   level  
            self.level=_checkLevel(level)
        def format(self,record):
            #  self.formatter,formatrecord
        def handle(self,record):
            #    filter   , emit  log
            rv=self.filter(record)
            self.emit(record)
        def emit(self,record):
            #       
    

    次に2つの簡単なhandlerのサブクラスを見てみましょう.実はloggingソースコードにはhandlerがあります.pyは、より複雑なhandlerを多く定義しており、ログをメモリにキャッシュしたり、ログをrotationしたりすることができます.
    4.1.1 StreamHandler
    最も簡単なhandler実装は、logをストリームに書き込む、デフォルトのstreamはsysである.stderr
    重要なコードは次のとおりです.
    class StreamHandler(Handler):
        def __init__(self, stream=None):
            if stream is None:
                stream=sys.stderr
            self.stream=stream
        def emit(self,record):
            # record       
            #         
            fs='%s
    ' # stream=self.stream stream.write(fs % msg)

    4.1.2 FileHandler
    ファイルにlogを出力するhandlerは、StreamHandlerから継承されます.
    重要なコードは次のとおりです.
    class FileHandler(StreamHandler):
        def __init__(self,filename, mode='a'):
            #append  ,      
            StreamHandler.__init__(self, self._open())
        def emit(self,record):
            # streamhandler    
            StreamHandler.emit(self, record)
    

    4.2 Logger-独立したlogパイプ
    loggerとは?
  • loggerクラスはFilterer,
  • から継承される.
  • loggerオブジェクトにloggerがある.levelログレベル
  • loggerオブジェクト制御複数handler:logger.handlers=[]
  • loggerオブジェクト間に親子関係がある
  • 簡単に言えば、loggerというクラスは、私たち以上のすべてのLogRecordクラス、Filterクラス、Formatterクラス、handlerクラスを集めています.まず、loggerは入力に基づいてLogRecordオブジェクトを生成し、FilterとFormatterを通過する後、selfを通過する.handlersリストのすべてのhandlerは、logを送信します.1つのloggerには複数のhandlerがあり、1つのlogを複数の任意の位置に配置することができる.
    重要なコード:
    class Logger(Filterer):
        def __init__ (self,name,level=NONSET):
            #handler  
            self.handlers=[]
            self.level=_checkLevel(level)
        def addHandler(self,hdlr):
        def removeHandler(self,hdlr):
        def _log(self, level, msg, args, exc_info=None, extra=None):
            # _log        LogRecord  
            record = self.makeRecord(self.name, level, fn, lno, msg, args, exc_info, func, extra)
            #  handle  
            self.handle(record)
        def handle(self,record):
            #  filter,    callHandlers
            if (not self.disabled) and self.filter(record):
                self.callHandlers(record)
        def callHandlers(self, record): 
            #   logger     logger,   handl   record
            c=self
            while c:
                for hdlr in c.handlers:
                    hdlr.handle(record) #  handler emit    log
                ……
                c=c.parent
    

    4.3 Manager——loggerのクラスを管理する
    マネージャというクラスは,ユーザには実際には見えないが,ロガーが生成されると自動的に存在し,マネージャオブジェクトはすべてのロガーを管理する.
    loggerとmanagerの関係について、いくつかまとめました.
  • Loggerはログを出力するオブジェクトであり、Managerクラスは複数のLoggerを管理する機能を提供する.
  • の1つのプログラムに1つのmanagerオブジェクトしか存在しない、managerを生成すると必ずRootLogger、managerオブジェクトのselfも生成する.rootはRootLogger
  • を指しています
  • managerオブジェクトのself.loggerDict、この辞書は現在のすべてのloggerオブジェクト(rootloggerを含まない)
  • を保存しています.
  • loggingを使用する場合.getLoggerのnameが空の場合、デフォルトではnameが「root」のRootLogger
  • を指します.
  • loggingを使用する場合.getLoggerのnameは空ではありません.生成されたloggerは、他の親logger
  • を指定しない限り、RootLoggerの下に自動的にマウントされます.
  • 他のloggerはnameによって親子関係を確立する
  • 親子関係の例:
    loger1=logging.getLogger('A')
    loger2=logging.getLogger('A.B')
    #loger2  loger loger1
    loger2.parent
    out>>
    #loger1  loger rootlogger
    loger1.parent
    out>> 
    

    これらの関係はmanagerで管理されています
    重要なコード:
    class Manager(object):
        def getLogger(self,name):
            #    logger, logger  manager  self
            #    logger     
        def _fixupParents(self,aloger):
        def _fixupChildren(self,ph,aloger):
            #    logger     
    

    4.4 Logger Adapter-標準loggerへの拡張
    LogRecordという大きな辞書で提供されているメンバー変数はすでにたくさんありますが、logを出力するときに自分が見たいもっと多くの情報を挟むことを望んでいる場合、例えばこのlogを生成するときに、いくつかの関数を呼び出して他の情報を得ると、これらをLoggerに追加することができ、Logger Adapterというクラスがこの役割を果たします.
    LoggerAdapterというクラスは面白いですが、何かを変更しなければLoggerAdapterクラスとLoggerには違いはありません.Logger AdapterはLogger類をパッケージしただけです.
    LoggerAdapterの使い方は、メンバー関数process()のコメントで説明されています.
    def process(self, msg, kwargs): 
        """
        Normally, you'll only need to override this one method in a
        LoggerAdapter subclass for your specific needs. 
        """
    

    すなわちprocess関数を書き換えると、次の例があります.
    import logging
    import random
    L=logging.getLogger('name')
    
    #      ,  0~1000    
    def func():
        return random.randint(1,1000)
    
    class myLogger(logging.LoggerAdapter):
        #  LoggerAdapter,  process,        msg  
        def process(self,msg,kwargs):
            return '(%d),%s' % (self.extra['name'](),msg)  ,kwargs
    
    #             
    LA=myLogger(L,{'name':func})
    
    #now,do some logging
    LA.debug('some_loging_messsage')
    
    out>>DEBUG:name:(167),some_loging_messsage 
    

    5.loggingのconfig関数
    5.1 def basicConfig(**kwargs)
    basicConfig関数では、各種パラメータが構成されます.パラメータが入力されない場合は、デフォルトの構成が行われます.
  • format構成
  • handler構成
  • level構成