[Pythonモジュール] ロギングログモジュール

言語を使い始めるとき、ログ情報を出力する最も簡単で直感的な方法は、print() 関数を使用することです。これは、練習とテストの後にのみ行われます。プロジェクトに参加する場合、必ず log モジュールを使用してログ情報を出力および記録します。また、Python には組み込みのログ モジュール logging が用意されているため、それについてさらに学習する必要があります。

1. ログオプションの基本設定

ロギング ログには 5 つのレベルがあり、出力の優先順位は次のとおりです: クリティカル > エラー > 警告 > 情報 > デバッグ. デフォルトでは、情報およびデバッグ レベルのログは出力されません. テストは次のとおりです:

logging モジュール導入後、オプションを設定しない場合は、警告レベル以上のログのみが出力され、出力形式は比較的シンプルで、デフォルトの形式は [ログレベル: root: ログ出力内容] です。

この時点で、basicConfig() メソッドを使用して、さらに設定を行うことができます. このメソッドのパラメーター オプションは次のとおりです。

  • filename: 出力ログ ファイルの名前を指定します。
  • filemode: ログ情報がファイルに書き込まれるモード。デフォルトは a です。
  • 形式: 形式。オプションは次のとおりです。
    • %(levelno)s: ログレベルの値を出力します
    • %(asctime)s: ログを出力する時間
    • %(levelname)s: ログ レベルの名前を出力します
    • %(pathname)s: 現在実行中のプログラムのパスを表示します。これは実際には sys.argv[0] です。
    • %(filename)s: 現在実行中のプログラムの名前を出力します
    • %(funcName)s: ログの現在の関数を出力します
    • %(lineno)d: ログの現在の行番号を出力します
    • %(process)d: 印刷プロセス ID
    • %(thread)d: スレッド ID の出力
    • %(threadName)s: スレッド名を表示
    • %(message)s: ログ情報の出力
  • datefmt: フォーマットされた日付と時刻を指定します。
  • style: フォーマット記号を指定します。デフォルトは % です。
  • level: ログ レベルを設定します。
  • stream: ログ出力ストリームのストリームまたはファイル名を指定します。ファイル名と一緒に指定すると、ストリームは無視されます。
  • handlers: ロギング プロセッサを指定します。
  • force: true として指定すると、ルート ロガー内のプログラムはすべて無視されます。

この API のパラメーター オプションに従って、構成ログの出力スタイルをカスタマイズできます。次に例を示します。

import logging
from datetime import date, datetime

filename = f'D:\\XXX\\{str(date.today())}.log'
format_option = '%(asctime)s - %(filename)s[line:%(lineno)d] - %(threadName)s - %(levelname)s: %(message)s'
logging.basicConfig(filename=filename,  # 输出到指定log文件
                    filemode='a+',  # 以a+写入
                    format=format_option,
                    datefmt='%Y-%m-%d %H:%M:%S',  # 日期时间格式:2022-11-25 21:59:59
                    level=logging.INFO  # 高于该级别的日志都可以输出显示)
logging.info(f"current datetime {datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S')}")
logging.warning(f"current datetime {datetime.strftime(datetime.now(), '%Y/%m/%d %H:%M:%S')}")

2022-11-25.log ファイルへのログ出力は次のとおりです。

もちろん、basicConfig() を使用してログ スタイルを設定する方法にも制限があります。たとえば、ログを切り取り、ログを複数のファイルに記録します。

2. プロセッサ Handler に基づいてログ オプションを設定します。

Python もオブジェクト指向言語です. ログ オプションは Handler オブジェクトを介して設定できます. Handler を導入するには 2 つの方法があります.

<1>. ロギング モジュールを介してインポートされるハンドラは次のとおりです。

  • Handler: すべてのハンドラーが持つべきインターフェースを定義する基本クラスであり、サブクラスが使用 (またはオーバーライド) できるいくつかのデフォルトの動作を確立します。
  • StreamHandler: sys.stdout (標準出力ストリーム)、sys.stderr (標準エラー ストリーム)、または任意のファイルのようなオブジェクト (つまり、write() および flush() をサポートする任意のオブジェクト) などのデータ ストリームにログ レコードを出力します。メソッド);
  • FileHandler: StreamHandler から継承されたログ レコードをディスク ファイルに出力します。
  • NullHandler: 書式設定や出力を実行しません。実際には、ライブラリ開発者が使用する「ノーオペレーション」ハンドラーです。

