ホームページ  >  記事  >  バックエンド開発  >  Python の組み込みロギングの使用方法

Python の組み込みロギングの使用方法

王林
王林転載
2023-05-10 10:55:051361ブラウズ

ロギングの主な機能

ユーザーがプログラムのデバッグやプログラム実行中の出力情報の記録に役立つように、ログをさまざまな形式で保存するためのロギング インターフェイスと多数の処理モジュールを提供します。

logging ログ レベル

logging ログ レベルは 5 つのレベルに分かれており、優先順位は高から低の順です:

**CRITICAL; ** 重大なプログラム エラー

**ERROR; **プログラムエラー/部分関数エラー

**WARNING; **プログラムにエラーがある可能性があります

**INFO; **プログラムが正常に実行中 情報

DEBUG プログラムのデバッグ情報

デフォルトのログ記録レベルは WARNING です。つまり、ログ レベルが WARNING 以上の場合にのみ記録されます。

一般的に使用される記録レベルは INFO で、プログラムの通常の動作に関する情報を記録するために使用されます (印刷と同様)。

ログ レベルが WARNING 以上に達すると、現時点ではプログラムが正常に実行できないことを示します。

ログの基本機能

logging.basicConfig(**kwargs)

は、明示的にRecorder ( logger) を使用すると、ルート ロガーがデフォルトで作成されます。logging.basicConfig(**kwargs) は、デフォルトの Formatter を使用して streamHandle を作成し、それをルート ロガーに追加して基本構成を初期化できます。

import logging
logging.debug('Debug code!')
logging.info('Run code!')
logging.warning('Watch out!')  
logging.error('This is an error')
logging.critical('This is a ciritical')

上記のコードでは、ロギングは明示的にロガー (logging.getLogger) を作成せず、debug()、info()、warning()、error() を直接使用します。 ) の場合、critical() が呼び出されたときにデフォルトのルート ロガーが使用され、ルート ロガーを初期化するためにカスタムまたはデフォルトのlogging.basicConfig(**kwargs) が自動的に呼び出されます。

カスタムlogging.basicConfig(**kwargs)のパラメータには、次の主なオプションがあります:

パラメータ 関数
filename ログを保存するファイル名を指定し、指定したファイル名で FileHandler を作成すると、記録されたログがファイルに保存されます
format 出力の形式と内容を指定します。デフォルトは、コロンで区切られたレベル名、名前、メッセージです。
datefmt Use 指定された日付/時刻形式。time.strftime() で受け入れられる形式と同じです。
level ルート ロガー レベルを指定します。デフォルトはロギングです。警告
stream ログの出力ストリームを指定します。出力を sys.stderr、std.stdout、またはファイルに指定できます。デフォルトの出力は sys.stderr です。指定されたストリームを使用して StramHandler を初期化します。 注: ストリーム パラメータとファイル名パラメータには互換性がありません。両方を同時に使用すると、ValueError が発生します。

例:次のカスタムlogging.basicConfig (**kwargs)を使用してルートロガーを初期化し、DEBUGレベル以上のログレコードを取得し、log.txtファイルに保存します。

import logging
logging.basicConfig(filename='./log.txt',
                        format='%(asctime)s-%(name)s-%(levelname)s-%(message)s-%(funcName)s:%(lineno)d',
                        level=logging.DEBUG)
logging.debug('Debug code!')
logging.info('Run code!')
logging.warning('Watch out!')  
logging.error('This is an error')
logging.critical('This is a ciritical')

ロギングの 4 つの主要なコンポーネント (クラス)

Logger

ルート ロガー (ルート ロガー) に加えて、最も重要なことは、独自のロガー。

モジュールレベルの関数を通じてlogging.getLogger(name) ロガーをインスタンス化する

デフォルトでは、ロガーは . による階層構造を採用します。さまざまなレベルを区別するため。たとえば、foo という名前のロガーがある場合、foo.afoo.b は両方とも foo の子ロガーです。もちろん、最初または最上位のロガーはルート ロガーです。 name=None の場合、ルート ロガーが構築されます。

