如何在 Python 中将所有记录的消息编码为 utf-8
How to encode all logged messages as utf-8 in Python
我有一个小记录器功能,returns 可能有两个处理程序同时记录到 RotatingFileHandler 和 sys.stdout。
import os, logging, sys
from logging.handlers import RotatingFileHandler
from config import *
def get_logger(filename, log_level_stdout=logging.WARNING, log_level_file=logging.INFO, echo=True):
logger = logging.getLogger(__name__)
if not os.path.exists(PATH + '/Logs'):
os.mkdir(PATH + '/Logs')
logger.setLevel(logging.DEBUG)
if echo:
prn_handler = logging.StreamHandler(sys.stdout)
prn_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s'))
prn_handler.setLevel(log_level_stdout)
logger.addHandler(prn_handler)
file_handler = RotatingFileHandler(PATH + '/Logs/' + filename, maxBytes=1048576, backupCount=3)
file_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s'))
file_handler.setLevel(log_level_file)
logger.addHandler(file_handler)
return logger
这在一般情况下工作正常,但某些正在记录的字符串似乎是在 cp1252 中编码的,并且在尝试通过记录器函数将它们打印到标准输出时抛出(非致命)错误。应该注意的是,在错误消息中可以打印出完全相同的字符。将它们记录到文件中也不会导致任何问题。只有控制台 - sys.stdout - 会引发此错误。
--- Logging error ---
Traceback (most recent call last):
File "C:\Program Files\Python38\lib\logging\__init__.py", line 1084, in emit
stream.write(msg + self.terminator)
File "C:\Program Files\Python38\lib\encodings\cp1252.py", line 19, in encode
return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode character '\u1ecd' in position 65: character maps to <undefined>
Call stack:
File "script.py", line 147, in <module>
logger.info(f"F-String with a name in it: '{name}'.")
Message: "F-String with a name in it: 'Heimstọð'."
Arguments: ()
解决此问题的方法是在调用记录器函数的代码中将每条消息编码为 utf8,如下所示:
logger.info((f"F-String with a name in it: '{name}'.").encode('utf8'))
但是我觉得这样既不优雅也不高效。
还应该注意的是,文件的日志记录工作得很好,我已经尝试在 Windows 的系统变量中将 PYTHONIOENCODING 设置为 utf-8,但没有任何明显的效果。
更新:
原来我是个笨蛋。仅仅因为在控制台中打印了错误消息并不意味着打印到控制台是错误的原因。我正在研究这里向我提出的另一个问题的答案,过了一会儿我意识到我对函数的“if echo”部分所做的任何事情都不会对结果产生任何影响。最后一次检查是注释掉整个块,但我仍然遇到错误。就在那时我意识到问题实际上是由于在写入文件时没有强制执行 UTF8 引起的。按照@michael-ruth 的建议,将简单的 kwarg encoding='utf-8' 添加到 RotatingFileHandler 为我解决了这个问题。
P.S。我不确定如何处理这种情况,因为虽然这个答案解决了我的问题,但这并不是我真正要求的或问题建议的内容,因为我最初误解了根本原因。我仍然会将其作为解决方案进行检查,并对两个答案都投赞成票。我还会编辑这个问题,以免误导未来的读者相信它会回答这个问题,但实际上并没有。
在实例化处理程序时设置编码,而不是显式编码消息。
file_handler = RotatingFileHandler(
PATH + '/Logs/' + filename,
maxBytes=1048576,
backupCount=3,
encoding='utf-8'
)
help(RotatingFileHandler)
是你最好的朋友。
Help on class RotatingFileHandler in module logging.handlers:
class RotatingFileHandler(BaseRotatingHandler)
| RotatingFileHandler(filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False)
你能检查一下 sys.stdout
(sys.stdout.encoding
) 的编码吗?
如果不是 'utf-8'
,this answer 可能有助于重新配置编码。
我有一个小记录器功能,returns 可能有两个处理程序同时记录到 RotatingFileHandler 和 sys.stdout。
import os, logging, sys
from logging.handlers import RotatingFileHandler
from config import *
def get_logger(filename, log_level_stdout=logging.WARNING, log_level_file=logging.INFO, echo=True):
logger = logging.getLogger(__name__)
if not os.path.exists(PATH + '/Logs'):
os.mkdir(PATH + '/Logs')
logger.setLevel(logging.DEBUG)
if echo:
prn_handler = logging.StreamHandler(sys.stdout)
prn_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s'))
prn_handler.setLevel(log_level_stdout)
logger.addHandler(prn_handler)
file_handler = RotatingFileHandler(PATH + '/Logs/' + filename, maxBytes=1048576, backupCount=3)
file_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s'))
file_handler.setLevel(log_level_file)
logger.addHandler(file_handler)
return logger
这在一般情况下工作正常,但某些正在记录的字符串似乎是在 cp1252 中编码的,并且在尝试通过记录器函数将它们打印到标准输出时抛出(非致命)错误。应该注意的是,在错误消息中可以打印出完全相同的字符。将它们记录到文件中也不会导致任何问题。只有控制台 - sys.stdout - 会引发此错误。
--- Logging error ---
Traceback (most recent call last):
File "C:\Program Files\Python38\lib\logging\__init__.py", line 1084, in emit
stream.write(msg + self.terminator)
File "C:\Program Files\Python38\lib\encodings\cp1252.py", line 19, in encode
return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode character '\u1ecd' in position 65: character maps to <undefined>
Call stack:
File "script.py", line 147, in <module>
logger.info(f"F-String with a name in it: '{name}'.")
Message: "F-String with a name in it: 'Heimstọð'."
Arguments: ()
解决此问题的方法是在调用记录器函数的代码中将每条消息编码为 utf8,如下所示:
logger.info((f"F-String with a name in it: '{name}'.").encode('utf8'))
但是我觉得这样既不优雅也不高效。 还应该注意的是,文件的日志记录工作得很好,我已经尝试在 Windows 的系统变量中将 PYTHONIOENCODING 设置为 utf-8,但没有任何明显的效果。
更新: 原来我是个笨蛋。仅仅因为在控制台中打印了错误消息并不意味着打印到控制台是错误的原因。我正在研究这里向我提出的另一个问题的答案,过了一会儿我意识到我对函数的“if echo”部分所做的任何事情都不会对结果产生任何影响。最后一次检查是注释掉整个块,但我仍然遇到错误。就在那时我意识到问题实际上是由于在写入文件时没有强制执行 UTF8 引起的。按照@michael-ruth 的建议,将简单的 kwarg encoding='utf-8' 添加到 RotatingFileHandler 为我解决了这个问题。 P.S。我不确定如何处理这种情况,因为虽然这个答案解决了我的问题,但这并不是我真正要求的或问题建议的内容,因为我最初误解了根本原因。我仍然会将其作为解决方案进行检查,并对两个答案都投赞成票。我还会编辑这个问题,以免误导未来的读者相信它会回答这个问题,但实际上并没有。
在实例化处理程序时设置编码,而不是显式编码消息。
file_handler = RotatingFileHandler(
PATH + '/Logs/' + filename,
maxBytes=1048576,
backupCount=3,
encoding='utf-8'
)
help(RotatingFileHandler)
是你最好的朋友。
Help on class RotatingFileHandler in module logging.handlers: class RotatingFileHandler(BaseRotatingHandler) | RotatingFileHandler(filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False)
你能检查一下 sys.stdout
(sys.stdout.encoding
) 的编码吗?
如果不是 'utf-8'
,this answer 可能有助于重新配置编码。