如何在 Python 中将所有记录的消息编码为 utf-8

Mid*_*ght 7 python logging encoding stdout utf-8

我有一个小记录器函数,它可能返回两个处理程序以同时记录到 RotatingFileHandler 和 sys.stdout。

\n
import os, logging, sys\nfrom logging.handlers import RotatingFileHandler\nfrom config import *\n\ndef get_logger(filename, log_level_stdout=logging.WARNING, log_level_file=logging.INFO, echo=True):\n    logger = logging.getLogger(__name__)\n    if not os.path.exists(PATH + '/Logs'):\n        os.mkdir(PATH + '/Logs')\n\n    logger.setLevel(logging.DEBUG)\n\n    if echo:\n        prn_handler = logging.StreamHandler(sys.stdout)\n        prn_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s'))\n        prn_handler.setLevel(log_level_stdout)\n        logger.addHandler(prn_handler)\n\n    file_handler = RotatingFileHandler(PATH + '/Logs/' + filename, maxBytes=1048576, backupCount=3)\n    file_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s'))\n    file_handler.setLevel(log_level_file)\n    logger.addHandler(file_handler)\n    return logger\n
Run Code Online (Sandbox Code Playgroud)\n

一般来说,这工作正常,但某些正在记录的字符串似乎是在 cp1252 中编码的,并且在尝试通过记录器函数将它们打印到标准输出时抛出(非致命)错误。应该注意的是,在错误消息中可以打印完全相同的字符。将它们记录到文件中也不会导致任何问题。只有控制台 - sys.stdout - 会抛出此错误。

\n
--- Logging error ---\nTraceback (most recent call last):\n  File "C:\\Program Files\\Python38\\lib\\logging\\__init__.py", line 1084, in emit\n    stream.write(msg + self.terminator)\n  File "C:\\Program Files\\Python38\\lib\\encodings\\cp1252.py", line 19, in encode\n    return codecs.charmap_encode(input,self.errors,encoding_table)[0]\nUnicodeEncodeError: 'charmap' codec can't encode character '\\u1ecd' in position 65: character maps to <undefined>\nCall stack:\n  File "script.py", line 147, in <module>\n    logger.info(f"F-String with a name in it: '{name}'.")\nMessage: "F-String with a name in it: 'Heimst\xe1\xbb\x8d\xc3\xb0'."\nArguments: ()\n
Run Code Online (Sandbox Code Playgroud)\n

解决这个问题的方法是在调用记录器函数的代码中将每条消息编码为 utf8,如下所示:

\n
logger.info((f"F-String with a name in it: '{name}'.").encode('utf8'))\n
Run Code Online (Sandbox Code Playgroud)\n

然而我觉得这既不优雅也不高效。 \n还应该注意的是,文件的日志记录工作得很好,我已经尝试在 Windows 系统变量中将 PYTHONIOENCODING 设置为 utf-8 ,但没有任何明显的效果。

\n

更新:\n事实证明我很愚蠢。仅仅因为在控制台中打印错误消息并不意味着打印到控制台是错误的原因。我正在研究这里向我建议的另一个问题的答案,过了一会儿我意识到我对函数的“if echo”部分所做的任何操作都对结果没有任何影响。最后一次检查是注释掉整个块,但我仍然收到错误。那时我意识到问题实际上是由于写入文件时未强制执行 UTF8 引起的。按照 @michael-ruth 的建议,将简单的 kwarg encoding='utf-8' 添加到 RotatingFileHandler 解决了我的问题。\nP.S. 我不确定如何处理这种情况,因为虽然这个答案解决了我的问题,但这并不是我真正想要的或问题所建议的,因为我最初误解了根本原因。我仍然会将其作为解决方案进行检查并对两个答案都投赞成票。我还将编辑这个问题,以免误导未来的读者相信它会回答这个问题,而实际上并没有。

\n

Mic*_*uth 6

在实例化处理程序时设置编码,而不是显式对消息进行编码。

file_handler = RotatingFileHandler(
    PATH + '/Logs/' + filename, 
    maxBytes=1048576, 
    backupCount=3,
    encoding='utf-8'
)
Run Code Online (Sandbox Code Playgroud)

help(RotatingFileHandler)是你最好的朋友。

有关模块logging.handlers中的RotatingFileHandler类的帮助:

类 RotatingFileHandler(BaseRotatingHandler)
 | RotatingFileHandler(文件名,模式='a',maxBytes=0,backupCount=0,编码=无,延迟=False)