记录异常

如果你想记录异常,你可以并且应该使用 logging.exception(msg) 方法:

>>> import logging
>>> logging.basicConfig()
>>> try:
...     raise Exception('foo')
... except:
...     logging.exception('bar')
...
ERROR:root:bar
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
Exception: foo

不要将异常作为参数传递:

由于 logging.exception(msg) 期望一个 msg arg,将异常传递给日志记录调用是一个常见的陷阱,如下所示:

>>> try:
...     raise Exception('foo')
... except Exception as e:
...     logging.exception(e)
...
ERROR:root:foo
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
Exception: foo

虽然起初看起来好像这是正确的事情,但由于异常和各种编码如何在日志记录模块中协同工作,实际上存在问题:

>>> try:
...     raise Exception(u'föö')
... except Exception as e:
...     logging.exception(e)
...
Traceback (most recent call last):
  File "/.../python2.7/logging/__init__.py", line 861, in emit
    msg = self.format(record)
  File "/.../python2.7/logging/__init__.py", line 734, in format
    return fmt.format(record)
  File "/.../python2.7/logging/__init__.py", line 469, in format
    s = self._fmt % record.__dict__
UnicodeEncodeError: 'ascii' codec can't encode characters in position 1-2: ordinal not in range(128)
Logged from file <stdin>, line 4

试图记录包含 unicode 字符的异常,这种方式将失败 。它将隐藏原始异常的堆栈跟踪,方法是使用在 logging.exception(e) 调用格式化期间引发的新异常覆盖它。

显然,在你自己的代码中,你可能会注意到异常中的编码。但是,第三方库可能以不同的方式处理此问题。

正确用法:

如果不是异常,你只是传递一条消息让 python 做它的魔力,它会起作用:

>>> try:
...     raise Exception(u'föö')
... except Exception as e:
...     logging.exception('bar')
...
ERROR:root:bar
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
Exception: f\xf6\xf6

正如你所看到的,在这种情况下我们实际上并没有使用 e,对 logging.exception(...) 的调用会神奇地格式化最近的异常。

使用非 ERROR 日志级别记录异常

如果要使用另一个日志级别而不是 ERROR 来记录异常,可以使用默认记录器的 exc_info 参数:

logging.debug('exception occurred', exc_info=1)
logging.info('exception occurred', exc_info=1)
logging.warning('exception occurred', exc_info=1)

访问例外的消息

请注意,那里的库可能会抛出异常消息,如任何 unicode 或(如果幸运的话,utf-8)字节串。如果你真的需要访问异常的文本,唯一可行的方法就是使用 repr(e)%r 字符串格式:

>>> try:
...     raise Exception(u'föö')
... except Exception as e:
...     logging.exception('received this exception: %r' % e)
...
ERROR:root:received this exception: Exception(u'f\xf6\xf6',)
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
Exception: f\xf6\xf6