91

Python 2.7.3 のロギング機能を使用しています。この Python バージョンのドキュメントは次のように述べています

logging パッケージは、str.format() や string.Template などの新しいフォーマット オプションよりも前のものです。これらの新しい書式設定オプションがサポートされています...

私は中括弧を使った「新しい」形式が好きです。だから私は次のようなことをしようとしています:

 log = logging.getLogger("some.logger")
 log.debug("format this message {0}", 1)

そしてエラーを取得します:

TypeError: 文字列のフォーマット中にすべての引数が変換されるわけではありません

ここで何が恋しいですか?

PS 使いたくない

log.debug("format this message {0}".format(1))

この場合、メッセージはロガー レベルに関係なく常にフォーマットされるためです。

4

10 に答える 10

40

編集:この回答とは異なりStyleAdapter、@ Dunesの回答のアプローチを見てください。ロガーのメソッド (debug()、info()、error() など) を呼び出すときに、ボイラープレートなしで代替の書式設定スタイルを使用できます。


ドキュメントから —代替書式スタイルの使用:

ロギング呼び出し (logger.debug()、logger.info() など) は、実際のロギング メッセージ自体の位置パラメーターのみを取り、実際のロギング呼び出しを処理する方法のオプションを決定するためだけに使用されるキーワード パラメーター (exc_info キーワード パラメーターなど) を使用します。トレースバック情報をログに記録する必要があることを示すか、追加のコンテキスト情報をログに追加することを示す extra キーワード パラメータ)。そのため、str.format() または string.Template 構文を使用してロギング呼び出しを直接行うことはできません。ロギング パッケージは内部的に %-formatting を使用してフォーマット文字列と可変引数をマージするためです。既存のコードに存在するすべてのロギング呼び出しは % 形式の文字列を使用するため、下位互換性を維持しながらこれを変更することはありません。

と:

ただし、{}- および $- 形式を使用して個々のログ メッセージを作成する方法があります。メッセージに対して、任意のオブジェクトをメッセージ フォーマット文字列として使用できること、およびロギング パッケージがそのオブジェクトに対して str() を呼び出して実際のフォーマット文字列を取得することを思い出してください。

これをコピーしてwhereverモジュールに貼り付けます:

class BraceMessage(object):
    def __init__(self, fmt, *args, **kwargs):
        self.fmt = fmt
        self.args = args
        self.kwargs = kwargs

    def __str__(self):
        return self.fmt.format(*self.args, **self.kwargs)

それで:

from wherever import BraceMessage as __

log.debug(__('Message with {0} {name}', 2, name='placeholders'))

注: 実際のフォーマットは、必要になるまで延期されます。たとえば、DEBUG メッセージがログに記録されない場合、フォーマットはまったく実行されません。

于 2012-10-30T00:39:53.197 に答える
25

これは、ログが printf スタイルの書式設定のみを使用していることがわかったときの問題に対する私の解決策でした。ロギング呼び出しを同じままにすることができます - のような特別な構文はありませんlog.info(__("val is {}", "x"))。コードに必要な変更は、ロガーをStyleAdapter.

from inspect import getargspec

class BraceMessage(object):
    def __init__(self, fmt, args, kwargs):
        self.fmt = fmt
        self.args = args
        self.kwargs = kwargs

    def __str__(self):
        return str(self.fmt).format(*self.args, **self.kwargs)

class StyleAdapter(logging.LoggerAdapter):
    def __init__(self, logger):
        self.logger = logger

    def log(self, level, msg, *args, **kwargs):
        if self.isEnabledFor(level):
            msg, log_kwargs = self.process(msg, kwargs)
            self.logger._log(level, BraceMessage(msg, args, kwargs), (), 
                    **log_kwargs)

    def process(self, msg, kwargs):
        return msg, {key: kwargs[key] 
                for key in getargspec(self.logger._log).args[1:] if key in kwargs}

使用法は次のとおりです。

log = StyleAdapter(logging.getLogger(__name__))
log.info("a log message using {type} substitution", type="brace")

中括弧置換に使用されるキーワードにlevelmsgargsexc_infoextraまたはが含まれる場合、この実装には問題があることに注意してくださいstack_info。これらは、 のlogメソッドで使用される引数名ですLogger。これらの名前のいずれかが必要な場合は、変更してこれらの名前を除外するか、呼び出しからprocess削除します。さらに、この実装では、Logger 用のスペルミスのあるキーワード (例: ) も黙って無視します。log_kwargs_logectra

于 2014-07-10T18:01:15.660 に答える
24

簡単な解決策は、優れたlogbookモジュールを使用することです

import logbook
import sys

logbook.StreamHandler(sys.stdout).push_application()
logbook.debug('Format this message {k}', k=1)

またはより完全な:

>>> import logbook
>>> import sys
>>> logbook.StreamHandler(sys.stdout).push_application()
>>> log = logbook.Logger('MyLog')
>>> log.debug('Format this message {k}', k=1)
[2017-05-06 21:46:52.578329] DEBUG: MyLog: Format this message 1
于 2012-10-30T00:11:42.743 に答える
0

pR0Ps ' と同様のソリューションで、新しいフォーマットが有効になっているインスタンスで(回答ではなく) ラップgetMessageすることでLogRecordラップします。makeRecordhandleLogger

def getLogger(name):
    log = logging.getLogger(name)
    def Logger_makeRecordWrapper(name, level, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None):
        self = log
        record = logging.Logger.makeRecord(self, name, level, fn, lno, msg, args, exc_info, func, sinfo)
        def LogRecord_getMessageNewStyleFormatting():
            self = record
            msg = str(self.msg)
            if self.args:
                msg = msg.format(*self.args)
            return msg
        record.getMessage = LogRecord_getMessageNewStyleFormatting
        return record
    log.makeRecord = Logger_makeRecordWrapper
    return log

これを Python 3.5.3 でテストしました。

于 2020-07-05T14:45:40.500 に答える