Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I was surprised that I didn't find this approach to logging anywhere while reading up on the subject. So, naturally, I think I may be doing something wrong. I set up some simple tests, and this seems to work:

First, the source: log.py

import datetime
import logging
import os

import config

#this is very straightforward, nothing special here.
log = config.Parser('log')


def setup(stream_level=logging.INFO):
    """shared log named {log.name + log.format}.log
    call this logging setup method once, in the main function
    always refer to the config file when referring to the logger 

    in modules other than the main file, call a reference to the
    already created logger in memory via log.hook(module_name)
    as long as this setup() was ran in the main method, the logfile
    should already exist in the proper place, with streams created
    for use, according to the config file entry for 'log'.

    `stream_level` indicates what level of 
    detail should be printed to the terminal
    """

    log.level = log.level.upper()

    logger = logging.getLogger(log.name)
    logger.setLevel(log.level)

    formatter = logging.Formatter(log.format)
    formatter.datefmt = log.datefmt

    pretty_date = datetime.date.strftime(datetime.datetime.now(), log.datefmt)
    date_ext = filter(lambda x: x.isdigit(), pretty_date)

    #terminal logging
    if stream_level:
        ch = logging.StreamHandler()
        ch.setLevel(stream_level)
        ch.setFormatter(formatter)

    #file logging
    logname = ''.join([log.name, date_ext, '.log'])
    fh = logging.FileHandler(os.path.join(log.dir, logname))
    fh.setLevel(log.level)
    fh.setFormatter(formatter)
    logger.addHandler(fh)

    if stream_level:
        logger.addHandler(ch)

    return logger

def hook(module_name):
    """pass in the special method __name__ for best results
    don't call this until you've setup() the logger in your main function
    """
    return logging.getLogger('.'.join([log.name, module_name]))

And the main.py

import util
import log

logger = log.setup()

logger.info('starting now')

util.p()

logger.critical('quitting!')

util.py

import log

def p():
    logger = log.hook(__name__)
    for x in range(10):
        logger.warn('.')
share|improve this question
add comment

1 Answer

up vote 2 down vote accepted

You can find approach you are looking for in the logging cookbook and logging howto: Default logging module provides nice configuration feature.

So your code will be like this:

simpleExample.py (main):

import os
import logging
import logging.config
logging.config.fileConfig(os.path.join(os.path.dirname(__file__),
                          'logging.conf')  
import util

# create logger
logger = logging.getLogger("simpleExample") 

# 'application' code
logger.info('starting now')

util.p()

logger.critical('quitting!')

util.py

import logging
logger = logging.getLogger("simpleExample.Utils")

def p():
    for x in range(10):
        logger.warn('.')

And all the magic of logging configuration will be avalible in config file: logging.cfg:

[loggers]
keys=root,simpleExample

[handlers]
keys=consoleHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=DEBUG
handlers=consoleHandler

[logger_simpleExample]
level=DEBUG
handlers=consoleHandler
qualname=simpleExample
propagate=0

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)

[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=`

You can use any handlers you want, and you can change levels, formats etc and you don't have to change your code.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.