python - 在 python 2 中正确记录 unicode 和 utf-8 异常

标签 python python-2.7 logging unicode utf-8

我正在尝试从 python 2.7 中的库中记录各种异常。我发现有时异常包含一个 unicode 字符串,有时包含一个 utf8 字节串。我认为 logging.exception(e) 是记录它们的正确方法,但以下似乎不起作用:

# encoding: utf-8
import logging
try:
    raise Exception('jörn')
except Exception as e:
    logging.exception(e)

try:
    raise Exception(u'jörn')
except Exception as e:
    logging.exception(e)

将其保存到文件中并运行它会产生以下结果:

$ python test.py
ERROR:root:jörn
Traceback (most recent call last):
  File "test.py", line 4, in <module>
    raise Exception('jörn')
Exception: jörn
Traceback (most recent call last):
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 859, in emit
    msg = self.format(record)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 732, in format
    return fmt.format(record)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 474, in format
    s = self._fmt % record.__dict__
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 1: ordinal not in range(128)
Logged from file test.py, line 12

因此,正如您所见,utf8 异常工作正常,但 unicode 异常破坏了日志记录,吞没了真正的异常并将其隐藏在 UnicodeEncodeError 之后。

是否有一些不会破坏我的代码的异常的标准日志记录工具?我错过了什么?

最佳答案

其实,我想我终于自己找到了错误和正确的方法:我似乎使用了logging.exception('msg')一直错您不是要传递异常,而是要传递一条消息:

# encoding: utf-8
import logging
try:
    raise Exception('jörn')
except Exception as e:
    logging.exception('exception occurred')

try:
    raise Exception(u'jörn')
except Exception as e:
    logging.exception('exception occurred')

正确运行上面的代码会记录异常:

$ python test.py
ERROR:root:exception occurred
Traceback (most recent call last):
  File "test.py", line 4, in <module>
    raise Exception('jörn')
Exception: jörn
ERROR:root:exception occurred
Traceback (most recent call last):
  File "test.py", line 10, in <module>
    raise Exception(u'jörn')
Exception: j\xf6rn

logging.exception(e) 似乎失败的原因是它将异常 e 向上传递到 logging.Formatter.format()它作为 record.message 变量到达的地方仍然是一个 Exception 对象。

然后在第 474 行发生以下情况:

s = self._fmt % record.__dict__

相当于以下内容:

s = '%(levelname)s:%(name)s:%(message)s' % {
   'levelname': 'ERROR',
   'name': 'ROOT',
   'message': Exception(u'jörn')
}

事实证明,这就是为什么如果 message['jörn', u'jörn', Exception('jörn')] 之一它会工作,而如果不是它是 Exception(u'jörn'):

>>> 'foo %s' % 'jörn'
'foo j\xc3\xb6rn'
>>> 'foo %s' % u'jörn'
u'foo j\xf6rn'
>>> 'foo %s' % Exception('jörn')
'foo j\xc3\xb6rn'
>>> 'foo %s' % Exception(u'jörn')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 1: ordinal not in range(128)

如您所见,unicode 字符串会发生自动向上转换,这就是以下工作的原因:

>>> logging.error('jörn')
ERROR:root:jörn
>>> logging.error(u'jörn')
ERROR:root:jörn

尝试使用未正确处理其消息编码的 Exception 对象时,这种到 unicode 的转换失败(遗憾的是,在很多库中似乎都是这种情况)。

logging.exception(msg) 调用似乎正确地使用了 repr() 来格式化日志记录的异常,并在其前面加上您的 msg。因此,如果您没有犯错并将异常传递给 logging.exception,它将正确记录它。

长话短说:

不要使用 logging.exception(e) 而要使用 logging.exception('exception occurred')。它会自动并正确地将格式化的异常附加到您的日志中。如果您真的想在不采用某种编码的情况下使用异常消息,最安全的做法是 logging.exception(repr(e))

关于python - 在 python 2 中正确记录 unicode 和 utf-8 异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31137568/

相关文章:

Python lxml(对象化): Xpath troubles

python 2.7 设置和列表删除时间复杂度

ruby-on-rails-3 - 在 Heroku 日志中查找特定字符串

java - logback 没有记录到文件

c# - 记录 Windows 服务

python - 如何收集文件中关键字之间的所有数据行 - 从换行符开始+结束

python - 组合 2 个不同元组的值的最佳方法

python - 为什么 subprocess.call 仅当参数在数组中分隔时才适用于任何字符串?

python - xlsxwriter 创建的损坏的 xlsx 文件

python - 如何将 csv 文件的第二列转换为 float 列表?