3
\$\begingroup\$

I'm trying to learn writing python programs in a modular way as much as possible. One of the issues I've had difficulty to solve is parsing command line arguments (with argparse) and having a logger object in all my modules which it's name will be the __name__ of the module and it's log level identical across all modules.

I've even posted a question on Sstack Overflow where I describe the problem more thoroughly but I would like to gain some confidence with the solution I've constructed before posting an answer to my own question.

This is the scheme I've come up with:

core/__init__.py:

from .argpconf import Argpconf

import logging
argpconf = Argpconf()
_loglevel = argpconf.get_loglevel()
class Logger(logging.Logger):
    def __init__(self, name, level=_loglevel):
        self.name = name
        logging.Logger.__init__(self, name, level)
        self.addHandler(argpconf.get_loghandler())

core/argpconf.py:

from argparse import ArgumentParser
import logging

class Argpconf():
    def __init__(self):
        """
        Define command line arguments parser
        """
        self.argp = ArgumentParser(
            description="Generator for shell, ranger and vim commands for fzf based shortcuts"
        )
        self.argp.add_argument(
            '-v', '--verbose',
            dest='verbosity',
            default=2,
            action='count',
            help='increase verbosity, use multiple times to increase more'
        )
        self.args = vars(self.argp.parse_args())
    def get_loglevel(self):
        # Convert logging level to the proper scale
        logging_level = self.args['verbosity'] * 10
        # make sure a level higher then 50 won't be passed to setLevel
        logging_level = min(logging_level, 50)
        # reverse the numbers of so a higher verbosity will set a higher log level
        logging_level = 60 - logging_level
        return logging_level
    def get_logformat(self):
        if self.args['verbosity'] > 2:
            return logging.Formatter('%(name)s - %(levelname)s - %(message)s')
        else:
            return logging.Formatter('%(message)s')
    def get_loghandler(self):
        handler = logging.StreamHandler()
        handler.setFormatter(self.get_logformat())
        return handler

Every other file that would like to use a logger:

from core import Logger
logger = Logger(__name__)

...

Notes

  • The Logger class defined in core/__init__.py is based on this.
  • The function get_logformat from Argpconf sets a different format for the messages so in debugging modes the __name__ and levelname will be included, according to the verbosity set in the command line.
\$\endgroup\$
  • \$\begingroup\$ Your code will not compile: argpconf.get_loglevel() is not defined. I assume you have "simplified" the code for posting to "Code Review", but ended up removing too much. You need to provide complete working code, or your question will be put on hold and/or closed. \$\endgroup\$ – AJNeufeld Oct 16 '18 at 18:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.