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