While reading Python code, I usually see one of those two conventions:
def something(logger):
logger.info('doing something')
or:
LOGGER = logging.getLogger(__NAME__)
def something():
LOGGER.info('doing something')
Does the former have any advantages, i.e. being thread safe while the other isn't? Or is it purely a stylistic difference?
Use a global logger if you want a fixed logger:
LOGGER = logging.getLogger('stuff.do')
# logger depends on what we are
def do_stuff(operation: Callable):
LOGGER.info('will do stuff')
operation()
LOGGER.info('just did stuff')
do_stuff(add_things)
do_stuff(query_things)
This is commonly used when logging shared operations for diagnostic purposes. For example, a web server would log creating and destroying threads.
Use a logger parameter if you want to change the logger:
# logger depends on what we do
def do_stuff(operation: Callable, logger: Logger):
logger.info('will do stuff')
operation()
logger.info('just did stuff')
do_stuff(add_things, logging.getLogger('add'))
do_stuff(query_things, logging.getLogger('query'))
This is commonly used when logging configurable operations for accounting purposes. For example, a web server would log different kinds of requests and their results.
Which one to use depends solely on whether the choice of logger depends on global or local data.
If the logger choice can be decided globally, doing so avoids polluting function signatures with logger passing. This improves modularity, as you can add/remove logging
calls without changing other code. When using logging to find bugs, you likely want to add logging to dubious code sections and remove it from proven ones.
If the logger choice depends on local state, passing loggers or their names around is often the only option. When using logging to document what is going on, you sometimes want to add new kinds of operation subjects later on.
There are no runtime or safety advantages to using either approach, other than avoiding the operations to pass things around. The logging
module is designed to be thread-safe:
Thread Safety
The logging module is intended to be thread-safe without any special work needing to be done by its clients. It achieves this though using threading locks; there is one lock to serialize access to the module’s shared data, and each handler also creates a lock to serialize access to its underlying I/O.
It is entirely equivalent to create a new "instance" of the same logger, or to create an alias for the same logger:
>>> a = logging.getLogger('demo')
>>> b = a
>>> c = logging.getLogger('demo')
>>> a is b is c
True
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