2019-03-04 Python標準モジュールloggingの使用

15042 ワード

loggingモジュールの概要
loggingモジュールはPythonに内蔵された標準モジュールで、主に運行ログを出力するために用いられ、出力ログの等級、ログ保存経路、ログファイルのロールバックなどを設定することができる.printに比べて、以下の利点があります.
  • は、異なるログレベルを設定することによって、releaseバージョンで重要な情報のみを出力することができ、大量のデバッグ情報
  • を表示する必要はない.
  • printはすべての情報を標準出力に出力し、開発者が標準出力から他のデータを表示することに深刻な影響を及ぼす.loggingは開発者が情報をどこに出力するか、どのように出力するかを決定することができる.

  • loggingモジュール使用
    1.基本使用
    loggingの基本的な設定を構成し、コンソールでログを出力します.
    import logging
    logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    logger = logging.getLogger(__name__)
    
    logger.info("Start print log")
    logger.debug("Do something")
    logger.warning("Something maybe fail.")
    logger.info("Finish")
    

    運転出力
    2016-10-09 19:11:19,434 - main - INFO - Start print log 2016-10-09 19:11:19,434 - main - WARNING - Something maybe fail. 2016-10-09 19:11:19,434 - main - INFO - Finish
    loggingでは、debug、info、warning、error、criticalなどの多くのメッセージ・レベルを選択できます.loggerまたはhandlerの異なるレベルを与えることで、開発者は特定のレコードファイルにエラー情報のみを出力したり、デバッグ時にデバッグ情報のみを記録したりすることができます.例えば、ロゴのレベルをDEBUGに変更し、出力結果を見てみましょう.
    logging.basicConfig(level = logging.DEBUG,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    

    出力からdebugレベルのメッセージが増えていることがわかります
    2016-10-09 19:12:08,289 - main - INFO - Start print log 2016-10-09 19:12:08,289 - main - DEBUG - Do something 2016-10-09 19:12:08,289 - main - WARNING - Something maybe fail. 2016-10-09 19:12:08,289 - main - INFO - Finish
    logging.basicConfig関数の各パラメータ:
  • filename:ログファイル名を指定します.
  • filemode:file関数と同じ意味で、ログファイルのオープンモード、「w」または「a」を指定します.
  • format:出力のフォーマットと内容を指定し、formatは多くの有用な情報を出力することができます.
  • formatパラメータ%(levelno)s:印刷ログレベルの数値%(levelname)s:印刷ログレベルの名前%(pathname)s:現在の実行プログラムを印刷するパス、実はsys.Argv[0]%(filename)s:現在実行プログラム名を印刷(funcName)s:印刷ログの現在関数%(lineno)d:印刷ログの現在行番号%(asctime)s:印刷ログの時間%(thread)d:印刷スレッドID%(threadName)s:印刷スレッド名%(process)d:印刷プロセスID%(message)s:印刷ログ情報
  • datefmt:時間フォーマットを指定し、time.strftime();
  • level:ログレベルを設定し、デフォルトはlogging.WARNNING;
  • stream:ログへの出力ストリームを指定し、sysへの出力を指定できます.stderr,sys.stdoutまたはファイル、デフォルトはsysに出力.stderr,7. streamとfilenameが同時に指定されると、streamは無視されます.

  • 2.ファイルへのログの書き込み
    2.1ファイルへのログの書き込み
    loggingを設定し、FileHandlerを作成し、出力メッセージのフォーマットを設定してloggerに追加し、指定したファイルにログを書き込みます.
    import logging
    logger = logging.getLogger(__name__)
    logger.setLevel(level = logging.INFO)
    handler = logging.FileHandler("log.txt")
    handler.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    
    logger.info("Start print log")
    logger.debug("Do something")
    logger.warning("Something maybe fail.")
    logger.info("Finish")
    

    log.txtのログデータは、
    2016-10-09 19:01:13,263 - main - INFO - Start print log 2016-10-09 19:01:13,263 - main - WARNING - Something maybe fail. 2016-10-09 19:01:13,263 - main - INFO - Finish
    2.2画面とログファイルへのログの同時出力
    loggerにStreamHandlerを追加し、ログを画面に出力します.
    import logging
    logger = logging.getLogger(__name__)
    logger.setLevel(level = logging.INFO)
    handler = logging.FileHandler("log.txt")
    handler.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)
    
    console = logging.StreamHandler()
    console.setLevel(logging.INFO)
    
    logger.addHandler(handler)
    logger.addHandler(console)
    
    logger.info("Start print log")
    logger.debug("Do something")
    logger.warning("Something maybe fail.")
    logger.info("Finish")
    

    ロゴでいいです.txtファイルとコンソールに同時に表示されます.loggingにはログ処理のメインオブジェクトがあり、その他の処理方法はaddHandlerで追加されています.loggingに含まれるhandlerは主に以下のようなものがあります.
    handler名:位置;作用StreamHandler:logging.StreamHandler;ログはストリームに出力sys.stderr,sys.stdoutまたはファイルFileHandler:logging.FileHandler;ファイルにログを出力handlers.BaseRotatingHandler;基本的なログロールバック方式RotatingHandler:logging.handlers.RotatingHandler;ログロールバック方式、ログファイルの最大数とログファイルロールバックをサポートするTimeRotatingHandler:logging.handlers.TimeRotatingHandler;ログ・ロールバック方式、ログ・ファイルを一定時間領域でロールバックするSocketHandler:logging.handlers.SocketHandler;TCP/IP sockets DatagramHandler:loggingへのリモート出力ログhandlers.DatagramHandler;リモート出力ログUDPソケットSMTPHandler:logging.handlers.SMTPHandler;メールアドレスへのログのリモート出力SysLogHandler:logging.handlers.SysLogHandler;ログ出力syslog NTEventLogHandler:logging.handlers.NTEventLogHandler;Windows NT/2000/XPにログをリモート出力するイベントログMemoryHandler:logging.handlers.MemoryHandler;メモリに出力指定buffer HTTPHandler:logging.handlers.HTTPHandler;「GET」または「POST」でHTTPサーバにリモート出力
    2.3ログロールバック
    RotatingFileHandlerを使用すると、ログロールバックを実行できます.
    import logging
    from logging.handlers import RotatingFileHandler
    logger = logging.getLogger(__name__)
    logger.setLevel(level = logging.INFO)
    #    RotatingFileHandler,    3     ,        1K
    rHandler = RotatingFileHandler("log.txt",maxBytes = 1*1024,backupCount = 3)
    rHandler.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    rHandler.setFormatter(formatter)
    
    console = logging.StreamHandler()
    console.setLevel(logging.INFO)
    console.setFormatter(formatter)
    
    logger.addHandler(rHandler)
    logger.addHandler(console)
    
    logger.info("Start print log")
    logger.debug("Do something")
    logger.warning("Something maybe fail.")
    logger.info("Finish")
    

    プロジェクトディレクトリにバックアップされたログファイルが表示されます.
    2016/10/09 19:36 732 log.txt 2016/10/09 19:36 967 log.txt.1 2016/10/09 19:36 985 log.txt.2 2016/10/09 19:36 976 log.txt.3
    2.4メッセージのレベル設定
    ログの出力を制御するために異なるログレベルを設定できます.
    ログレベル:使用範囲FATAL:致命的なエラーCRITICAL:特に悪いこと、例えばメモリが切れたり、ディスク領域が空になったり、一般的にERRORをあまり使用しません:エラーが発生した場合、例えばIO操作が失敗したり、接続の問題WARNING:重要なイベントが発生したりしますが、エラーではありません.ユーザログインパスワードエラーINFO:処理要求や状態変化などの日常的なトランザクションDEBUG:デバッグ中にDEBUGレベルを使用するアルゴリズムの各ループの中間状態
    2.5 tracebackのキャプチャ
    Pythonのtracebackモジュールは異常戻り情報を追跡するために使用され、loggingにtracebackを記録することができ、
    import logging
    logger = logging.getLogger(__name__)
    logger.setLevel(level = logging.INFO)
    handler = logging.FileHandler("log.txt")
    handler.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)
    
    console = logging.StreamHandler()
    console.setLevel(logging.INFO)
    
    logger.addHandler(handler)
    logger.addHandler(console)
    
    logger.info("Start print log")
    logger.debug("Do something")
    logger.warning("Something maybe fail.")
    try:
        open("sklearn.txt","rb")
    except (SystemExit,KeyboardInterrupt):
        raise
    except Exception:
        logger.error("Faild to open sklearn.txt from logger.error",exc_info = True)
    
    logger.info("Finish")
    

    コンソールとログファイルlog.txtで出力、
    Something maybe fail.
    Faild to open sklearn.txt from logger.error
    Traceback (most recent call last):
      File "G:\zhb7627\Code\Eclipse WorkSpace\PythonTest\test.py", line 23, in 
        open("sklearn.txt","rb")
    IOError: [Errno 2] No such file or directory: 'sklearn.txt'
    Finish
    

    loggerも使用できます.Exception(msg,_args)はlogger.に等価である.error(msg,exc_info = True,_args),
    logger.exception("Failed to open sklearn.txt from logger.exception")
    

    2.6マルチモジュール使用logging
    メインモジュールpy,
    import logging
    import subModule
    logger = logging.getLogger("mainModule")
    logger.setLevel(level = logging.INFO)
    handler = logging.FileHandler("log.txt")
    handler.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)
    
    console = logging.StreamHandler()
    console.setLevel(logging.INFO)
    console.setFormatter(formatter)
    
    logger.addHandler(handler)
    logger.addHandler(console)
    
    
    logger.info("creating an instance of subModule.subModuleClass")
    a = subModule.SubModuleClass()
    logger.info("calling subModule.subModuleClass.doSomething")
    a.doSomething()
    logger.info("done with  subModule.subModuleClass.doSomething")
    logger.info("calling subModule.some_function")
    subModule.som_function()
    logger.info("done with subModule.some_function")
    

    サブモジュールpy,
    import logging
    
    module_logger = logging.getLogger("mainModule.sub")
    class SubModuleClass(object):
        def __init__(self):
            self.logger = logging.getLogger("mainModule.sub.module")
            self.logger.info("creating an instance in SubModuleClass")
        def doSomething(self):
            self.logger.info("do something in SubModule")
            a = []
            a.append(1)
            self.logger.debug("list a = " + str(a))
            self.logger.info("finish something in SubModuleClass")
    
    def som_function():
        module_logger.info("call function some_function")
    

    実行後、制御およびログファイルlog.txtで出力、
    2016-10-09 20:25:42,276 - mainModule - INFO - creating an instance of subModule.subModuleClass 2016-10-09 20:25:42,279 - mainModule.sub.module - INFO - creating an instance in SubModuleClass 2016-10-09 20:25:42,279 - mainModule - INFO - calling subModule.subModuleClass.doSomething 2016-10-09 20:25:42,279 - mainModule.sub.module - INFO - do something in SubModule 2016-10-09 20:25:42,279 - mainModule.sub.module - INFO - finish something in SubModuleClass 2016-10-09 20:25:42,279 - mainModule - INFO - done with subModule.subModuleClass.doSomething 2016-10-09 20:25:42,279 - mainModule - INFO - calling subModule.some_function 2016-10-09 20:25:42,279 - mainModule.sub - INFO - call function some_function 2016-10-09 20:25:42,279 - mainModule - INFO - done with subModule.some_function
    まずメインモジュールでlogger'mainModule'を定義し、それを構成すると、解釈プロセス内の他の場所でgetLogger('mainModule')で得られるオブジェクトはすべて同じで、再構成する必要がなく、直接使用することができます.定義されたこのloggerのサブloggerは、親loggerの定義と構成を共有することができ、いわゆる親子loggerは、「mainModule」で始まる任意のloggerがそのサブloggerである、例えば「mainModule.sub'.
    実際にアプリケーションを開発すると、まずloggingプロファイルでこのアプリケーションに対応する構成を記述することができ、「PythonAPP」のようなルートloggerを生成し、次いでメイン関数でfileConfigを介してlogging構成をロードし、次にアプリケーションの他の場所、異なるモジュールで「PythonAPP.」のようなルートloggerのサブloggerを使用することができる.Core','PythonAPP.Web'は、各モジュールのloggerを繰り返し定義して構成する必要がなく、logを行う.
    JSONまたはYAMLファイルによるloggingモジュールの構成
    Pythonコードでloggingを構成することはできますが、柔軟ではありません.最善の方法は、プロファイルを使用して構成することです.Python 2.7以降のバージョンでは、辞書からlogging構成をロードできます.つまり、JSONまたはYAMLファイルからログの構成をロードできることを意味します.
    3.1 JSONファイルによる構成
    {
        "version":1,
        "disable_existing_loggers":false,
        "formatters":{
            "simple":{
                "format":"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
            }
        },
        "handlers":{
            "console":{
                "class":"logging.StreamHandler",
                "level":"DEBUG",
                "formatter":"simple",
                "stream":"ext://sys.stdout"
            },
            "info_file_handler":{
                "class":"logging.handlers.RotatingFileHandler",
                "level":"INFO",
                "formatter":"simple",
                "filename":"info.log",
                "maxBytes":"10485760",
                "backupCount":20,
                "encoding":"utf8"
            },
            "error_file_handler":{
                "class":"logging.handlers.RotatingFileHandler",
                "level":"ERROR",
                "formatter":"simple",
                "filename":"errors.log",
                "maxBytes":10485760,
                "backupCount":20,
                "encoding":"utf8"
            }
        },
        "loggers":{
            "my_module":{
                "level":"ERROR",
                "handlers":["info_file_handler"],
                "propagate":"no"
            }
        },
        "root":{
            "level":"INFO",
            "handlers":["console","info_file_handler","error_file_handler"]
        }
    }
    

    JSONでプロファイルをロードし、logging.dictConfig構成logging、
    import json
    import logging.config
    import os
    
    def setup_logging(default_path = "logging.json",default_level = logging.INFO,env_key = "LOG_CFG"):
        path = default_path
        value = os.getenv(env_key,None)
        if value:
            path = value
        if os.path.exists(path):
            with open(path,"r") as f:
                config = json.load(f)
                logging.config.dictConfig(config)
        else:
            logging.basicConfig(level = default_level)
    
    def func():
        logging.info("start func")
    
        logging.info("exec func")
    
        logging.info("end func")
    
    if __name__ == "__main__":
        setup_logging(default_path = "logging.json")
        func()
    

    3.2 YAMLファイルによる構成
    version: 1
    disable_existing_loggers: False
    formatters:
            simple:
                format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
    handlers:
        console:
                class: logging.StreamHandler
                level: DEBUG
                formatter: simple
                stream: ext://sys.stdout
        info_file_handler:
                class: logging.handlers.RotatingFileHandler
                level: INFO
                formatter: simple
                filename: info.log
                maxBytes: 10485760
                backupCount: 20
                encoding: utf8
        error_file_handler:
                class: logging.handlers.RotatingFileHandler
                level: ERROR
                formatter: simple
                filename: errors.log
                maxBytes: 10485760
                backupCount: 20
                encoding: utf8
    loggers:
        my_module:
                level: ERROR
                handlers: [info_file_handler]
                propagate: no
    root:
        level: INFO
        handlers: [console,info_file_handler,error_file_handler]
    

    YAMLでプロファイルをロードし、loggingでdictConfig構成logging、
    import yaml
    import logging.config
    import os
    
    def setup_logging(default_path = "logging.yaml",default_level = logging.INFO,env_key = "LOG_CFG"):
        path = default_path
        value = os.getenv(env_key,None)
        if value:
            path = value
        if os.path.exists(path):
            with open(path,"r") as f:
                config = yaml.load(f)
                logging.config.dictConfig(config)
        else:
            logging.basicConfig(level = default_level)
    
    def func():
        logging.info("start func")
    
        logging.info("exec func")
    
        logging.info("end func")
    
    if __name__ == "__main__":
        setup_logging(default_path = "logging.yaml")
        func()
    

    Reference http://www.cnblogs.com/zhbzz2007/p/5943685.html