如何在python中对同一个日志处理程序使用不同的格式化程序

如何在python中对同一个日志处理程序使用不同的格式化程序,python,logging,Python,Logging,是否可以使用多个记录器(即logging.getLogger(“base.foo”)和logging.getLogger(“base.bar”))登录到单个目标(即使用一个FileHandler),并为每个记录器使用不同的格式化程序 据我所知,每个句柄只能分配一个格式化程序。也许可以将格式化程序与记录器相关联,而不是与处理程序相关联?可以根据记录.name轻松地分派到不同的格式化程序。以下是概念验证示例代码: import logging class DispatchingFormatter

是否可以使用多个记录器(即
logging.getLogger(“base.foo”)
logging.getLogger(“base.bar”)
)登录到单个目标(即使用一个
FileHandler
),并为每个记录器使用不同的格式化程序


据我所知,每个句柄只能分配一个格式化程序。也许可以将格式化程序与记录器相关联,而不是与处理程序相关联?

可以根据
记录.name
轻松地分派到不同的格式化程序。以下是概念验证示例代码:

import logging


class DispatchingFormatter:

    def __init__(self, formatters, default_formatter):
        self._formatters = formatters
        self._default_formatter = default_formatter

    def format(self, record):
        formatter = self._formatters.get(record.name, self._default_formatter)
        return formatter.format(record)


handler = logging.StreamHandler()
handler.setFormatter(DispatchingFormatter({
        'base.foo': logging.Formatter('FOO: %(message)s'),
        'base.bar': logging.Formatter('BAR: %(message)s'),
    },
    logging.Formatter('%(message)s'),
))
logging.getLogger().addHandler(handler)

logging.getLogger('base.foo').error('Log from foo')
logging.getLogger('base.bar').error('Log from bar')
logging.getLogger('base.baz').error('Log from baz')

另一种方法是手动打开文件,并使用不同的格式化程序从中创建两个流处理程序。

对优秀的Denis解决方案进行了小小的修改

基于层次结构:

名称
可能是一个周期分隔的层次值,如
foo.bar.baz
(例如,它也可以是普通的
foo
)。 在层次结构列表中较低的记录器是 伐木工人在名单中排名靠前。例如,给定一个具有名称的记录器 在
foo
中,名为
foo.bar
foo.bar.baz
foo.bam
的记录器是
foo
的所有后代

例如,对于某些记录器,此级别也将应用于子记录器。这就是为什么您可能希望您的格式化程序将用于记录器,它也是子记录器。例如,
'one.two'
格式化程序也应应用于
'one.two.three'
记录器(如果没有设置
'one.two.three'
的格式化程序)。以下是执行此任务的DispatchingFormatter版本(Python 3代码):

例如:

handler = logging.StreamHandler()
handler.setFormatter(DispatchingFormatter({
        'one': logging.Formatter('%(message)s -> one'),
        'one.two': logging.Formatter('%(message)s -> one.two'),
    },
    logging.Formatter('%(message)s -> <default>'),
))
logging.getLogger().addHandler(handler)

print('Logger used -> formatter used:')
logging.getLogger('one').error('one')
logging.getLogger('one.two').error('one.two')
logging.getLogger('one.two.three').error('one.two.three')  # parent formatter 'one.two' will be used here
logging.getLogger('other').error('other')

# OUTPUT:
# Logger used -> formatter used:
# one -> one
# one.two -> one.two
# one.two.three -> one.two
# other -> <default>
handler=logging.StreamHandler()
handler.setFormatter(DispatchingFormatter({
“一”:logging.Formatter(“%(消息)s->one”),
'one.two':logging.Formatter('%(message)s->one.two'),
},
logging.Formatter('%(消息)s->'),
))
logging.getLogger().addHandler(handler)
打印('使用记录器->使用格式化程序:')
logging.getLogger('one')。错误('one'))
logging.getLogger('one.two')。错误('one.two'))
logging.getLogger('one.two.three')。error('one.two.three')#这里将使用父格式化程序'one.two'
logging.getLogger('other')。错误('other'))
#输出:
#使用记录器->使用格式化程序:
#一->一
#一.二->一.二
#一。二。三->一。二
#其他->

这是你的工作吗?不同的日志级别输出格式和不同的日志目标、文件与标准输出(以及每个目标的不同级别):


优秀、优雅的解决方案。对于记录,这也基于record.levelno工作,因此格式化程序字典键可以是
logging.DEBUG
而不是
'base.foo'
您知道如何对filehandler执行此操作吗?同样的方法?@Henry,是的,只需将第二段代码“StreamHandler()”更改为“FileHandler(filename)”。格式化程序本身可以应用于任何类型的处理程序。
handler = logging.StreamHandler()
handler.setFormatter(DispatchingFormatter({
        'one': logging.Formatter('%(message)s -> one'),
        'one.two': logging.Formatter('%(message)s -> one.two'),
    },
    logging.Formatter('%(message)s -> <default>'),
))
logging.getLogger().addHandler(handler)

print('Logger used -> formatter used:')
logging.getLogger('one').error('one')
logging.getLogger('one.two').error('one.two')
logging.getLogger('one.two.three').error('one.two.three')  # parent formatter 'one.two' will be used here
logging.getLogger('other').error('other')

# OUTPUT:
# Logger used -> formatter used:
# one -> one
# one.two -> one.two
# one.two.three -> one.two
# other -> <default>
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.DEBUG)

    format_for_stdout = logging.Formatter('%(message)s')
    format_for_logfile = logging.Formatter('%(asctime)s: %(name)s: %(levelname)s: %(message)s')

    handler_logfile = logging.FileHandler('my_awesome_logs.log')
    handler_logfile.setLevel(logging.DEBUG)
    handler_logfile.setFormatter(format_for_logfile)

    handler_stdout = logging.StreamHandler()
    handler_stdout.setLevel(logging.INFO)
    handler_stdout.setFormatter(format_for_stdout)

    logger.addHandler(handler_logfile)
    logger.addHandler(handler_stdout)

    logging.addLevelName(logging.INFO, logging.getLevelName(logging.INFO))
    logging.addLevelName(logging.ERROR, logging.getLevelName(logging.ERROR))