正确记录unicode&;python 2中的utf-8异常

正确记录unicode&;python 2中的utf-8异常,python,python-2.7,logging,unicode,utf-8,Python,Python 2.7,Logging,Unicode,Utf 8,我试图在Python2.7中记录库中的各种异常。我发现有时异常包含unicode字符串,有时包含utf8 bytestring。我认为logging.exception(e)是记录它们的正确方法,但以下方法似乎不起作用: # encoding: utf-8 import logging try: raise Exception('jörn') except Exception as e: logging.exception(e) try: raise Exception

我试图在Python2.7中记录库中的各种异常。我发现有时异常包含unicode字符串,有时包含utf8 bytestring。我认为
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
$python test.py
错误:root:jörn
回溯(最近一次呼叫最后一次):
文件“test.py”,第4行,在
引发异常(“jörn”)
例外:约恩
回溯(最近一次呼叫最后一次):
文件“/usr/local/cillar/python/2.7.10/Frameworks/python.framework/Versions/2.7/lib/python2.7/logging/_init__.py”,第859行,在emit中
msg=self.format(记录)
文件“/usr/local/cillar/python/2.7.10/Frameworks/python.framework/Versions/2.7/lib/python2.7/logging/_init__.py”,第732行,格式为
返回格式(记录)
文件“/usr/local/cillar/python/2.7.10/Frameworks/python.framework/Versions/2.7/lib/python2.7/logging/_init__.py”,第474行,格式为
s=自记录的百分比__
UnicodeEncodeError:“ascii”编解码器无法对位置1中的字符u'\xf6'进行编码:序号不在范围内(128)
从文件test.py第12行记录
如您所见,utf8异常工作正常,但unicode异常破坏了日志记录,吞并了真正的异常并将其隐藏在
UnicodeEncodeError
后面


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

不是日志记录无法处理unicode,而是异常。_str___方法不支持unicode字符串作为异常参数。当您调用
logging.exception(e)
时,它将执行类似于
logging.exception(str(e))
的操作,这反过来又对异常实例执行类似于
str(self.args)
的操作。这就是错误的来源,您的self.args是一个无法用ascii编码的unicode字符串。 您有两个选项,一个是执行
logging.exception(unicode(e))
,另一个是实现您自己的异常类,该类提供了一个
\uuu str\uuu
方法,可以处理self.args中的unicode对象


第一次测试通过的原因是编辑器将字符串编码为UTF-8,Python看到一个带有编码unicode字符的字符串实例。

事实上,我想我自己终于找到了错误和正确的方法:我似乎一直在使用错误的字符串。您不是要传递异常,而是要传递一条消息:

# 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
这相当于以下内容:

s = '%(levelname)s:%(name)s:%(message)s' % {
   'levelname': 'ERROR',
   'name': 'ROOT',
   'message': Exception(u'jörn')
}
这就是为什么如果
消息
['jörn',u'jörn',Exception('jörn')]
它会工作,而如果它是
Exception(u'jörn'),

当使用
异常
对象尝试转换为unicode时失败,该对象不能正确处理其消息的编码(遗憾的是,在许多库中似乎都是这样)

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

长话短说:
不要使用
logging.exception(e)
而是
logging.exception(“异常发生”)
。它将自动并正确地将格式化的异常附加到日志中。如果您真的想在不使用编码的情况下使用异常消息,那么您可以做的最安全的事情就是
记录。异常(repr(e))

对不起,这并不能真正回答我的问题:
unicode(exception('jörn'))
在到达
记录。异常
之前将失败。我要求的解决方案只适用于任何库以及嵌入其中的开发人员的任何编码。如果默认编码与编辑器编码不匹配,则unicode(Exception('jörn')在解码字符串时会失败。它旨在应用于unicode参数的异常:unicode(Exception(u'jörn'))。没有支持此功能的日志记录工具,因为问题在于无法处理unicode args的Exception类。您可以在logging.Exception周围编写一个包装器,用于检查Exception.args,检查Exception.args中是否存在unicode对象,并对其进行适当处理。
s = '%(levelname)s:%(name)s:%(message)s' % {
   'levelname': 'ERROR',
   'name': 'ROOT',
   'message': 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)
>>> logging.error('jörn')
ERROR:root:jörn
>>> logging.error(u'jörn')
ERROR:root:jörn