Package: logging-plus
Python logging add-onThis package provides some enhancements to standard Python logging:Subclassed Logger allowing customization of logging outputAutomatic indentation depending on call stack levelGeneric logging of function entry and exitStandard filter and handler support is preservedContentInstallationBasic UsageLogging Function Entry and ExitSupressing Entry/Exit Logging in specific Infrastructure ModulesShutdown BehaviorOutputInstallationlogging_plusis available on PyPI.Use pip to install:pipinstalllogging-plusBasic UsageIn order to use this logging add-on, you only need to importlogging_plusin addition tologgingand instantiate a Logger instance fromlogging_plusrather thanlogging.Then your python code will look, for example, as follows:#!/usr/bin/python3importloggingimportlogging_plus#Specific for logging_pluslogger=logging_plus.getLogger('my_logger')#Specific for logging_plushandler=logging.StreamHandler()formatter=logging.Formatter('%(asctime)s%(name)-20s%(levelname)-8s%(message)s')handler.setFormatter(formatter)logger.addHandler(handler)logger.setLevel(logging.DEBUG)The only lines which are specific forlogging_plusare marked.Logging Function Entry and ExitIn order to automatically log entry and exit of functions, the following line needs to be added after the first import oflogging_plus:logging_plus.registerAutoLogEntryExit()This can be deactivated throughlogging_plus.unregisterAutoLogEntryExit()DetailsLogging of function entry and exit is generic and automatic and does not require any coding.
It is implemented by registering a logging function as systemtrace function(sys.settrace(autoLogEntryExit)).ATTENTION:Since this function may also be used by Python debuggers, it may be necessary to skip this statement when debugging.Logging of function entry and exit uses a logger with the name of the module in which the function is located (__name__).Logging of function entry and exit useslogging.DEBUGlevelSupressing Entry/Exit Logging in specific Infrastructure ModulesWhen activated, the mechanism for automatic logging of function entry and exit is active inallfunctions within program control flow.A lot of logging output would, therefore, also be produced by theloggingmodule itself as well as the functions called from there.
Since this is normally not of interest, logging in specific infrastructure modules and subordinate functions is deactivated by default.The following statement activates entry/exit logging for all modules.logging_plus.noInfrastructureLogging=FalseThis affects logging in the following modules as well as any functions in a call stack originating from these modules:logginglogging_plusinspectShutdown BehaviorDuring shutdown of the Python interpreter, a special sequence of actions is followed:Stop main threadClose open file handlersWait for termination of non-daemon threadsExecute registered atexit functionsGarbage collectionProcess terminationAutomatic logging of function entry and exit may cause issues when this would be tried in functions which are run during the shutdown process.
For example, class finalizers__del__(), called during garbage collection, could cause logging issues if a logging file handler is involved, because at this time the shutdown process has already closed any open file handlers.To avoid such issues,logging_plusregisters twoatexitroutines:atexit.register(removeFileHandlers)which removes any file handlers found in any of the active loggersatexit.register(unregisterAutoLogEntryExit)which disables automatic entry/exit loggingThese routines are executed in step 4, above, before garbage collection, with the following consequences in case that objects are not finalized explicitely but during garbage collection:there is no automatic logging of finalizer (__del__()) entry/exit.for explicit logs, there is no file output even for loggers for which a file handler has been registered.NOTE:in case of explicitely finalizing object instances by usingdel myObjto remove all references to an instance, logging within__del__()is done like in any other function.(see also chapter 3.3 inhttps://docs.python.org/3/reference/datamodel.html#index-70)OutputThe following is the logging output from the test module under ./tests with automatic entry/exit logging activated.The file output can be found at ./tests/logTest.log.
The file output for a run with full logging is in ./tests/logTestFull.log2020-12-1312:37:40,048rootDEBUGStart2020-12-1312:37:40,057logTestModDEBUG>>>Entry__init__(/home/pi/dev/py-logging-plus/tests/logTestMod/__init__.py-line7-modulelogTestMod)2020-12-1312:37:40,086logTestModDEBUG## Explicit log: A - Initializing MyClass2020-12-1312:37:40,093logTestModDEBUG<<<Exit__init__:Returnvalue:None2020-12-1312:37:40,095logTestModDEBUG>>>Entry__init__(/home/pi/dev/py-logging-plus/tests/logTestMod/__init__.py-line27-modulelogTestMod)2020-12-1312:37:40,124logTestModDEBUG## Explicit log: F - Initializing subclass MySpecialClass(MyClass)2020-12-1312:37:40,132logTestModDEBUG>>>Entry__init__(/home/pi/dev/py-logging-plus/tests/logTestMod/__init__.py-line7-modulelogTestMod)2020-12-1312:37:40,170logTestModDEBUG## Explicit log: A - Initializing MyClass2020-12-1312:37:40,177logTestModDEBUG<<<Exit__init__:Returnvalue:None2020-12-1312:37:40,179logTestModDEBUG<<<Exit__init__:Returnvalue:None2020-12-1312:37:40,180logTestModDEBUG>>>Entrystatus(/home/pi/dev/py-logging-plus/tests/logTestMod/__init__.py-line13-modulelogTestMod)2020-12-1312:37:40,210logTestModDEBUG## Explicit log: C - getter of MyClass2020-12-1312:37:40,217logTestModDEBUG<<<Exitstatus:Returnvalue:12020-12-1312:37:40,219logTestModDEBUG>>>Entrystatus(/home/pi/dev/py-logging-plus/tests/logTestMod/__init__.py-line18-modulelogTestMod)2020-12-1312:37:40,248logTestModDEBUG## Explicit log: D - setter of MyClass2020-12-1312:37:40,256logTestModDEBUG<<<Exitstatus:Returnvalue:None2020-12-1312:37:40,257logTestModDEBUG>>>EntrydoSomething(/home/pi/dev/py-logging-plus/tests/logTestMod/__init__.py-line23-modulelogTestMod)2020-12-1312:37:40,287logTestModDEBUG## Explicit log: E - MyClass method call2020-12-1312:37:40,295logTestModDEBUG<<<ExitdoSomething:Returnvalue:None2020-12-1312:37:40,296__main__DEBUG>>>Entryfunc(logTest.py-line26-module__main__)2020-12-1312:37:40,327rootDEBUG## Explicit log: 5 ** 2 = 252020-12-1312:37:40,335__main__DEBUG<<<Exitfunc:Returnvalue:252020-12-1312:37:40,337logTestModDEBUG>>>Entry__del__(/home/pi/dev/py-logging-plus/tests/logTestMod/__init__.py-line10-modulelogTestMod)2020-12-1312:37:40,367logTestModDEBUG## Explicit log: B - Finalizing MyClass2020-12-1312:37:40,374logTestModDEBUG<<<Exit__del__:Returnvalue:None2020-12-1312:37:40,377threadingDEBUG>>>Entry_shutdown(/usr/lib/python3.7/threading.py-line1263-modulethreading)2020-12-1312:37:40,378threadingDEBUG>>>Entry_stop(/usr/lib/python3.7/threading.py-line968-modulethreading)2020-12-1312:37:40,380threadingDEBUG<<<Exit_stop:Returnvalue:None2020-12-1312:37:40,381threadingDEBUG>>>Entry_pickSomeNonDaemonThread(/usr/lib/python3.7/threading.py-line1284-modulethreading)2020-12-1312:37:40,383threadingDEBUG>>>Entryenumerate(/usr/lib/python3.7/threading.py-line1244-modulethreading)2020-12-1312:37:40,384threadingDEBUG<<<Exitenumerate:Returnvalue:[<_MainThread(MainThread,stopped547789455376)>]2020-12-1312:37:40,386threadingDEBUG>>>Entrydaemon(/usr/lib/python3.7/threading.py-line1104-modulethreading)2020-12-1312:37:40,387threadingDEBUG<<<Exitdaemon:Returnvalue:False2020-12-1312:37:40,389threadingDEBUG>>>Entryis_alive(/usr/lib/python3.7/threading.py-line1080-modulethreading)2020-12-1312:37:40,391threadingDEBUG<<<Exitis_alive:Returnvalue:False2020-12-1312:37:40,392threadingDEBUG<<<Exit_pickSomeNonDaemonThread:Returnvalue:None2020-12-1312:37:40,393threadingDEBUG<<<Exit_shutdown:Returnvalue:None2020-12-1312:37:40,407logTestModDEBUG## Explicit log: G - Finalizing subclass MySpecialClass(MyClass)2020-12-1312:37:40,408logTestModDEBUG## Explicit log: B - Finalizing MyClassThe last two lines in this example originate from explicit logging calls in finalizers called during garbage collection.
In case of an explicit call ofdel obj, also entry and exit of the finalizers are logged automatically as seen for timestamp 2020-12-13 12:37:40,337.