現在のモジュールの名前をロガーの名前として直接使用できますlogging.getLogger(__name__)

子レベルのロガーは通常、設定する必要はありませんログ レベルとハンドラーを個別に設定する場合、子ロガーが個別に設定されていない場合、その動作は親に委任されます。たとえば、ロガー foo のレベルは INFO ですが、foo.afoo.b のどちらにもログ レベルが設定されていません。現時点では、foo.afoo.bfoo のレベル設定に従います。つまり、INFO 以上のレベルを持つログのみが出力されます。 foo が設定されていない場合は、ルート ロガーが見つかります。ルートのデフォルト レベルは WARGING です。

ロガー クラスの一般的に使用されるいくつかのメソッド

メソッド 関数の説明
Logger.setLevel() ロガーが処理するログ メッセージ レベルを設定します
Logger.addHandler() ハンドラー オブジェクトの追加
Logger.removeHandler() ハンドラー オブジェクトの削除
Logger.addFilter( ) フィルター オブジェクトの追加
Logger.removeFilter() フィルター オブジェクトの削除
Logger.debug () DEBUG レベルのログを設定します
Logger.info() INFO レベルのログを設定します
Logger.warning() 警告レベルのログの設定
Logger.error() エラー レベルのログの設定
Logger.critical() CRITICAL レベルのログ記録を設定します
Logger.Exception( ) スタック トレース情報を出力します
Logger.log() カスタム レベル パラメータを設定してログ レコードを作成する

logger は、後で紹介する他の 3 つのコンポーネントと組み合わせて、次の機能を実現できます。

  • Logger は、ハンドラーを介してターゲットの場所にログ情報を出力する必要があります。場所は sys.stdout や files などになります (これはlogging.basicConfig(**kwargs)設定と一致しません)。

  • ロガーは異なるハンドラーを設定でき、異なるハンドラーは異なる場所 (異なるログ ファイル) にログを出力でき、各ハンドラーは独自のフィルターを設定してログ フィルタリングを実装し、ログを保持できます。実際のプロジェクトでは必要になります。同時に、各 Handler は異なる Formatter を設定することもでき、各 Formatter は同じログを異なる形式で異なる場所に出力できることを実現します。

ハンドル

プロセッサ; 記録されたログの出力先 (標準出力/ファイル/...) を制御でき、プロセッサはフィルター Filter および Filter を追加することもできます。フォーマッタは、出力コンテンツと出力形式を制御するために使用されます。

これには、いくつかの共通プロセッサがあります:

  • logging.StreamHandler 標準ストリーム プロセッサ。メッセージを標準出力ストリームとエラー ストリームに送信します-->logging .StreamHandler( sys.stdout) # sys.stdout は、コンソール、つまり標準出力を指すことを意味します。Python でオブジェクトを印刷するために print obj を呼び出すとき、実際には sys.stdout.write(obj '\n') を呼び出します。

  • print は、必要なコンテンツをコンソールに出力し、改行文字を追加します。

  • logging.FileHandler ファイル ハンドラー、メッセージ送信先file -->logging.FileHandler(log_path)

  • logging.RotatingFileHandler ファイル ハンドラー、ファイルが指定されたサイズに達した後、新しいファイルでログを保存できるようにします

  • logging.TimedRotatingFileHandler ファイル ハンドラー、ログは特定の時間間隔でログ ファイルをローテーションします

ハンドル クラスのいくつかの一般的なメソッド

##Handler.setLevel()プロセッサが処理するログ メッセージの最小重大度レベルを設定しますHandler.setFormatter()プロセッサのフォーマット オブジェクトを設定しますHandler.addFilter()プロセッサのフィルタ オブジェクトを追加します ##Handler.removeFilter()logging.StramHandler()logging.FilterHandler()RotationFileHandler()TimeRotatingFileHandler( )logging.handers.HTTPHandler()#logging.handlers.SMTPHandler()ログ メッセージを電子メール アドレスに送信します
ハンドラーのフィルター オブジェクトを削除します。
ログ メッセージを出力ストリーム (std.out、std.err など)
ログ メッセージをディスク ファイルに送信します。デフォルトでは、ファイル サイズは大きくなります。ワイヤレス
ログ メッセージをディスク ファイルに送信し、サイズに応じたログ ファイルの切り取りをサポートします
ログ メッセージをディスク ファイルに送信し、時間によるログ ファイルの分割をサポートします
GET 経由でログ メッセージを送信しますまたは HTTP サーバーに POST
##

