Cómo usar el registro de Python en múltiples módulos

Me preguntaba cuál es la configuración estándar para realizar el registro desde una aplicación Python.

Estoy usando la clase de registro y he escrito mi propia clase de registrador que crea una instancia de la clase de registro. Mi principal entonces crea una instancia de mi clase de contenedor de registrador. Sin embargo, mi principal crea una instancia de otras clases y quiero que esas otras clases también puedan escribir en el archivo de registro a través del objeto logger en la principal.

¿Cómo hago ese objeto de registrador para que pueda ser llamado por otras clases? Es casi como si necesitamos algún tipo de objeto de registrador estático para que esto funcione.

Creo que la pregunta más larga y corta es: ¿cómo implementa el registro dentro de su estructura de código de manera que todas las clases creadas desde el main puedan escribir en el mismo archivo de registro? ¿Tengo que crear un nuevo objeto de registro en cada una de las clases que apunta al mismo archivo?

No sé qué quiere decir con la clase de Logging : no existe tal clase en el registro integrado de Python. Realmente no necesita envoltorios: aquí hay un ejemplo de cómo hacer el registro de clases arbitrarias que escribe:

 import logging # This class could be imported from a utility module class LogMixin(object): @property def logger(self): name = '.'.join([__name__, self.__class__.__name__]) return logging.getLogger(name) # This class is just there to show that you can use a mixin like LogMixin class Base(object): pass # This could be in a module separate from B class A(Base, LogMixin): def __init__(self): # Example of logging from a method in one of your classes self.logger.debug('Hello from A') # This could be in a module separate from A class B(Base, LogMixin): def __init__(self): # Another example of logging from a method in one of your classes self.logger.debug('Hello from B') def main(): # Do some work to exercise logging a = A() b = B() with open('myapp.log') as f: print('Log file contents:') print(f.read()) if __name__ == '__main__': # Configure only in your main program clause logging.basicConfig(level=logging.DEBUG, filename='myapp.log', filemode='w', format='%(name)s %(levelname)s %(message)s') main() 

En general, no es necesario tener registradores a nivel de clase: en Python, a diferencia de Java, la unidad de la composición del progtwig (de) es el módulo. Sin embargo, nada te impide hacerlo, como he mostrado anteriormente. El script, cuando se ejecuta, muestra:

 Log file contents: __main__.A DEBUG Hello from A __main__.B DEBUG Hello from B 

Tenga en cuenta que el código de ambas clases se registró en el mismo archivo, myapp.log. Esto habría funcionado incluso con A y B en diferentes módulos.

Intente usar logging.getLogger () para obtener su instancia de objeto de registro:

http://docs.python.org/3/library/logging.html#logging.getLogger

Todas las llamadas a esta función con un nombre dado devuelven la misma instancia de registrador. Esto significa que las instancias del registrador nunca deben pasar entre diferentes partes de una aplicación.

ACTUALIZACIÓN :

La forma recomendada de hacer esto es usar la función getLogger () y configurarla (configurando un controlador, formateador, etc.):

 # main.py import logging import lib def main(): logger = logging.getLogger('custom_logger') logger.setLevel(logging.INFO) logger.addHandler(logging.FileHandler('test.log')) logger.info('logged from main module') lib.log() if __name__ == '__main__': main() # lib.py import logging def log(): logger = logging.getLogger('custom_logger') logger.info('logged from lib module') 

Si realmente necesita ampliar la clase de registrador, eche un vistazo a logging.setLoggerClass (klass)

ACTUALIZACIÓN 2 :

Ejemplo sobre cómo agregar un nivel de registro personalizado sin cambiar la clase de registro:

 # main.py import logging import lib # Extend Logger class CUSTOM_LEVEL_NUM = 9 logging.addLevelName(CUSTOM_LEVEL_NUM, 'CUSTOM') def custom(self, msg, *args, **kwargs): self._log(CUSTOM_LEVEL_NUM, msg, args, **kwargs) logging.Logger.custom = custom # Do global logger instance setup logger = logging.getLogger('custom_logger') logger.setLevel(logging.INFO) logger.addHandler(logging.FileHandler('test.log')) def main(): logger = logging.getLogger('custom_logger') logger.custom('logged from main module') lib.log() if __name__ == '__main__': main() 

Tenga en cuenta que no se recomienda agregar un nivel personalizado: http://docs.python.org/2/howto/logging.html#custom-levels

Definir un controlador personalizado y quizás usar más de un registrador puede hacer el truco para su otro requisito: salida opcional a stderr.