Использование python 'logging', когда logging.root был переопределен (Kivy)
Я уже видел Использование журналирования Python в нескольких модулях и аналогичных, которые рекомендуют использовать:-
import logging
logger = logging.getLogger(__name__)
в каждом модуле. Однако я также использую Kivy в качестве внешнего интерфейса, который имеет собственный код регистрации. Подводя итог, код регистрации Kivy устанавливает logging.root к своему собственному классу.
Для меня это означает, что обработчики, которые назначает Kivy, не наследуются моими дочерними модулями.
Как мне обойти это? Я даже попытался вручную назначить обработчики, как показано ниже:
logging.getLogger(my.module.name).addHandler(handler)
и это все еще, кажется, не обнаруживается в моем журнале консоли. Очевидно, я бы предпочел не делать выше один раз для каждого модуля.
РЕДАКТИРОВАТЬ
Чтобы уточнить, я хотел бы настроить приложение Kivy, чтобы иметь возможность обрабатывать модули, которые используют "рекомендуемый" метод журнала, без каких-либо изменений в коде модуля.
1 ответ
Почему бы не использовать logging.Logger.getChild
? В частности, в вашем модуле, позвоните
mylogger = logging.getLogger().getChild(__name__)
Если модуль импортируется после 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()
А также 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()
А также app_wo_kivy.py
:
import logging
from test import MyClass
logging.getLogger().addHandler(logging.StreamHandler())
mc = MyClass()
mc.act()
mc.act()
редактировать
Другой подход: поместите это в приложение kivy:
from kivy.logger import Logger
import logging
logging.Logger.manager.root = Logger
При этом вы сможете просто использовать стандартный способ получения логгера (logger = logging.getLogger(__name__)
). Это будет работать для существующих модулей (при условии, что они не связываются с logging
самих себя...). logging.Logger.manager
содержит словарь регистратора и определяет иерархию. Всякий раз, когда новый регистратор создается с logging.getLogger
, logging.Manager._fixupParents
вызывается, который, когда никакой другой родительский регистратор не может быть найден, назначает logging.Logger.manager.root
как родитель. Без приведенной выше строки это все еще оригинальный корневой логгер, поэтому он будет использоваться.
Теперь я понятия не имею, может ли это иметь непредвиденные последствия; но, по крайней мере, синтаксический анализ имени регистратора не должен быть скомпрометирован, так как имя корневого регистратора никогда не проверяется.