When is logging.getLogger(__name__) needed?

Loris Bennett loris.bennett at fu-berlin.de
Wed Apr 5 09:06:22 EDT 2023


"Loris Bennett" <loris.bennett at fu-berlin.de> writes:

> dn <PythonList at DancesWithMice.info> writes:
>
>> On 01/04/2023 02.01, Loris Bennett wrote:
>>> Hi,
>>> In my top level program file, main.py, I have
>>>    def main_function():
>>>        parser = argparse.ArgumentParser(description="my prog")
>>>        ...
>>>        args = parser.parse_args()
>>>        config = configparser.ConfigParser()
>>>        if args.config_file is None:
>>>            config_file = DEFAULT_CONFIG_FILE
>>>        else:
>>>            config_file = args.config_file
>>>        config.read(config_file)
>>>        logging.config.fileConfig(fname=config_file)
>>>        logger = logging.getLogger(__name__)
>>>        do_some_stuff()
>>>               my_class_instance = myprog.MyClass()
>>>    def do_some_stuff():
>>>        logger.info("Doing stuff")
>>> This does not work, because 'logger' is not known in the function
>>> 'do_some_stuff'.
>>> However, if in 'my_prog/my_class.py' I have
>>>    class MyClass:
>>>        def __init__(self):
>>>            logger.debug("created instance of MyClass")
>>> this 'just works'.
>>> I can add
>>>    logger = logging.getLogger(__name__)
>>> to 'do_some_stuff', but why is this necessary in this case but not
>>> in
>>> the class?
>>> Or should I be doing this entirely differently?
>>
>> Yes: differently.
>>
>> To complement @Peter's response, two items for consideration:
>>
>> 1 once main_function() has completed, have it return logger and other
>> such values/constructs. The target-identifiers on the LHS of the 
>> function-call will thus be within the global scope.
>>
>> 2 if the purposes of main_function() are condensed-down to a few
>> (English, or ..., language) phrases, the word "and" will feature, eg
>> - configure env according to cmdLN args,
>> - establish log(s),
>> - do_some_stuff(),  ** AND **
>> - instantiate MyClass.
>>
>> If these (and do_some_stuff(), like MyClass' methods) were split into
>> separate functions* might you find it easier to see them as separate 
>> sub-solutions? Each sub-solution would be able to contribute to the
>> whole - the earlier ones as creating (outputting) a description, 
>> constraint, or basis; which becomes input to a later function/method.
>
> So if I want to modify the logging via the command line I might have the
> following:
>
> ---------------------------------------------------------------------
>
> #!/usr/bin/env python3
>
> import argparse
> import logging
>
>
> def get_logger(log_level):
>     """Get global logger"""
>
>     logger = logging.getLogger('example')
>     logger.setLevel(log_level)
>     ch = logging.StreamHandler()
>     formatter = logging.Formatter('%(levelname)s - %(message)s')
>     ch.setFormatter(formatter)
>     logger.addHandler(ch)
>
>     return logger
>
>
> def do_stuff():
>     """Do some stuff"""
>
> #    logger.info("Doing stuff!")

Looks like I just need 

  logger = logging.getLogger('example)
  logger.info("Doing stuff!")

>
> def main():
>     """Main"""
>
>     parser = argparse.ArgumentParser()
>     parser.add_argument("--log-level", dest="log_level", type=int)
>     args = parser.parse_args()
>
>     print(f"log level: {args.log_level}")
>
>     logger = get_logger(args.log_level)
>     logger.debug("Logger!")
>     do_stuff()
>
>
> if __name__ == "__main__":
>     main()
>
> ---------------------------------------------------------------------
>
> How can I get logging for 'do_stuff' in this case without explicitly
> passing 'logger' as an argument or using 'global'?
>
> Somehow I am failing to understand how to get 'logger' defined
> sufficiently high up in the program that all references 'lower down' in
> the program will be automatically resolved. 
>
>> * there is some debate amongst developers about whether "one function,
>>   one purpose" should be a rule, a convention, or tossed in the
>>  trash. YMMV!
>>
>> Personal view: SOLID's "Single" principle applies: there should be
>> only one reason (hanging over the head of each method/function, like
>> the Sword of Damocles) for it to change - or one 'user' who could
>> demand a change to that function. In other words, an updated cmdLN
>> option shouldn't affect a function which establishes logging, for
>> example.
>>
>>
>> Web.Refs:
>> https://people.engr.tamu.edu/choe/choe/courses/20fall/315/lectures/slide23-solid.pdf
>> https://www.hanselminutes.com/145/solid-principles-with-uncle-bob-robert-c-martin
>> https://idioms.thefreedictionary.com/sword+of+Damocles
>> https://en.wikipedia.org/wiki/Damocles
>
> I don't really get the "one reason" idea and the Sword of Damocles
> analogy.  The later to me is more like "there's always a downside",
> since the perks of being king may mean someone might try to usurp the
> throne and kill you.  Where is the "single principle" aspect?
>
> However, the idea of "one responsibility" in the sense of "do only one
> thing" seems relatively clear, especially if I think in terms of writing
> unit tests.
>
> Cheers,
>
> Loris
-- 
Dr. Loris Bennett (Herr/Mr)
ZEDAT, Freie Universität Berlin


More information about the Python-list mailing list