在重新定义 logging.root 时使用 python 'logging' (Kivy)

Ng *_*-Ee 5 python logging kivy

我已经看到在多个模块中使用 Python 日志记录和类似的推荐使用:-

import logging
logger = logging.getLogger(__name__)
Run Code Online (Sandbox Code Playgroud)

在每个模块中。但是我也使用 Kivy 作为前端,它有自己的日志代码。总而言之,Kivy 的日志代码将 logging.root 设置为它自己的类。

这对我来说意味着 Kivy 分配的处理程序不会被我的子模块继承。

我该如何解决这个问题?我什至尝试过手动分配处理程序如下:-

logging.getLogger(my.module.name).addHandler(handler)
Run Code Online (Sandbox Code Playgroud)

它似乎仍然没有出现在我的控制台日志中。显然,我也不希望每个模块都执行上述操作。

编辑

澄清一下,我想将 Kivy 应用程序设置为能够处理使用“推荐”日志方法的模块,而无需对模块代码进行任何更改。

zee*_*eez 5

为什么不使用logging.Logger.getChild?特别是,在您的模块中,调用

mylogger = logging.getLogger().getChild(__name__)
Run Code Online (Sandbox Code Playgroud)

如果在导入模块之后再导入模块kivy.logger,则根记录器的名称将为kivy,因此mylogger的名称将为kivy.module.name,更重要的是,它将把其消息传播到根记录器kivy。另一方面,如果kivy.logger尚未导入,mylogger则 的名称将只是module.name,因此默认情况下不附加任何处理程序。

例子: test.py

import logging

class MyClass(object):
    def __init__(self):
        super(MyClass, self).__init__()
        self.logger = logging.getLogger().getChild(__name__)
        self.value = 0

    def act(self):
        self.value += .5
        self.logger.warning("MyClass.act: value: {}".format(self.value))

if __name__ == '__main__':
    mc = MyClass()
    mc.act()
    mc.act()
    mc.act()
Run Code Online (Sandbox Code Playgroud)

app.py

from kivy.app import App
from kivy.logger import Logger
from kivy.clock import Clock
from kivy.properties import ObjectProperty, NumericProperty
from kivy.uix.widget import Widget
from test import MyClass

class AnApp(App):
    mc = ObjectProperty()
    value = NumericProperty(0)
    def action_c(self, dt=0):
        self.value += 1
        self.mc.act()
        Logger.info("action_c: value now {}".format(self.value))
        
    def build(self):
        self.mc = MyClass()
        Clock.schedule_interval(self.action_c, 1)
        return Widget()
AnApp().run()
Run Code Online (Sandbox Code Playgroud)

app_wo_kivy.py

import logging
from test import MyClass
logging.getLogger().addHandler(logging.StreamHandler())

mc = MyClass()
mc.act()
mc.act()
Run Code Online (Sandbox Code Playgroud)

编辑

另一种方法:在 kivy 应用程序中,将其放在第一位:

from kivy.logger import Logger
import logging
logging.Logger.manager.root = Logger # before importing modules using logging
Run Code Online (Sandbox Code Playgroud)

有了这个,您应该能够使用获取记录器的标准方法(logger = logging.getLogger(__name__))。这适用于现有模块(假设它们不会弄乱logging自己......)。logging.Logger.manager保存记录器字典并确定层次结构。每当使用 创建新记录器 时logging.getLoggerlogging.Manager._fixupParents都会调用 ,当找不到其他父记录器时,它将指定logging.Logger.manager.root 为父记录器。如果没有上面的行,这仍然是原始的根记录器,因此将使用它。

现在我不知道这是否会产生意想不到的后果;但至少记录器名称解析不应受到损害,因为根记录器的名称永远不会被检查。