3

私は Python で Web アプリケーション フレームワークのプロトタイプを作成しています (主に教育目的のため)。長い間欲しかった 1 つの機能、つまりルートごとのログ レベルに行き詰まっています。

この機能の目的は、診断を実行している特定のエントリ ポイントを特定することです。たとえば、発信者が をヒットしたときに何が起こっているかを追跡したいと考えていPOST /sessions/loginます。ここで、この URL のリクエスト処理によってヒットしたコードのログ エントリを 100% 取得したいと考えています。これは、サードパーティのアプリケーションで行われることを含め、すべてを意味します。

: 架空のアプリケーションには と の 2 つのルートが/sessions/loginあり/sessions/infoます。両方のリクエスト ハンドラーが、userslogger を使用する package 内の同じデータベース コードにヒットしますmyapp.users.db。のリクエスト処理は/sessions/loginloggermyapp.users.dbでログ メッセージを出力する必要がありますが、 のリクエスト処理は/sessions/infoすべきではありません。

問題は、これが Python のロギング ライブラリにうまく適合しないことです。このライブラリはロギングを階層的に分解し、階層化に適しています (たとえば、アプリケーション レイヤによるログ レベルの制御)。

私が本当に欲しいのは、コンテキスト依存のログ レベルです。頭に浮かぶ自然な実装はlogger.getEffectiveLevel()、スレッド ローカルのログ レベルを返すようにするものです (リクエスト URL がデバッグの対象である場合、デバッグ ミドルウェアは条件付きでログ レベルをデバッグに下げます)。しかし、私は Python ドキュメントのロギング フローを見ていますが、さまざまな種類の構成フックのいずれかを使用してこれを実装する方法がわかりません。


質問: Python でコンテキスト依存のログ レベルをどのように実装しますか?


更新:部分的な解決策が見つかりました。

context = threading.local()

class ContextualLogger(logging.Logger):
    def getEffectiveLevel(self):
        global context
        level = getattr(context, 'log_level', logging.NOTSET)
        if level == logging.NOTSET:
            level = super(ContextualLogger, self).getEffectiveLevel()
        return level

logging.setLoggerClass(ContextualLogger)

ただし、これはルート ロガーでは機能しません。何か案は?


更新: 関数にモンキー パッチを適用することもできgetEffectiveLevel()ます。

context = threading.local()

# Monkey patch "getEffectiveLevel()" to consult the current setting in the
# `context.log_level` thread-local storage.  If that value is present, use
# it to override the current value; else, compute the level using the usual
# infrastructure.
default_getEffectiveLevel = logging.Logger.getEffectiveLevel
def patched_getEffectiveLevel(self):
    level = getattr(context, 'log_level', logging.NOTSET)
    if level == logging.NOTSET:
        level = default_getEffectiveLevel(self)
    return level
logging.Logger.getEffectiveLevel = patched_getEffectiveLevel

現在、これはルートロガーでも機能します。この関数にモンキー パッチを適用することに少し抵抗があることは認めざるを得ませんが、通常のインフラストラクチャにフォールバックするため、実際には見た目ほど汚れていません。

4

1 に答える 1

0

コンテキストを使用してイベントをドロップする (メソッドから戻ることによって) か、イベントをログに記録できるようにする (メソッドからlogging.Filter戻ることによって) ロガー (またはハンドラー) にアタッチされている を使用することをお勧めします。FalsefilterTruefilter

あなたのユースケースには正確ではありませんが、この投稿では、スレッドローカルコンテキストでのフィルターの使用について説明しました。

于 2013-07-08T09:13:54.687 に答える