web-dev-qa-db-ja.com

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

これが私がやっていることです

>>> import logging
>>> logging.getLogger().setLevel(logging.INFO)
>>> from datetime import date
>>> date = date.today()
>>> logging.info('date={}', date)
Traceback (most recent call last):
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 846, in emit
    msg = self.format(record)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 723, in format
    return fmt.format(record)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 464, in format
    record.message = record.getMessage()
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 328, in getMessage
    msg = msg % self.args
TypeError: not all arguments converted during string formatting
Logged from file <stdin>, line 1
>>> 

私のpythonバージョンは

$ python --version
Python 2.7.3

どうすれば機能しますか?

35
daydreamer

自分でフォーマットを行うことができます:

logging.info('date={}'.format(date))

Martijn Pietersによって指摘されたように、これは常に文字列フォーマットを実行しますが、ロギングモジュールを使用すると、メッセージが実際にログに記録された場合にのみフォーマットが実行されます。

24
Matt

ロギングモジュールを使用する場合は、新しいスタイルのフォーマットを使用できません。 _%s_の代わりに_{}_を使用します。

_logging.info('date=%s', date)
_

ログモジュールは、古い形式の_%_演算子を使用してログ文字列をフォーマットします。詳細は debug method を参照してください。

本当にstr.format()文字列フォーマットを使用したい場合は、実際に文字列に変換するときに、「late」フォーマットを適用するカスタムオブジェクトの使用を検討してください。

_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)

__ = BraceMessage

logging.info(__('date={}', date))
_

これは Python 3 logging module documentation のアプローチであり、Python 2でも動作します。

49
Martijn Pieters

Martijnの答えは正しいですが、ロギングで新しいスタイルのフォーマットを使用したい場合は、Loggerをサブクラス化することで実現できます。

import logging

class LogRecord(logging.LogRecord):
    def getMessage(self):
        msg = self.msg
        if self.args:
            if isinstance(self.args, dict):
                msg = msg.format(**self.args)
            else:
                msg = msg.format(*self.args)
        return msg

class Logger(logging.Logger):
    def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None):
        rv = LogRecord(name, level, fn, lno, msg, args, exc_info, func)
        if extra is not None:
            for key in extra:
                rv.__dict__[key] = extra[key]
        return rv

次に、ロギングクラスを設定します。

logging.setLoggerClass(Logger)
6
Jeff-Meadows

(Python 3);

logging.info(f'date={date}')
1
yusuf