ここで、最も一般的に使用されるのは StreamHandler と FileHandler で、後で詳しく説明します。

<2>. logging.handlers モジュールによって導入されたハンドラは次のとおりです。

  • HTTPHandler: GET または POST メソッドを使用して、メッセージを HTTP サーバーに送信します。
  • QueueHandler: キューまたはマルチプロセッシング モジュールで実装されたものなどのキューにメッセージを送信します。
  • SMTPHandler: 指定された電子メール アドレスにメッセージを送信します。
  • MemoryHandler: メッセージをメモリ内のバッファに送信します。特定の条件が満たされている限り、バッファは更新されます。
  • SocketHandler: TCP/IP ソケットにメッセージを送信します (3.4 以降、Unix ドメイン ソケットもサポートされています)。
  • DatagramHandler: UDP ソケットにメッセージを送信します (3.4 以降では、Unix ドメイン ソケットもサポートされています)。
  • RotatingFileHandler: メッセージをディスク ファイルに送信し、最大ログ ファイル サイズとログ ファイルの切り取りをサポートします。
  • TimedRotatingFileHandler: メッセージをディスク ファイルに送信し、特定の時間間隔でログ ファイルを切り取ります。
  • BaseRotatingHandler: ログ ファイルをローテーションするプロセッサの基本クラスです。直接インスタンス化しないでください。代わりに RotatingFileHandler または TimedRotatingFileHandler を使用してください。
  • NTEventLogHandler: Windows NT/2000/XP イベント ログにメッセージを送信します。
  • SysLogHandler: Unix syslog デーモンにメッセージを送信します (おそらくリモート コンピューター上)。
  • WatchedFileHandler: ログに書き込みたいファイルを監視します。ファイルが変更された場合、ファイルは閉じられ、ファイル名で再度開かれます。このハンドラは、Unix 系のシステムでのみ有用です。Windows は、依存する基本的なメカニズムをサポートしていません。

logging モジュールはこのような豊富なログ プロセッサを提供するため、さまざまな使用シナリオに従って対応するハンドラを選択できます。たとえば、RotatingFileHandler はログの切り取りに最も適した選択肢でありQueueHandler は複数のプロセスによって引き起こされるログ レコードのブロックの問題を解決するのに適しています...... 詳細は後述します。

2.1 ストリームハンドラ

ストリーム ログ レコード プロセッサは、カスタム ログ スタイルをサポートし、ログ コンテンツをストリーム形式で出力し、デフォルトで sys.stderr に出力するか、コンストラクタで特定のストリーム インスタンスを指定します。デモンストレーションは次のとおりです。

# 获取日志记录器
logger = logging.getLogger()
# 设置全局日志输出级别
logger.setLevel(logging.INFO)
# 创建stream日志记录处理器,默认使用sys.stderr
streamHandler = logging.StreamHandler()
# 定义日志输出风格(格式器)
format_option = '%(asctime)s - %(filename)s[line:%(lineno)d] - %(threadName)s - %(levelname)s: %(message)s'
streamHandler.setFormatter(logging.Formatter(format_option))
# 将日志记录处理器加入日志对象
logger.addHandler(streamHandler)
logger.info(f"current datetime {datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S')}")
logger.info(f"current datetime {datetime.strftime(datetime.now(), '%Y/%m/%d %H:%M:%S')}")

効果は次のとおりです。

2.2 ファイルハンドラー

ファイル ログ プロセッサはカスタム ログ スタイルもサポートし、ログの内容をディスク ファイルに出力して保存します。コンストラクターは、ログ出力ファイル名、書き込みモード、エンコード方法、記録遅延を遅らせるかどうか、およびその他のオプション設定をサポートします。デモンストレーションは次のとおりです。

logger = logging.getLogger() # 获取日志记录器
logger.setLevel(logging.INFO) # 设置全局日志输出级别
# 创建文件日志记录处理器,并指定一些设置选项
fileHandler = logging.FileHandler(filename=f'D:\\XXX\\{str(date.today())}_fileHandler.log',
                                  mode='a+', encoding='utf-8', delay=False)
# 定义日志输出风格(格式器)
format_option = '%(asctime)s - %(filename)s[line:%(lineno)d] - %(threadName)s - %(levelname)s: %(message)s'
fileHandler.setFormatter(logging.Formatter(format_option))
# 定义日志输出级别(这个不起作用,需要使用全局定义)
# fileHandler.setLevel(logging.DEBUG)
# 将日志记录处理器加入日志对象
logger.addHandler(fileHandler)
logger.info(f"current datetime {datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S')}")
logger.info(f"current datetime {datetime.strftime(datetime.now(), '%Y/%m/%d %H:%M:%S')}")

