When is logging.getLogger(__name__) needed?

Loris Bennett loris.bennett at fu-berlin.de
Wed Apr 5 08:45:03 EDT 2023


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!")


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

-- 
This signature is currently under constuction.


More information about the Python-list mailing list