I'm wondering where to configure and initialize stuff related with logging module?
For example I writing some class and I want to log some info while method will be executed. Should I configure logging in init or above class on the top of module:
# LOGGING STUFF <--- Should be here ?
class SomeClass:
def __init__(self):
# class stuff
# LOGGING STUFF <--- Or should be here ?
def some_method(self):
# method stuff
# LOGGING SOME INFO
def some_method2(self):
# method stuff
# LOGGING SOME INFO
What is the best practice ?
The logging package serves two purposes, assisting the author to produce logs and assisting the user to consume logs. You might perform both those roles but thinking about them separately will help you write clean, understandable code.
Author should instantiate the logger at the right level:
Package logger should go in the packages __init__
file. Note the use of __name__
, it'll resolve to SomePackage
:
import logging
package_logger = logging.getLogger(__name__)
Module logger at the top of your module. Note the power of __name__
! Here it'll resolve to SomePackage.SomeModule
.
import logging
module_logger = logging.getLogger(__name__)
Class level logger could go at the top of the class definition. Note the awesome power of __name__
enhanced with getLogger and __qualname__
! The loggers name will be SomePackage.SomeModule.SomeClass
. Also, not the underscore in _class_logger
to signal that it is for internal use.:
class SomeClass:
_class_logger = logging.getLogger(__name__).getChild(__qualname__)
Instance logger in the classes __init__
. Use ID to produce a unique identifier. Note the stupend... you get the idea. Logger name will be SomePackage.SomeModule.SomeClass.<large_unique_number>
:
class SomeClass:
def __init__(self):
self._instance_logger = logging.getLogger(__name__).getChild(self.__class__.__name__).getChild(str(id(self)))
The names may not suit your application. For instance you may want an instance logger that is derived from one of it's instantiating args. However, you should still aim to get a grip on your logger at the right level.
It's the Users job to configure handlers. Generally, the author will have ensured that no handlers will be active by default. logging.basicConfig
will dump all log records of level warning and above to stderr.
import SomePackage
import logging
logging.basicConfig()
Remember you can use logging.getLogger() to access the same loggers that the author defined.
from SomePackage import SomeModule
import logging
"""
module_logger debug to a file. Will capture all
child loggers as well if used i.e class_logger and
instance_logger
"""
h = logging.FileHandler('debug')
h.setLevel('DEBUG')
SomeModule.module_logger.addHandler(h)
"""
class_logger warning to stderr. Will capture all child loggers
as well if used i.e instance_logger Note: No need to import
SomeClass to access it's logger as Logger keeps track of them in
a dictionary. Typically the prefered approach if your not
actually using the class.
"""
h = logging.StreamHandler()
getLogger('SomePackage.SomeModule.SomeClass').addHandler(h)
If you're debugging your own modules by calling them directly, you probably have a def main()
and they should go in there. This ensures a package user won't get unexpected log files or consoles messages.
If using loggers at multiple levels, deriving from existing ones is more pythonic.
module_logger = logging.getLogger(__name__)
class SomeClass:
_class_logger = module_logger.getChild(__qualname__)
def __init__(self):
self._instance_logger = self._class_logger.getChild(str(id(self)))
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