I've already seen Using Python logging in multiple modules and similar which recommend using:-
import logging
logger = logging.getLogger(__name__)
in every module. However I'm also using Kivy as a front-end, which has its own logging code. To summarise, Kivy's logging code sets logging.root to its own class.
What this means for me is that the handlers which Kivy assigns aren't inherited by my child modules.
How do I get around this? I've even tried manually assigning handlers as below:-
logging.getLogger(my.module.name).addHandler(handler)
and it still doesn't seem to show up in my console log. Obviously I'd prefer not to do the above once per module, as well.
EDIT
To clarify, I'd like to set up the Kivy app to be able to handle modules which use the 'recommended' log method, without any change to the module code.
Why not use logging.Logger.getChild
? In particular, in your module, call
mylogger = logging.getLogger().getChild(__name__)
If the module is imported after kivy.logger
has been imported, the root logger's name will be kivy
, and thus mylogger
's name will be kivy.module.name
, and more importantly, it will propagate its messages to the root logger, kivy
. On the other hand, if kivy.logger
has not been imported, mylogger
's name will just be module.name
, and thus come with no handlers attached by default.
Example:
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()
And 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()
And app_wo_kivy.py
:
import logging
from test import MyClass
logging.getLogger().addHandler(logging.StreamHandler())
mc = MyClass()
mc.act()
mc.act()
Another approach: In the kivy app, put this first:
from kivy.logger import Logger
import logging
logging.Logger.manager.root = Logger # before importing modules using logging
With this, you should be able to just use the standard way of getting a logger (logger = logging.getLogger(__name__)
). This will work for existing modules (assuming they do not mess with logging
themselves ...). logging.Logger.manager
holds the logger dictionary and determines the hierarchy. Whenever a new logger is created with logging.getLogger
, logging.Manager._fixupParents
gets called, which, when no other parent logger can be found, assigns logging.Logger.manager.root
as parent. Without the above line, this is still the original root logger, hence that will be used.
Now I have no idea whether this might have unintended consequences; but at least logger name parsing should not be compromised, as the root logger's name never gets checked.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With