如何在Python日志中使用UTF-8?
我正在尝试使用Python的日志记录工具把一个UTF-8编码的字符串写入文件。举个简单的例子:
import logging
def logging_test():
handler = logging.FileHandler("/home/ted/logfile.txt", "w",
encoding = "UTF-8")
formatter = logging.Formatter("%(message)s")
handler.setFormatter(formatter)
root_logger = logging.getLogger()
root_logger.addHandler(handler)
root_logger.setLevel(logging.INFO)
# This is an o with a hat on it.
byte_string = '\xc3\xb4'
unicode_string = unicode("\xc3\xb4", "utf-8")
print "printed unicode object: %s" % unicode_string
# Explode
root_logger.info(unicode_string)
if __name__ == "__main__":
logging_test()
在调用logging.info()的时候,这个代码会报出UnicodeDecodeError的错误。
从底层来看,Python的日志记录工具是用codecs这个工具来打开日志文件的,并且把“UTF-8”作为编码格式传进去。这本身没有问题,但它试图把字节字符串写入文件,而不是写入Unicode对象,这就出错了。简单来说,Python实际上是这样做的:
file_handler.write(unicode_string.encode("UTF-8"))
但它应该是这样做的:
file_handler.write(unicode_string)
这是Python的一个bug吗,还是我在胡思乱想?顺便说一下,我用的是标准的Python 2.6版本。
9 个回答
14
我来得有点晚,但我刚看到这个帖子,它让我很容易就设置了utf-8格式的日志记录。
或者这里是代码:
root_logger= logging.getLogger()
root_logger.setLevel(logging.DEBUG) # or whatever
handler = logging.FileHandler('test.log', 'w', 'utf-8') # or whatever
formatter = logging.Formatter('%(name)s %(message)s') # or whatever
handler.setFormatter(formatter) # Pass handler as a parameter, not assign
root_logger.addHandler(handler)
35
代码如下:
raise Exception(u'щ')
导致了:
File "/usr/lib/python2.7/logging/__init__.py", line 467, in format
s = self._fmt % record.__dict__
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
这个问题出现的原因是,格式字符串是字节字符串,而一些格式字符串的参数是包含非ASCII字符的unicode字符串:
>>> "%(message)s" % {'message': Exception(u'\u0449')}
*** UnicodeEncodeError: 'ascii' codec can't encode character u'\u0449' in position 0: ordinal not in range(128)
将格式字符串改为unicode格式可以解决这个问题:
>>> u"%(message)s" % {'message': Exception(u'\u0449')}
u'\u0449'
所以,在你的日志配置中,确保所有的格式字符串都是unicode格式:
'formatters': {
'simple': {
'format': u'%(asctime)-s %(levelname)s [%(name)s]: %(message)s',
'datefmt': '%Y-%m-%d %H:%M:%S',
},
...
并且修改默认的logging
格式化器,使其使用unicode格式字符串:
logging._defaultFormatter = logging.Formatter(u"%(message)s")
16
检查一下你是否安装了最新的 Python 2.6,因为自从 2.6 发布以来,发现并修复了一些 Unicode 的错误。例如,在我的 Ubuntu Jaunty 系统上,我运行了你复制粘贴的脚本,只去掉了日志文件名中的 '/home/ted/' 前缀。结果(从终端窗口复制粘贴过来的):
vinay@eta-jaunty:~/projects/scratch$ python --version Python 2.6.2 vinay@eta-jaunty:~/projects/scratch$ python utest.py printed unicode object: ô vinay@eta-jaunty:~/projects/scratch$ cat logfile.txt ô vinay@eta-jaunty:~/projects/scratch$
在 Windows 系统上:
C:\temp>python --version Python 2.6.2 C:\temp>python utest.py printed unicode object: ô
还有文件的内容:
这也可能解释了为什么 Lennart Regebro 也无法重现这个问题。