2011-05-12 10 views
33

Tengo un simple script en Python que utiliza el incorporado logging.Python: ¿evitar pasar la referencia del registrador entre funciones?

estoy configurar el registro dentro de una función. Estructura básica sería algo como esto:

#!/usr/bin/env python 
import logging 
import ... 

def configure_logging(): 
    logger = logging.getLogger("my logger") 
    logger.setLevel(logging.DEBUG) 
    # Format for our loglines 
    formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") 
    # Setup console logging 
    ch = logging.StreamHandler() 
    ch.setLevel(logging.DEBUG) 
    ch.setFormatter(formatter) 
    logger.addHandler(ch) 
    # Setup file logging as well 
    fh = logging.FileHandler(LOG_FILENAME) 
    fh.setLevel(logging.DEBUG) 
    fh.setFormatter(formatter) 
    logger.addHandler(fh) 
    return logger 

def count_parrots(): 
    ... 
    logger.debug?? 

if __name__ == '__main__': 
    logger = configure_logging() 
    logger.debug("I'm a log file") 
    parrots = count_parrots() 

que pueda llamar desde el interior fina registrador __main__. Sin embargo, ¿cómo puedo llamar al registrador desde dentro de la función count_parrots()? ¿Cuál es la forma más pitónica de manejar la configuración de un registrador como este?

Respuesta

32

Puede usar el registrador raíz (predeterminado) y, por lo tanto, las funciones de nivel de módulo logging.debug, ... o puede utilizar su registrador en la función. De hecho, la función getLogger es una función como de fábrica con un registro (singleton similares), es decir, siempre devuelve la misma instancia para el nombre logger dado. este modo se puede conseguir que su registrador en count_parrots por el simple uso

logger = logging.getLogger("my logger") 

al principio. Sin embargo, la convención es usar un nombre jerárquico con puntos para su registrador. Ver http://docs.python.org/library/logging.html#logging.getLogger

EDIT:

Puede utilizar un decorador para añadir el comportamiento de registro a sus funciones individuales, por ejemplo:

def debug(loggername): 
    logger = logging.getLogger(loggername) 
    def log_(enter_message, exit_message=None): 
     def wrapper(f): 
      def wrapped(*args, **kargs): 
       logger.debug(enter_message) 
       r = f(*args, **kargs) 
       if exit_message: 
        logger.debug(exit_message) 
       return r 
      return wrapped 
     return wrapper 
    return log_ 

my_debug = debug('my.logger') 

@my_debug('enter foo', 'exit foo') 
def foo(a, b): 
    return a+b 

puede "codificar" el nombre del registrador y retire la parte superior- cierre de nivel y mi_debug.

+5

Ok, entonces puedo simplemente llamar a logging.getLogger al comienzo de cada función que necesita iniciar sesión. Parece un poco derrochador y repetitivo seguramente? Lo suficientemente justo. ¿O sería mejor orientarme hacia los objetos y tratar de calzar todo en una clase? (Es una pregunta muy general que sé, solo estoy buscando qué es lo que se hace en el mundo de Python). – victorhooi

+0

Puede poner su función en una clase con el registrador como variable de instancia, o (lo prefiero) crear un decorador para agregar la funcionalidad de registro a sus funciones individuales –

+9

Esta respuesta muestra casi todo lo que está mal con el registro de Python. módulo ... – rkrzr

-3

Puede dar logger como argumento al count_parrots() O, lo que haría, crear loros de clase y usar el registrador como uno de sus métodos.

6

La forma típica de manejar el registro es tener un registrador por módulo almacenado en una variable global. Cualquier función y método dentro de ese módulo simplemente hace referencia a esa misma instancia de registrador.

Esto se discute brevemente en la introducción al tutorial registro de avance en la documentación: http://docs.python.org/howto/logging.html#advanced-logging-tutorial

Usted puede casos registrador pase alrededor como parámetros, pero hacerlo es normalmente rara.

+0

Pensé que la práctica estándar era usar logger = logging.getLogger ("logger.name") –

+0

En el nivel del módulo, claro. El uso de registradores separados para diferentes funciones y métodos en el mismo módulo suele ser excesivo. Una excepción es que el uso de registradores separados puede ser una manera muy fácil de registrar qué hilos están registrando eventos particulares. – ncoghlan

+0

Ah. Pensé que querías decir realmente usar la palabra clave 'global'. –

13

sólo se puede hacer:

logger = logging.getLogger("my logger") 

en su método count_parrots(). Cuando pasa el nombre que se utilizó anteriormente (es decir, "mi registrador"), el módulo de registro devolverá la misma instancia que se creó correspondiente a ese nombre.

Actualización: Desde el logging tutorial (el mío emphais)

getLogger() devuelve una referencia a una instancia registrador con el nombre especificado si se proporciona, o raíz, si no . Los nombres son estructuras jerárquicas separadas por un período.Múltiples llamadas a getLogger() con el mismo nombre devolverá una referencia al mismo objeto logger .

0

Me confundí el funcionamiento de las variables globales en Python. Dentro de una función solo necesita declarar global logger si estaba haciendo algo como logger = logging.getLogger("my logger") y esperar modificar global logger.

Para modificar su ejemplo, puede crear un objeto registrador global al comienzo del archivo. Si su módulo puede ser importado por otro, debe agregar el NullHandler para que si el importador de la biblioteca no desea habilitar el registro, no tenga ningún problema con su lib (ref).

#!/usr/bin/env python 
import logging 
import ... 

logger = logging.getLogger("my logger").addHandler(logging.NullHandler()) 

def configure_logging(): 
    logger.setLevel(logging.DEBUG) 
    # Format for our loglines 
    formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") 
    # Setup console logging 
    ch = logging.StreamHandler() 
    ch.setLevel(logging.DEBUG) 
    ch.setFormatter(formatter) 
    logger.addHandler(ch) 
    # Setup file logging as well 
    fh = logging.FileHandler(LOG_FILENAME) 
    fh.setLevel(logging.DEBUG) 
    fh.setFormatter(formatter) 
    logger.addHandler(fh) 

def count_parrots(): 
    ... 
    logger.debug('counting parrots') 
    ... 
    return parrots 

if __name__ == '__main__': 
    configure_logging() 
    logger.debug("I'm a log file") 
    parrots = count_parrots() 
Cuestiones relacionadas