効果は次のとおりです。

delay パラメータが True の場合、ファイルのオープンは emit() メソッドの最初の呼び出しまで延期され、emit() メソッドは logging.LogRecord() を導入する必要があることに注意してください。これについてはここでは詳しく説明しません。

2.3 RotatingFileHandler はログの切り取りを実装します

RotatingFileHandler の親クラスは BaseRotatingHandler であり、BaseRotatingHandler の親クラスは logging.FileHandler であるため、RotatingFileHandler は基本的に FileHandler を介してディスク ファイルを操作します。ログのセグメンテーションを実現します。デモンストレーションは次のとおりです。

logger = logging.getLogger()  # 获取日志记录器
logger.setLevel(logging.DEBUG)  # 设置全局日志级别
# 基本设置:log文件路径、写入模式、切割后每个文件大小(5k)、文件数量(现分在4个)、编码方式、是否延迟记录日志
rotatingFileHandler = RotatingFileHandler('D:\\XXX\\test_rotatingFileHandler.log',
                                          mode='a', maxBytes=5 * 1024,
                                          backupCount=4, encoding='utf-8', delay=False)
# 定义日志输出风格(格式器)
format_option = '%(asctime)s - %(filename)s[line:%(lineno)d] - %(threadName)s - %(levelname)s: %(message)s'
rotatingFileHandler.setFormatter(logging.Formatter(format_option))
# 将日志记录处理器加入日志对象
logger.addHandler(rotatingFileHandler)
for i in range(1, 221):
    logger.info(f"你可曾记得,这已经是我第{i}次说了,哎!")

カット効果は以下の通りです。

2.4 QueueHandler は ロギングのブロッキング問題を解決します

Web アプリケーションでは、複数のプロセスがログ レコードをブロックするという問題がよくあります。これを解決するには、QueueHandler + QueueListener ソリューションを使用できます。

実際には、パフォーマンスを必要とするいくつかの主要なスレッドは、QueueHandler をログ オブジェクトに接続することしかできません。ログオブジェクトは単純にキューに書き込むだけでよいが、キューの容量を十分大きく設定してもよいし、初期化時に容量の上限を設定しなくてもよい。

QueueListener の利点は、同じインスタンスを使用して複数の QueueHandler を提供できることです。QueueListener には、キューと 1 つ以上のハンドラーを渡す必要があり、内部スレッドが開始されて、QueueHandlers (または他の LogRecords ソース) によって送信された LogRecord キューをリッスンし、LogRecords がキューから削除され、ハンドラーに渡されます。処理。デモンストレーションは次のとおりです。

3. 構成ファイルに基づいてログ オプションを設定する

Python 3.2 以降のバージョンでは、ログ構成をディクショナリから読み込むことができることがわかっています。つまり、ログ構成を JSON または YAML ファイルから読み込むことができます.yml ファイルを例にとります。

最初のステップは、zdy_log.yml ファイルをカスタマイズして、次のように構成することです。

version: 1
disable_existing_loggers: False
# 格式器配置
formatters:
  simple:
    format: '%(asctime)s - %(filename)s[line:%(lineno)d] - %(threadName)s - %(levelname)s: %(message)s'
# 处理器配置
handlers:
  console: # 控制台
    class: logging.StreamHandler
    level: DEBUG
    formatter: simple
    stream: ext://sys.stdout
  info_file_handler: # info级别的日志文件配置
    class: logging.handlers.RotatingFileHandler
    level: INFO
    formatter: simple
    filename: info.log
    maxBytes: 10485760
    backupCount: 20
    encoding: utf8
  error_file_handler: # errors级别的日志文件配置
    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 ]

2 番目のステップは、次のように、コードをエンコードしてロギング機能を実現することです。

import logging.config, yaml
from datetime import datetime

# 加载日志文件
with open('zdy_log.yml', 'r', encoding='utf-8') as f:
    logging.config.dictConfig(yaml.load(f))
# 输出日志
logging.info(f"current datetime {datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S')}")
logging.info(f"current datetime {datetime.strftime(datetime.now(), '%Y/%m/%d %H:%M:%S')}")

3 番目のステップは、実行して結果を表示することです。