Filter

filter组件用来过滤 logger 对象,一个 filter 可以直接添加到 logger对象上,也可以添加到 handler 对象上,而如果在logger和handler中都设置了filter,则日志是先通过logger的filter,再通过handler的filter。由于所有的信息都可以经过filter,所以filter不仅可以过滤信息,还可以增加信息。

Filter 类的实例化对象可以通过 logging.Filter(name) 来创建,其中name 为 记录器的名字,如果没有创建过该名字的记录器,就不会输出任何日志:

filter = logging.Filter("foo.a")

基本过滤器类只允许低于指定的日志记录器层级结构中低于特定层级的事件,例如 这个用 foo.a 初始化的过滤器,则foo.a.b;foo.a.c 等日志记录器记录的日志都可以通过过滤器,而foo.c; a.foo 等就不能通过。如果name为空字符串,则所有的日志都能通过。

Filter 类 有 三个方法 :

  • addFilter(filter) : 为 logger(logger..addFilter(filter)) 或者 handler(handler..addFilter(filter)) 增加过滤器

  • removeFilter(filter) : 为 logger 或者 handler 删除一个过滤器

  • filter(record) : 表示是否要记录指定的记录?返回零表示否,非零表示是。一般自定义Filter需要继承Filter基类,并重写filter方法

Formatter

格式化日志的输出;实例化:formatter = logging.Formatter(fmt=None,datefmt=None); 如果不指明 fmt,将默认使用 ‘%(message)s’ ,如果不指明 datefmt,将默认使用 ISO8601 日期格式。

其中 fmt 参数 有以下选项:

%(name)s Logger的名字
%(levelno)s 数字形式的日志级别
%(levelname)s 文本形式的日志级别;如果是logger.debug则它是DEBUG,如果是logger.error则它是ERROR
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出函数的模块的文件名
%(module)s 调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s 用户输出的消息; 假如有logger.warning("NO Good"),则在%(message)s位置上是字符串NO Good

例如:

formatter = logging.Formatter('%(asctime)s %(levelname)-8s: %(message)s')		# -表示右对齐 8表示取8位
handler.formatter = formatter

datefmt 参数 有以下选项:

参数 含义
%y 两位数的年份表示(00-99)
%Y 四位数的年份表示(000-9999)
%m 月份(01-12)
%d 月内中的一天(0-31)
%H 24小时制小时数(0-23)
%I 12小时制小时数(01-12)
%M 分钟数(00=59)
%S 秒 (00-59)

例如:

formatter = logging.Formatter('%(asctime)s %(levelname)-8s: %(message)s')		# -表示右对齐 8表示取8位
handler.formatter = formatter

datefmt 参数 有以下选项:

参数 含义
%y 两位数的年份表示(00-99)
%Y 四位数的年份表示(000-9999)
%m 月份(01-12)
%d 月内中的一天(0-31)
%H 24小时制小时数(0-23)
%I 12小时制小时数(01-12)
%M 分钟数(00=59)
%S 秒 (00-59)

例子:

formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s","%Y%m%d-%H:%M:%S")
handler.formatter = formatter

logging 的配置

  • conf 形式的配置

在 loguser.conf 中 写入相关的信息

[loggers]
keys=root,fileLogger,rotatingFileLogger

[handlers]
keys=consoleHandler,fileHandler,rotatingFileHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=INFO
handlers=consoleHandler

[logger_fileLogger]
level=INFO
handlers=fileHandler
qualname=fileLogger
propagate=0

[logger_rotatingFileLogger]
level=INFO
handlers=consoleHandler,rotatingFileHandler
qualname=rotatingFileLogger
propagate=0

[handler_consoleHandler]
class=StreamHandler
level=INFO
formatter=simpleFormatter
args=(sys.stdout,)

