0

So, I want to control the verbosity of the logger. I know that I can do this via logging.basicConfig. Currently, I have the following code which works fine:

import logging
from argparse import ArgumentParser
logger = None

class MyClass:
    def __init__(self):
        logger.info('initialized')

def main():
    parser = ArgumentParser()
    parser.add_argument('--verbose', default=False, action='store_true')
    args = parser.parse_args()

    global logger
    if args.verbose:
        logging.basicConfig(format="%(levelname)s: %(message)s", level=logging.DEBUG)
    else:
        logging.basicConfig(format="%(levelname)s: %(message)s", level=logging.INFO)
    logger = logging.getLogger('mylogger')
    myclass = MyClass()


if __name__ == '__main__':
    main()

However, I get the pylint error:

Redefining name 'logger' from outer scope (line 3) (redefined-outer-name)

What is the best way to achieve this without any pylint errors?

CentAu
  • 10,660
  • 15
  • 59
  • 85
  • So... why are you setting `logger` inside `main`? – user2357112 Jul 18 '18 at 23:57
  • Because of pylint. I did that first, and it complained that the name `logger` does not conform to constant name. After searching it seemed that variables should not be defined at the module level. – CentAu Jul 19 '18 at 00:13

2 Answers2

4

So there are a few ways to go about fixing your problem... Here is what I recommend, (Comments inline with #)

import logging
from argparse import ArgumentParser

# You only need to set the logger config once really
logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)s %(name)s %(levelname)-8s %(thread)d %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S")

# Typically make globals in CAPS to avoid name space problems.. per PEP-8 
LOG = logging.getLogger("My Module")
# Note you may not need a global logger?

class MyClass:
    def __init__(self, log_level=logging.INFO):
       # you can just setup a class logger like this, and pass in the log level?
       self.log = logging.getlogger("My Class")
       self.log.setLevel(log_level)

       # Will print a message with "My Module"
       LOG.info('Message from global logger!')

       # Will print a message with "My Class"
       self.log.info('Message from class logger!')

       # Will print a message if -v or --verbose was used on CLI
       self.log.debug('Debug class message!')


def main():
    parser = ArgumentParser()

    # You can use arg parse to just store a couple constants of the log level
    parser.add_argument("-v", "--verbose", help="Increase output verbosity",
                        action="store_const", const=logging.DEBUG, default=logging.INFO)
    args = parser.parse_args()

    # Now you can just set the const from the arg
    LOG.setLevel(args.verbose)

    # If you want to set it to the class logger you can do this
    myclass = MyClass(args.verbose)


if __name__ == '__main__':
    main()
sehafoc
  • 866
  • 6
  • 9
  • Do other libraries will log at DEBUG level? – Anton Petrov Dec 20 '18 at 14:29
  • @AntonPetrov Sorry for the late reply. Yes many python libraries do. In many libs you can just call it's logger and set the level to what ever you like. Here is an example of modifying a libraries logger: https://stackoverflow.com/questions/8144545/turning-off-logging-in-paramiko – sehafoc Jan 06 '19 at 05:56
0

Once you are declaring global, Initializing a variable to None in the outer scope unnecessary. Try removing that line.

I Dav
  • 374
  • 1
  • 2
  • 8
  • When I remove it, I get another pylint error: Global variable 'logger' undefined at the module level – CentAu Jul 19 '18 at 00:02
  • As stated on the comment above, you should consider setting the logger in the module's level, not inside main. – I Dav Jul 19 '18 at 00:04