How to implement logging for an imported module?

Peter Otten __peter__ at web.de
Mon Mar 15 05:46:06 EDT 2021


On 15/03/2021 09:47, Robert Latest via Python-list wrote:
> Richard Damon wrote:
>> On 3/8/21 4:16 AM, Robert Latest via Python-list wrote:
>>> Joseph L. Casale wrote:
>>>>> I couldn't find any information on how to implement logging in a library
>>>>> that doesn't know the name of the application that uses it. How is that
>>>>> done?
>>>> That's not how it works, it is the opposite. You need to know the name of
>>>> its logger, and since you imported it, you do.
>>> [much snipping]
>>>
>>>> Last word of advice, don't fight it by hacking up or patching (somehow?),
>>>> it will simply not work right for any other case even slightly different
>>>> than the one you somehow beat into submission.
>>> I didn't waht to hack the logging system, it's just that I wasn't sure of
>>> its design principles. I had hoped that if I set up a logger (including
>>> levels and formatter) in my main app, the loggers in the imported modules
>>> would somwhow automagically follow suit. Now I understand that for each
>>> imported module I must import its logger, too, and decide how to deal with
>>> its messages.
>>>
>>>
>> Each instance of the logger inherents from a 'parent' logger, except for the
>> top level logger which has the name None (as in the singleton of NoneType),
>> and unless told otherwise will inherit it properties from its parent.
>>
>> Thus, if you get the root logger with logging.getLogger() you can set
>> properties there, and unless a child logger has specifical been told not to
>> inherit or has been specifically given a different value.
>>
>> General convention is that modules will use their name as the name of their
>> logger, as that is generally unique.
>>
> 
> I must admit I'm still struggling with the very basics of logging. I don't
> understand the behavior of the code samples below at all, see comments.
> It seems that logging.debug() et al have some side effects that are required
> to get a logger to notice its level in the first place.
> 
> 
> # Example 1:
> # Why does the logger "mylog" require
> # a call to the root logger in order to work?

Because logging.debug() implicitly calls basicConfig() if there are no 
handlers yet for the root logger. You should always configure your 
handlers explicitly, usually by a call to logging.basicConfig().

> 
> import logging

# - set the root logger's level
# - add a handler to the root logger
logging.basicConfig(level=logging.DEBUG)

> mylog = logging.getLogger('foo')

In most cases I want the same log-level for all loggers, so I'd omit the 
line below.

> mylog.setLevel(logging.DEBUG)
> 
> mylog.debug('1 mylog.debug()')   # prints nothing
> logging.debug('2 logging.debug()') # prints nothing
> mylog.debug('3 mylog.debug()')   # works
> 
> 
> # Example 2:
> # Why do I have to call 'logging.debug' before the root
> # logger works?
> 
> import logging
> 
> mylog = logging.getLogger() # now mylog is the root logger
> mylog.setLevel(logging.DEBUG) # setting level of root logger
> 
> mylog.debug('1 mylog.debug()')   # prints nothing, why?
> logging.debug('2 logging.debug()') # works
> mylog.debug('3 mylog.debug()')   # works
> 




More information about the Python-list mailing list