[handler_fileHandler]
class=FileHandler
level=INFO
formatter=simpleFormatter
args=("logs/fileHandler_test.log", "a")

[handler_rotatingFileHandler]
class=handlers.RotatingFileHandler
level=WARNING
formatter=simpleFormatter
args=("logs/rotatingFileHandler.log", "a", 10*1024*1024, 50)

[formatter_simpleFormatter]
format=%(asctime)s - %(module)s - %(levelname)s -%(thread)d : %(message)s
datefmt=%Y-%m-%d %H:%M:%S
  • 在使用logger时,直接导入配置文件即可

from logging import config

with open('./loguser.conf', 'r', encoding='utf-8') as f:
	## 加载配置
    config.fileConfig(f)
    ## 创建同名Logger,其按照配置文件的handle,formatter,filter方法初始化
    logger = logging.getLogger(name="fileLogger")
  • yaml 形式配置文件

在 loguser.yaml文件 中 配置相关信息

version: 1
disable_existing_loggers: False
# formatters配置了日志输出时的样式
# formatters定义了一组formatID,有不同的格式;
formatters:
  brief:
      format: "%(asctime)s - %(message)s"
  simple:
      format: "%(asctime)s - [%(name)s] - [%(levelname)s] :%(levelno)s: %(message)s"
      datefmt: '%F %T'
# handlers配置了需要处理的日志信息,logging模块的handler只有streamhandler和filehandler
handlers:
  console:
      class : logging.StreamHandler
      formatter: brief
      level   : DEBUG
      stream  : ext://sys.stdout
  info_file_handler:
      class : logging.FileHandler
      formatter: simple
      level: ERROR
      filename: ./logs/debug_test.log
  error_file_handler:
    class: logging.handlers.RotatingFileHandler
    level: ERROR
    formatter: simple
    filename: ./logs/errors.log
    maxBytes: 10485760 # 10MB #1024*1024*10
    backupCount: 50
    encoding: utf8

loggers:
#fileLogger, 就是在代码中通过logger = logging.getLogger("fileLogger")来获得该类型的logger
  my_testyaml:
      level: DEBUG
      handlers: [console, info_file_handler,error_file_handler]
# root为默认情况下的输出配置, 当logging.getLogger("fileLoggername")里面的fileLoggername没有传值的时候,
# 就是用的这个默认的root,如logging.getLogger(__name__)或logging.getLogger()
root:
    level: DEBUG
    handlers: [console]

同样的可以通过导入 yaml 文件加载配置

with open('./loguser.yaml', 'r', encoding='utf-8') as f:
        yaml_config = yaml.load(stream=f, Loader=yaml.FullLoader)
        config.dictConfig(config=yaml_config)

    root = logging.getLogger()
    # 子记录器的名字与配置文件中loggers字段内的保持一致
    # loggers:
    #   my_testyaml:
    #       level: DEBUG
    #       handlers: [console, info_file_handler,error_file_handler]
    my_testyaml = logging.getLogger("my_testyaml")

logging 和 print 的区别

看起来logging要比print复杂多了,那么为什么推荐在项目中使用 logging 记录日志而不是使用print 输出程序信息呢。

相比与print logging 具有以下优点:

  • 可以通过设置不同的日志等级,在 release 版本中只输出重要信息,而不必显示大量的调试信息;

  • print 将所有信息都输出到标准输出中,严重影响开发者从标准输出中查看其它数据;logging 则可以由开发者决定将信息输出到什么地方,以及怎么输出;

  • 和 print 相比,logging 是线程安全的。(python 3中 print 也是线程安全的了,而python 2中的print不是)(线程安全是指在多线程时程序不会运行混乱;而python 2 中的print 分两步打印信息,第一打印字符串,第二打印换行符,如果在这中间发生线程切换就会产生输出混乱。这就是为什么python2的print不是原子操作,也就是说其不是线程安全的)印信息,第一打印字符串,第二打印换行符,如果在这中间发生线程切换就会产生输出混乱。这就是为什么python2的print不是原子操作,也就是说其不是线程安全的)

以上がPython の組み込みロギングの使用方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。