Python: registro personalizado en todos los módulos

Tarea

Tengo una colección de scripts y me gustaría que produjeran mensajes de registro unificados con modificaciones mínimas en los módulos que registran los mensajes reales.

He escrito un pequeño módulo 'custom_logger' al que planeo llamar desde la aplicación principal una vez, que devuelva un registrador, que luego seguiré usando.

Los submódulos que estaría importando en la aplicación solo deberían (o más bien deseo que lo hagan)

solo debe "importar el registro como registro", de modo que no se requiera nada específico de mi sitio para que solo se ejecuten si alguien más lo encuentra útil.solo debe registrar los mensajes con log.info/error('message ') sin agregarles nada específico del sitiodebe usar el registrador 'root' ya configurado con todo su formato y manejadores, y no afectar la configuración del registrador raíz

* custom_logger.py *

import logging
import logging.handlers
import os
import sys


def getLogger(name='root', loglevel='INFO'):
  logger = logging.getLogger(name)

  # if logger 'name' already exists, return it to avoid logging duplicate
  # messages by attaching multiple handlers of the same type
  if logger.handlers:
    return logger
  # if logger 'name' does not already exist, create it and attach handlers
  else:
    # set logLevel to loglevel or to INFO if requested level is incorrect
    loglevel = getattr(logging, loglevel.upper(), logging.INFO)
    logger.setLevel(loglevel)
    fmt = '%(asctime)s %(filename)-18s %(levelname)-8s: %(message)s'
    fmt_date = '%Y-%m-%dT%T%Z'
    formatter = logging.Formatter(fmt, fmt_date)
    handler = logging.StreamHandler()
    handler.setFormatter(formatter)
    logger.addHandler(handler)

    if logger.name == 'root':
      logger.warning('Running: %s %s',
                     os.path.basename(sys.argv[0]),
                     ' '.join(sys.argv[1:]))
    return logger

Luego viene el submódulo que contiene algunos mensajes de prueba con ejemplos de lo que funciona y lo que no.

submódulo.py

import sys
import custom_logger
import logging


class SubClass(object):

  def __init__(self):
    # NOK (no idea why since by default (no name parameter), it should return the root logger)
    #log = logging.getLogger()
    #log.info('message from SubClass / __init__')

    # OK (works as expected)
    #log = logging.getLogger('root')
    #log.info('message from SubClass / __init__')

    # OK (works as expected)
    log = custom_logger.getLogger('root')
    log.info('message from SubClass / __init__')


  def SomeMethod(self):
    # OK but I'd have to define `log` for every method, which is unacceptable
    # Please see question below all code snippets
    log = custom_logger.getLogger('root')
    log.info('message from SubClass / SomeMethod')

Y la aplicación principal:app.py Nada especial aquí:

#!/usr/bin/python

import custom_logger
import submodule

log = custom_logger.getLogger('root', loglevel='DEBUG')

log.debug('debug message')
log.info('info message')
log.warning('warning message')
log.error('error message')

a = submodule.SubClass() # this should produce a log message
a.SomeMethod()           # so should this

Salida que estoy buscando y que estoy obteniendo, solo de una manera extremadamente fea:

% ./app.py 
2013-04-08T03:07:46BST custom_logger.py   WARNING : Running: app.py 
2013-04-08T03:07:46BST app.py             DEBUG   : debug message
2013-04-08T03:07:46BST app.py             INFO    : info message
2013-04-08T03:07:46BST app.py             WARNING : warning message
2013-04-08T03:07:46BST app.py             ERROR   : error message
2013-04-08T03:07:46BST submodule.py       INFO    : message from SubClass / __init__
2013-04-08T03:07:46BST submodule.py       INFO    : message from SubClass / SomeMethod

Quiero poder definir un registrador en app.py y luego, en los submódulos, solo uso la biblioteca de registro estándar de Python para hacer uso de un registrador ya configurado en app.py.

También, una solución fea: si coloco el siguiente código después de las importaciones en submodule.py:

log = custom_logger.getLogger('root')

se ejecutará antes de que mi registrador se configure en app.py, haciendo el submódulo de manera efectiva, no mi registro de configuración de la aplicación.

Otra solución que consideré: dentro del constuctor de la clase SubClass, podría definir

self.log = custom_logger.getLogger('root')

y luego use self.log.error ('algún error'). Debe haber una forma más agradable: si puede sugerir algo útil o señalar dónde entendí mal la documentación, ¡le estaría muy agradecido!

PD. Me he pasado un buen rato leyendo el howto de registro de Python (básico y avanzado) y el libro de cocina, así que si me he perdido algo útil, indíquelo.

¡Gracias!

Respuestas a la pregunta(1)

Su respuesta a la pregunta