以下の内容はhttps://nikkie-ftnext.hatenablog.com/entry/structlog-integration-with-stdlib-logging-example-httpxより取得しました。


HTTPX を例に、標準ライブラリ logging によるログを structlog で出力するには

はじめに

七尾百合子さん、お誕生日 193日目 おめでとうございます! nikkieです。

標準ライブラリの logging を使うことが多い私ですが、awesome なロギングライブラリの1つである structlog を使ったらどうなるのか、手を動かしてみました。

loguru 篇はこちら:

目次

HTTPX の Guide「logging」

HTTP クライアントライブラリの1つ、HTTPX1
ドキュメントからロギングの Guide です。

import logging

logging.basicConfig(
    format="%(levelname)s [%(asctime)s] %(name)s - %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S",
    level=logging.DEBUG
)

HTTPX は logging.getLogger("httpx").info() のようにロギングを実装しています。
Guide では logging.basicConfig() でルートロガーをDEBUGレベルに設定し、httpxロガー(やhttpcoreロガー)からの propagate を使ってロギングしています。

では structlog を使った場合はどう実装するのでしょうか?

structlog

vinta/awesome-python の Logging より2

structlog - Structured logging made easy.

integration についてのドキュメントから

www.structlog.org

structlog の ProcessorFormatter を利用する

標準ライブラリの logging との integration のドキュメントには、いくつか実装例が載っていました。
logging.getLogger("httpx").info() のようなライブラリのロギングもサポートする例は「Rendering using structlog-based formatters within logging」と理解しました。

ここでやりたいことは2つあります。

  • structlog によるロギングの設定(HTTPXのログを出すケースでは必須ではないですが、取り組むことにしました)
  • logging によるロギングの設定

見なよ...

structlog 側の設定はshared_processorsの末尾にstructlog.stdlib.ProcessorFormatter.wrap_for_formatterを追加。

On the structlog side, the processor chain must be configured to end with structlog.stdlib.ProcessorFormatter.wrap_for_formatter() as the renderer.
It converts the processed event dictionary into something that ProcessorFormatter understands.

logging 向けにstructlog.stdlib.ProcessorFormatterインスタンスを作成。

  • processors 引数では、structlog が追加するログレコード属性を削除し、コンソール出力する指定
  • foreign_pre_chain 引数に shared_processors を指定

The ProcessorFormatter has a foreign_pre_chain argument which is responsible for adding properties to events from the standard library

このフォーマッタをルートロガーのハンドラに設定しています。

ルートロガーのハンドラにフィルタを設定して、httpxロガーによるログだけにできています(コメントアウト部分)

ドキュメント確認メモ

shared_processorsの要素について、ドキュメントを確認します。

そもそも structlog の Processor とは

The true power of structlog lies in its combinable log processors. A log processor is a regular callable (略)

structlog.stdlib.add_logger_name
https://www.structlog.org/en/stable/api.html#structlog.stdlib.add_logger_name

Add the logger name to the event dict.

structlog.stdlib.add_log_level
https://www.structlog.org/en/stable/api.html#structlog.stdlib.add_log_level

Add the log level to the event dict under the level key.

structlog.stdlib.PositionalArgumentsFormatter
https://www.structlog.org/en/stable/api.html#structlog.stdlib.PositionalArgumentsFormatter

Apply stdlib-like string formatting to the event key.

structlog.processors.TimeStamper
https://www.structlog.org/en/stable/api.html#structlog.processors.TimeStamper

Add a timestamp to event_dict.

structlog.processors.StackInfoRenderer
https://www.structlog.org/en/stable/api.html#structlog.processors.StackInfoRenderer

Add stack information with key stack if stack_info is True.

structlog.processors.format_exc_info
https://www.structlog.org/en/stable/api.html#structlog.processors.format_exc_info

Replace an exc_info field with an exception string field using Python’s built-in traceback formatting.

structlog.processors.UnicodeDecoder
https://www.structlog.org/en/stable/api.html#structlog.processors.UnicodeDecoder

Decode byte string values in event_dict.

structlog.processors.CallsiteParameterAdder
https://www.structlog.org/en/stable/api.html#structlog.processors.CallsiteParameterAdder

Adds parameters of the callsite that an event dictionary originated from to the event dictionary.

processor を組合せるというのは私も結構好きで、過去に他の OSS で見た実装を思い出しました。

宿題事項としては、filter_by_levelがよく分かっていないかも
https://www.structlog.org/en/stable/api.html#structlog.stdlib.filter_by_level
先頭に入れたのですが、例外送出。なんでだろ〜

終わりに

HTTPX に仕込まれた標準ライブラリ logging のロガーのログを structlog で出力してみました。
structlog.configureにもstructlog.stdlib.ProcessorFormatterにも共通の processor たちを設定します

  • structlog.configure: shared_processors の末尾に structlog.stdlib.ProcessorFormatter.wrap_for_formatter を追加
  • structlog.stdlib.ProcessorFormatter: foreign_pre_chain 引数に shared_processors を指定
    • 標準ライブラリ logging のフォーマッタとして設定

小さな processor がいくつも登場して新規事項の量に圧倒されていますが、structlog のロガーも logging のロガーも共通の設定をして実現するというのが印象的でした。


  1. requests よりも推していて、いくつか記事も書いています
  2. 作者は別の話題で取り上げたこともある hynek 氏です



以上の内容はhttps://nikkie-ftnext.hatenablog.com/entry/structlog-integration-with-stdlib-logging-example-httpxより取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14