python 2.7.3。 このためのドキュメントPython version say :
ロギングパッケージは、str.format()やstring.Templateなどの新しいフォーマットオプションよりも前のものです。これらの新しいフォーマットオプションがサポートされています...
中括弧で囲まれた「新しい」形式が好きです。だから私は次のようなことをしようとしています:
log = logging.getLogger("some.logger")
log.debug("format this message {0}", 1)
エラーが発生します:
TypeError:文字列のフォーマット中にすべての引数が変換されるわけではありません
ここで何が恋しいですか?
追伸使いたくない
log.debug("format this message {0}".format(1))
この場合、メッセージはロガーレベルに関係なく常にフォーマットされるためです。
EDIT:@ -Dunesの回答の StyleAdapter
アプローチ この回答とは異なり、ロガーのメソッド(debug()、info()、error()など)を呼び出している間に、定型文なしで代替のフォーマットスタイルを使用できます。
ドキュメントから— 代替書式スタイルの使用 :
ロギング呼び出し(logger.debug()、logger.info()など)は、実際のロギングメッセージ自体の位置パラメーターのみを取り、実際のロギング呼び出しを処理する方法のオプションを決定するためにのみ使用されるキーワードパラメーター(exc_infoキーワードパラメーターなど)トレースバック情報をログに記録する必要があることを示すため、または追加のコンテキスト情報をログに追加するために追加のキーワードパラメータを追加するため)。したがって、内部的にロギングパッケージは%-formattingを使用してフォーマット文字列と変数引数をマージするため、str.format()またはstring.Template構文を使用してロギング呼び出しを直接行うことはできません。既存のコードにあるすべてのロギング呼び出しは%形式の文字列を使用するため、後方互換性を維持しながらこれを変更することはありません。
そして:
ただし、{}-および$-フォーマットを使用して個々のログメッセージを作成する方法があります。メッセージの場合、任意のオブジェクトをメッセージ形式文字列として使用でき、ロギングパッケージはそのオブジェクトで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メッセージがログに記録されない場合、フォーマットはまったく実行されません。
Dunesの回答に記載されているキーワードの問題がない別のオプションを次に示します。位置(_{0}
_)引数のみを処理でき、キーワード(_{foo}
_)引数は処理できません。また、フォーマットに2つの呼び出しを必要としません(アンダースコアを使用)。 str
をサブクラス化するick-factorがあります:
_class BraceString(str):
def __mod__(self, other):
return self.format(*other)
def __str__(self):
return self
class StyleAdapter(logging.LoggerAdapter):
def __init__(self, logger, extra=None):
super(StyleAdapter, self).__init__(logger, extra)
def process(self, msg, kwargs):
if kwargs.pop('style', "%") == "{": # optional
msg = BraceString(msg)
return msg, kwargs
_
次のように使用します。
_logger = StyleAdapter(logging.getLogger(__name__))
logger.info("knights:{0}", "ni", style="{")
logger.info("knights:{}", "shrubbery", style="{")
_
もちろん、_# optional
_で示されたチェックを削除して、アダプターを経由するすべてのメッセージに新しい形式のフォーマットを使用させることができます。
この回答を数年後に読んでいる人への注意:Python 3.2からは、 Formatter
オブジェクトを使用したスタイルパラメーター :
ロギング(3.2以降)では、これら2つの追加のフォーマットスタイルのサポートが改善されています。 Formatterクラスは、
style
という名前の追加のオプションのキーワードパラメータを取るように拡張されました。デフォルトは_'%'
_ですが、他の2つのフォーマットスタイルに対応する他の可能な値は_'{'
_および_'$'
_です。下位互換性はデフォルトで維持されます(予想どおり)が、スタイルパラメーターを明示的に指定することにより、str.format()
または _string.Template
_ 。
ドキュメントにはサンプルlogging.Formatter('{asctime} {name} {levelname:8s} {message}', style='{')
が用意されています
この場合、logger
を新しい形式で呼び出すことはできません。つまり、以下はまだ機能しません:
_logger.info("knights:{say}", say="ni") # Doesn't work!
logger.info("knights:{0}", "ni") # Doesn't work either
_
これは、ロギングが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} substiution", type="brace")
ブレース置換に使用されるキーワードにlevel
、msg
、args
、exc_info
、extra
が含まれる場合、この実装に問題があることに注意してくださいstack_info
。これらは、log
のLogger
メソッドで使用される引数名です。これらの名前のいずれかが必要な場合は、process
を変更してこれらの名前を除外するか、log_kwargs
呼び出しから_log
を削除してください。さらに注意すべき点として、この実装は、ロガー向けのスペルミスのキーワード(たとえば、ectra
)も黙って無視します。
より簡単な解決策は、 excellent logbook
module を使用することです
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
他の回答が言及しているように、ブレーススタイルのフォーマット Python 3.2 で導入)は、実際のログメッセージではなくフォーマット文字列でのみ使用されます。
Python 3.5の時点で、中括弧スタイルのフォーマットを使用してメッセージを記録する良い方法はありません。
ただし、Pythonのほとんどのものと同様に、ナイスではない方法があります。
次の例では、logging
モジュールにモンキーパッチを適用して、処理するすべてのログレコードに対して新しい形式のフォーマットを使用するロガーを返す_get_logger
_関数を作成します。
_import functools
import logging
import types
def _get_message(record):
"""Replacement for logging.LogRecord.getMessage
that uses the new-style string formatting for
it's messages"""
msg = str(record.msg)
args = record.args
if args:
if not isinstance(args, Tuple):
args = (args,)
msg = msg.format(*args)
return msg
def _handle_wrap(fcn):
"""Wrap the handle function to replace the passed in
record's getMessage function before calling handle"""
@functools.wraps(fcn)
def handle(record):
record.getMessage = types.MethodType(_get_message, record)
return fcn(record)
return handle
def get_logger(name=None):
"""Get a logger instance that uses new-style string formatting"""
log = logging.getLogger(name)
if not hasattr(log, "_newstyle"):
log.handle = _handle_wrap(log.handle)
log._newstyle = True
return log
_
使用法:
_>>> log = get_logger()
>>> log.warning("{!r}", log)
<logging.RootLogger object at 0x4985a4d3987b>
_
ノート:
get_logger
_関数によって作成された特定のロガーにのみ影響します。logging.getLogger()
呼び出しから再度アクセスされた場合、新しいスタイルのフォーマットが引き続き適用されますlogging.LogRecord
_オブジェクトに保存されるのを止めません(特定の場合に便利です)logging
モジュールのソースコード を見ると、Python 2.6 when _str.format
_ が導入されました(ただし、Python 3.5)でのみテストされました。logging.setLogRecordFactory
in Python 3.2+:
import collections
import logging
class _LogRecord(logging.LogRecord):
def getMessage(self):
msg = str(self.msg)
if self.args:
if isinstance(self.args, collections.Mapping):
msg = msg.format(**self.args)
else:
msg = msg.format(*self.args)
return msg
logging.setLogRecordFactory(_LogRecord)
以下に、実際に機能するシンプルなものを示します。
debug_logger: logging.Logger = logging.getLogger("app.debug")
def mydebuglog(msg: str, *args, **kwargs):
if debug_logger.isEnabledFor(logging.DEBUG):
debug_logger.debug(msg.format(*args, **kwargs))
次に:
mydebuglog("hello {} {val}", "Python", val="World")
ColorFormatter という名前のカスタムフォーマッターを作成し、次のような問題を処理します。
class ColorFormatter(logging.Formatter):
def format(self, record):
# previous stuff, copy from logging.py…
try: # Allow {} style
message = record.getMessage() # printf
except TypeError:
message = record.msg.format(*record.args)
# later stuff…
これにより、さまざまなライブラリとの互換性が維持されます。欠点は、ストリングのフォーマットを2回試行する可能性があるため、おそらくパフォーマンスが低下することです。