views:

46

answers:

2

I have a package that has several components in it that would benefit greatly from using logging and outputting useful information.

What I do not want to do is to 'setup' proper logging for every single file with somewhere along these lines:

import logging
logging.basicConfig(level=DEBUG)
my_function = logging.getLogger("my_function")
my_class = logging.getLogger("my_class")

I have tried a couple of approaches, one of them being adding the boilerplate code into a class within a utility module and try and do something like this:

from util import setlogging
set_logging()

But even the above solution doesn't look clean to me and would cause issues because setLogger doesn't have a __call__ method. What I did liked was that my "set_logging" class would read form a config file and have some default values so it wouldn't matter what level or what type of logging format I wanted it would set it up correctly.

Is there a way to initialize proper logging across the board in my package? Maybe in the __init__.py file?

And just to be as verbose as possible, this is what setlogging (now a function, not a class) looks like:

def setlogging(config=None):
    if config == None:
        config = config_options() # sets default values
    levels = {
        'debug': DEBUG,
       'info': INFO
        }

    level = levels.get(config['log_level'])
    log_format = config['log_format']
    datefmt = config['log_datefmt']

    basicConfig(
        level   = level,
        format  = log_format,
        datefmt = datefmt)
+2  A: 

If you want all the code in the various modules of your package to use the same logger object, you just need to (make that logger available -- see later -- and) call

mylogger.warning("Attenzione!")

or the like, rather than logging.warning &c. So, the problem reduces to making one mylogger object for the whole package and making it available throughout the modules in the package. (Alternatively, you could used named loggers with names starting with the package's name followed by a dot, but while that's very much a part of the logging package functionality, I've personally never found it a natural way to operate).

So, your util.setlogging function could simply be followed by, say,

mylogger = logging.getLogger(package_name)

and every module that imports util can simply use

util.mylogger.warning('Watch out!')

and the like. This seems to me to be the simplest approach, as long as the concept that all the code in the package should be logging in the same way applies.

Alex Martelli
wouldn't I still need to call setlogging() to be able to access 'mylogger' ? Even though I try that, I still get an expected AttributeError since the 'function' object has no attribute 'mylogger'.Maybe I am not fully getting the picture...
alfredodeza
@alfredo, it needs to be called only once (from the package's `__init__.py` would be the simplest spot to use for the purpose, since you know it always runs before any code in any module in the package) and of course you can add to that logger a handler, with its formatter configured as you please, as in the example code given at http://docs.python.org/library/logging.html?highlight=logging#configuring-logging .
Alex Martelli
Thanks Alex, that really helped out! I will buy you a beer next year at PyCon :)
alfredodeza
@alfredo, counting on it -- see you in San Jose then!-)
Alex Martelli
+1  A: 

The proper way for a module to use logging is

import logging
logger = getLogger('my_module_name')

and

logger.debug('help!')

becomes a no-op until someone calls logging.basicConfig() (or a variant).

msw