子类化 logging.Formatter 更改 logging.Formatter 的默认行为
Subclassing logging.Formatter Changes Default Behavior of logging.Formatter
我向我的记录器添加了两个具有不同格式化程序的处理程序。第一个需要 subclassing logging.Formatter 来进行自定义格式化。对于第二个处理程序,默认格式化程序就足够了。
假设第一个格式化程序只是从消息中删除换行符。以下脚本说明了看似奇怪的行为:
import logging
logger = logging.getLogger(__name__)
class CustomFormatter(logging.Formatter):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def format(self, record):
record.msg = record.msg.strip().replace('\n', ' ')
return super().format(record)
h1 = logging.StreamHandler()
formatter1 = CustomFormatter(fmt=None, datefmt=None)
h1.setFormatter(formatter1)
logger.addHandler(h1)
h2 = logging.StreamHandler()
formatter2 = logging.Formatter(fmt=None, datefmt=None)
h2.setFormatter(formatter2)
logger.addHandler(h2)
logger.warning('string with\nmultiple lines')
这会输出以下内容:
string with multiple lines
string with multiple lines
我期望的是:
string with multiple lines
string with
multiple lines
第二个格式化程序不应该实现 CustomFormatter 的行为,但它确实实现了。当我颠倒处理程序添加到记录器的顺序时,这不会发生。
除非我误解了 subclassing,否则不应通过覆盖 subclass 中的方法来改变基 class 的行为。当我覆盖 logging.Formatter.
以外的 classes 方法时,这似乎不是问题
这是日志记录模块中的错误,还是我遗漏了什么?
这条线是你的失败:
record.msg = record.msg.strip().replace('\n', ' ')
您将擦除后的字符串重新分配给附加到记录器的所有剩余 handlers/formatters 使用的记录。复制记录并有效:
import logging
from copy import copy
logger = logging.getLogger(__name__)
class CustomFormatter(logging.Formatter):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def format(self, record):
record = copy(record)
record.msg = record.msg.strip().replace('\n', ' ')
return super().format(record)
h1 = logging.StreamHandler()
formatter1 = CustomFormatter(fmt=None, datefmt=None)
h1.setFormatter(formatter1)
logger.addHandler(h1)
h2 = logging.StreamHandler()
formatter2 = logging.Formatter(fmt=None, datefmt=None)
h2.setFormatter(formatter2)
logger.addHandler(h2)
logger.warning('string with\nmultiple lines')
产出
string with multiple lines
string with
multiple lines
我向我的记录器添加了两个具有不同格式化程序的处理程序。第一个需要 subclassing logging.Formatter 来进行自定义格式化。对于第二个处理程序,默认格式化程序就足够了。
假设第一个格式化程序只是从消息中删除换行符。以下脚本说明了看似奇怪的行为:
import logging
logger = logging.getLogger(__name__)
class CustomFormatter(logging.Formatter):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def format(self, record):
record.msg = record.msg.strip().replace('\n', ' ')
return super().format(record)
h1 = logging.StreamHandler()
formatter1 = CustomFormatter(fmt=None, datefmt=None)
h1.setFormatter(formatter1)
logger.addHandler(h1)
h2 = logging.StreamHandler()
formatter2 = logging.Formatter(fmt=None, datefmt=None)
h2.setFormatter(formatter2)
logger.addHandler(h2)
logger.warning('string with\nmultiple lines')
这会输出以下内容:
string with multiple lines
string with multiple lines
我期望的是:
string with multiple lines
string with
multiple lines
第二个格式化程序不应该实现 CustomFormatter 的行为,但它确实实现了。当我颠倒处理程序添加到记录器的顺序时,这不会发生。
除非我误解了 subclassing,否则不应通过覆盖 subclass 中的方法来改变基 class 的行为。当我覆盖 logging.Formatter.
以外的 classes 方法时,这似乎不是问题这是日志记录模块中的错误,还是我遗漏了什么?
这条线是你的失败:
record.msg = record.msg.strip().replace('\n', ' ')
您将擦除后的字符串重新分配给附加到记录器的所有剩余 handlers/formatters 使用的记录。复制记录并有效:
import logging
from copy import copy
logger = logging.getLogger(__name__)
class CustomFormatter(logging.Formatter):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def format(self, record):
record = copy(record)
record.msg = record.msg.strip().replace('\n', ' ')
return super().format(record)
h1 = logging.StreamHandler()
formatter1 = CustomFormatter(fmt=None, datefmt=None)
h1.setFormatter(formatter1)
logger.addHandler(h1)
h2 = logging.StreamHandler()
formatter2 = logging.Formatter(fmt=None, datefmt=None)
h2.setFormatter(formatter2)
logger.addHandler(h2)
logger.warning('string with\nmultiple lines')
产出
string with multiple lines
string with
multiple lines