web-dev-qa-db-ja.com

CPythonロギングでは、ロガーごとに1つのロックではなく、ハンドラごとにロックを使用するのはなぜですか?

独自のロギングライブラリを開発しているときに、CPythonの標準 logging モジュールのソースコードを研究しました。

その機能の1つは、ハンドラーがthread-safeであることです。行が破損するリスクなしに、複数のスレッドからファイルにログを書き込むことができます。

loggingモジュールのソースを詳しく調べて、スレッドの安全性を確保するために各ハンドラーが独自のLock各ロギング呼び出しで取得および解放すること。あなたはこれを見ることができます ここ

ハンドラーの呼び出しをグローバルに囲む単一のロックを使用するのではなく、これを行う意味は何ですか?たとえば、 callHandlers() 関数でロックを取得しませんか?

主な利点は2つあります。

  • ロックが1つだけ取得および解放されるため、パフォーマンスが向上します
  • ログに記録されたメッセージがすべてのハンドラーで同じ順序で表示されることを確認します(たとえば、2つのハンドラーH1とH2、およびそれぞれM1とM2を記録する2つのスレッドを考えると、シーケンスH1.handle(M1) -> H1.handle(M2) -> H2.handle(M2) -> H2.handle(M1)が発生する可能性を回避できます)。

私の個人用ロギングライブラリでは、ロガーごとに次のようなことを安全に実行できますか?

with self.lock:
    for handler in self.handlers:
        handler.handle(message)  # No lock used in "handle()"

それとも何か他を見落としているのでしょうか?

3
Delgan

特にSocketHandler/SMTPHandler/HTTPHandlerなどの別のマシンやサードパーティのサービスロギングハンドラーをリモートロギングする場合、ロギングハンドラーが遅くなる可能性があります。ロギングライブラリ全体が単一のロックを使用している場合、遅いハンドラー(例:例外時に管理者への電子メール)へのロギングは、速いハンドラー(例:ローカルファイルのログ)へのロギングをブロックします。

さらに、一部のロギングハンドラーはロックをまったく必要としない場合があります。たとえば、外部ロギングでは、処理をシリアル化して暗黙的にではなく、タイムスタンプを使用してログを並べ替えることがあります。

4
Lie Ryan