Issue
I have the following setup:
- root logger to log everywhere
- my programm adds a new handler after startup via an callback (for example a database) with
CallbackHandler
- named logger in my modules do not call into the root-logger
Online Python Compiler <- you need to have main.py selected to Run main.py in there
main.py
import logging
import logging.config
import MyLogger
from MyApp import MyApp
MyLogger.init()
_logger = logging.getLogger() # root
def main() :
_logger.error( "main - root logger" )
app = MyApp() # setup app and attach CallbackHandler to root logger
app.testLog() # call named logger - should call root logger & callback handler
if __name__ == "__main__" :
main()
MyLogger.py
import logging
from logging import LogRecord
import logging.config
import os
from typing import Callable
LOG_PATH = "./logs"
LOGGING_CONFIG : dict = {
"version" : 1 ,
'formatters': {
'simple': {
'format': '%(name)s %(message)s'
},
},
"handlers" : {
"ConsoleHandler" : {
"class" : "logging.StreamHandler" ,
"formatter" : "simple" ,
} ,
} ,
"root" : {
"handlers" : [
"ConsoleHandler" ,
] ,
"level" : "DEBUG" ,
}
}
def init() :
os.makedirs( LOG_PATH , exist_ok = True )
logging.config.dictConfig( LOGGING_CONFIG )
class CallbackHandler( logging.Handler ) :
def __init__( self , level = logging.DEBUG , callback : Callable = None ) :
super().__init__( level )
self._callback = callback
def emit( self , record : LogRecord ) :
if self._callback is not None :
self._callback( record.name + " | " + record.msg )
MyApp.py
import logging
from MyLogger import CallbackHandler
_logger = logging.getLogger( __name__ )
class MyApp :
def __init__( self ) :
rootLogger = logging.getLogger()
rootLogger.addHandler( CallbackHandler( callback = self.myCallback ) )
def myCallback( self , msg : str ) :
print( "CALLBACK: " + msg )
def testLog( self ) :
_logger.error( "MyApp.testLog() - named logger" )
The docs say, named loggers do not inherit the parents handlers. But they propagate their log messages to the parent/root logger - which has handlers attached. However they do not get called with a named logger.
The Problem: CallbackHandler.emit()
is not called
(if I remove the __name__
in MyApp.py: logging.getLogger()
, the root logger gets referenced and the Callback-Handler is called)
How do I :
- initialize the root logger
- later in my program attach a custom Handler to the root logger
- use named loggers in my program
- propagate the the logs from named loggers to the root logger
- such that the logs use the custom root-logger-handler
Solution
How to fix: add the following line to your LOGGING_CONFIG
dict:
"disable_existing_loggers" : False,
The problem is that the child logger is created before the logging gets its configuration and the default behaviour when configuring the logging is to disable existing loggers. Link to the docs (it's the last item in that section).
Answered By - VPfB
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.