もちろん、.conf ファイル形式を使用してログ オプションを構成することもできますが、ここでは辞書構成を使用することをお勧めします。

4. その他

4.1 ロギングモジュールの重要なコンポーネントのまとめ

ロギング ライブラリはモジュラー アプローチを採用し、いくつかの重要なコンポーネントを提供します: ロガー、プロセッサ、フィルター、およびフォーマッター. 関数は次のように説明されています。

  • ロガー: 対応するプロセッサへのログ メッセージの構成と送信を担当する、アプリケーション コードによって直接使用されるインターフェイスを公開します。
  • プロセッサ ハンドラ: ログ レコード (ロガーによって作成された) を指定されたターゲットに送信する責任があります。
  • フォーマッタ フォーマッタ: 最終出力でログ レコードのスタイルを指定する責任があります。
  • フィルター: どのログ レコードを出力するかを決定するためのより細かい機能を提供する責任があります。

ログ イベント情報は、LogRecord インスタンスのロガー、プロセッサ、フォーマッタ、およびフィルタの間で渡されます。

通常は getLogger(name=None) メソッドを使用してロガー オブジェクトを作成します. 名前が None の場合, デフォルトはルート ロガーです. 名前が特定の名前に設定されている場合, この名前でルート ロガーを検索します. ロガーの最も一般的な構成メソッドは、setLevel()、addFilter() および removeFilter()、addHandler() および removeHandler()、およびさまざまなレベルのログ メソッド (critical()/error()/… /debug()) です。 、このログ レベルの構成はグローバルであることに注意してください。

ロガー オブジェクトが作成されたら、addHandler() を使用して 0 個以上のハンドラー オブジェクトをそれ自体に追加します。さまざまな処理シナリオの要件に従って、プロセッサはログ メッセージを特定のハンドラにディスパッチします。さらに、プロセッサはいくつかの構成メソッドも提供します: setLevel()、setFormatter()、addFilter()、および removeFilter() のうち、setLevel() はプロセッサ内でのみ有効です。

フォーマッタ 出力ログ コンテンツを簡単にカスタマイズできるフォーマッタ. 重要なパラメータには、ログ コンテンツのフォーマット、日時のフォーマット、およびフォーマット スタイルが含まれます. デフォルトでは、スタイルの正確性が検証されます. コンストラクタは次のとおりです:

logging.Formatter.__init__(self, fmt=None, datefmt=None, style='%', validate=True)

A filter is a finer-grained control of log output content, which can be used by loggers and processor to implement more complex filtering operations than provided by level. 基本的なフィルター クラスは、ロガー階層イベントの特定のレベルよりも低いレベルのみを許可します。通常は Filter(name='') メソッドを使用してフィルタ オブジェクトを作成します。name が空の文字列で初期化されている場合、すべてのログ イベントが通過します。フィルタが 'ab'、'ab'、'abc' で初期化されている場合、 「abcd」のログ イベントは渡されますが、「acb」、「bc」などは許可されません。フィルタには、次のように addFilter(filter)、removeFilter(filter)、filter(record) の 3 つの一般的に使用されるメソッドがあります。

class Filter(object):
    def __init__(self, name=''):
        .....
    def filter(self, record):
        .....

class Filterer(object):
    def addFilter(self, filter):
        .....
    def removeFilter(self, filter):
        .....

4.2 例外ロギング

ロギングの重要な目的は、プログラム内の問題を迅速に特定して解決することです。ロギング モジュールによって提供されるエラー レベルのログは、次のように exc_info パラメータ オプションを介して例外情報を出力できます。

try:
    doSomeThings()
except Exception as e:
    logging.error('error!!!!', exc_info=True)

もちろん、例外分析のためにプログラムで実行中の例外をより便利に印刷または保存するには、モジュールtracebackを使用して例外情報を追跡する ことをお勧めします。一般的な API は次のとおりです。

  • print_exc(): 端末に例外情報を直接出力します。
  • format_exc(): 情報をファイルに記録するために使用できる例外情報の文字列を返します。

次のように、例外情報をファイルに保存します。

traceback.print_exc(file=open('traceback_ERROR.txt','w+'))

traceback モジュールは、例外情報の追跡において比較的柔軟であり、推奨されます。

【人生は短い、Pythonを学べ!Python モジュール シリーズは継続的に更新され、文書化されます...]

おすすめ

転載: blog.csdn.net/qq_29119581/article/details/128025093