2012-10-11 17 views
18

Oto co robięPython: Rejestrowanie TypeError: nie wszystkie argumenty przekształcone w ciąg formatowania

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

moją wersję Pythona

$ python --version 
Python 2.7.3 

Jak zrobić to działa?

Odpowiedz

10

Można wykonać formatowanie siebie:

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

Jak wskazano przez Martijn Pieters, to będzie zawsze uruchamiane formatowanie ciąg, podczas korzystania z modułu rejestrowania spowodowałoby formatowanie być wykonywane tylko wtedy, gdy wiadomość jest faktycznie zalogowany.

+15

wiem, że wykonując formatowanie siebie, tracą przewagę szybkości oferowanej przez pozwalając moduł rejestrowania zrobi to za Ciebie * tylko wtedy, gdy wiadomość jest faktycznie zalogowany *. Innymi słowy, jeśli użyjesz funkcji 'debug()', ale poziom rejestrowania nie obejmuje poziomu DEBUG, nie ponosisz kary za operację formatowania ciągu. Różnica prędkości może być znacząca, jeśli masz dużo komunikatów diagnostycznych. –

32

Nie można używać formatowania w nowym stylu podczas korzystania z modułu rejestrowania; użyj %s zamiast {}.

logging.info('date=%s', date) 

Moduł logowania używa starym stylu % operatorowi sformatować ciąg dziennika. Więcej szczegółów znajduje się w debug method.

Jeśli naprawdę chcesz używać str.format() formatowanie ciąg, należy rozważyć użycie niestandardowych obiektów, które mają zastosowanie formatowania „późno”, podczas gdy w rzeczywistości konwertowane na ciąg znaków:

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

To podejście Python 3 logging module documentation proposes, i zdarza pracować również na Pythonie 2.

6

Odpowiedź Martijna jest prawidłowa, ale jeśli wolisz używać nowego formatowania stylu z rejestrowaniem, można to osiągnąć przez podklasy 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 

Następnie wystarczy ustawić klasę rejestrowania:

logging.setLoggerClass(Logger) 
+0

Lub nawet (przynajmniej na Pythonie 3.5) używaj tylko LogRecord z 'logging.setLogRecordFactory (LogRecord)' –

Powiązane problemy