Registrar, eliminar, inspeccionar y modificar controladores configurados por fileConfig()

5 minutos de lectura

Avatar de usuario de Pawel Furmaniak
Pawel Furmaniak

¿Cómo puedo eliminar, inspeccionar y modificar los controladores configurados para mis registradores mediante la función fileConfig()?

Para eliminar, existe el método Logger.removeHandler(hdlr), pero ¿cómo obtengo el controlador en primer lugar si se configuró desde un archivo?

logger.handlers contiene una lista con todos los controladores de un registrador.

  • Esto no está documentado. ¿Es seguro usarlo?

    – Manish

    24/04/2012 a las 19:33

  • @Manish: mirando el código, diría que es seguro de usar, siempre que no haga subprocesos múltiples. La lista de controladores es un recurso compartido protegido por un bloqueo y la lista solo contiene referencias a los controladores. No lo use, si hace subprocesos múltiples.

    – Enno Groper

    9 de febrero de 2013 a las 11:59

  • Esto solo contiene controladores estándar, ¿qué sucede si escribe los suyos propios? Además, llamarlo lista es engañoso, estaba buscando una lista de instancias y no había ninguna. Es solo una colección de clases.

    – bartekbrak

    22 de marzo de 2017 a las 13:35

  • Vale la pena señalar que logger.handlers no incluye controladores derivados del registrador principal. Todos los registradores, excepto RootLogger, tienen su registrador principal que tiene su propio handlers lista.

    – patryk.beza

    26 de abril de 2017 a las 20:22

  • Advertencia: logger.handlers podría ser modificado por paquetes como pytest (al menos si logger es el registrador raíz, es decir logger = logging.getLogger()). Entonces, si desea un código comprobable (que se comporte en las pruebas de la misma manera que en producción), prefiero evitar acceder logger.handlers que es esencialmente un estado global. Realmente me supera por qué los desarrolladores de Python decidieron implementar el registro a través del estado global en lugar de realizar una inyección de dependencia adecuada.

    – balú

    7 dic 2020 a las 20:29


Avatar de usuario de Mickey Perlstein
mickey perlstein

Este código imprimirá todos los registradores y para cada registrador sus controladores

for k,v in  logging.Logger.manager.loggerDict.items()  :
        print('+ [%s] {%s} ' % (str.ljust( k, 20)  , str(v.__class__)[8:-2]) )
        if not isinstance(v, logging.PlaceHolder):
            for h in v.handlers:
                print('     +++',str(h.__class__)[8:-2] )

Esto imprimirá los registradores y controladores en su sistema, incluidos sus estados y niveles.

Esto lo ayudará a depurar sus problemas de registro

output:
+ [root                ] {logging.RootLogger} {DEBUG}
-------------------------
   -name=root
   -handlers=[<logging.FileHandler object at 0x7fc599585390>, <logging.StreamHandler object at 0x7fc599585550>]
   -filters=[]
   -propagate=True
   -level=10
   -disabled=False
   -parent=None
     +++logging.FileHandler {NOTSET}
   -stream=<_io.TextIOWrapper name="/dev/logs/myapp.log" mode="w" encoding='UTF-8'>
   -mode=w
   -filters=[]
   -encoding=None
   -baseFilename=/home/dev/logs/myapp.log
   -level=0
   -lock=<unlocked _thread.RLock object owner=0 count=0 at 0x7fc5a85a4240>
   -delay=False
   -_name=None
   -formatter=<logging.Formatter object at 0x7fc599585358>
     +++logging.StreamHandler {DEBUG}
   -lock=<unlocked _thread.RLock object owner=0 count=0 at 0x7fc5a85a4210>
   -filters=[]
   -stream=<ipykernel.iostream.OutStream object at 0x7fc5aa6abb00>
   -level=10
   -_name=None
   -formatter=<logging.Formatter object at 0x7fc5995853c8>
+ [PathFinder          ] {logging.Logger} {NOTSET}
-------------------------
   -name=PathFinder
   -handlers=[]
   -filters=[]
   -manager=<logging.Manager object at 0x7fc5b09757f0>
   -propagate=True
   -level=0
   -disabled=False
   -parent=<logging.RootLogger object at 0x7fc5b09757b8>

  • Esto es increíble y exactamente el tipo de cosas que no pude encontrar en ningún otro lugar.

    – Greg Müller

    1 de abril de 2019 a las 11:52

  • gracias @GregMueller, estoy trabajando en un módulo auxiliar instalado en pip que ofrecerá otros conocimientos sobre la pila de registro

    -Mickey Perlstein

    1 de abril de 2019 a las 12:42

  • @jens sí. Hace tiempo que no me comprometo

    -Mickey Perlstein

    12 de agosto de 2019 a las 23:23

  • Para aquellos que quieren ver el depurador de Mickey en github: github.com/mickeyperlstein/logging_debugger/blob/master/…

    – Russau

    9 de abril de 2020 a las 14:28

Avatar de usuario de Alias_Knagg
Alias_Knagg

La respuesta de Mickey-Perlstein fue justo lo que estaba buscando, pero la lista parece provenir de una versión mucho más completa que el código proporcionado.

Este código es un poco más tosco, pero crucialmente para mi uso y comprensión, incluye el registrador raíz.

import logging

def listloggers():
    rootlogger = logging.getLogger()
    print(rootlogger)
    for h in rootlogger.handlers:
        print('     %s' % h)

    for nm, lgr in logging.Logger.manager.loggerDict.items():
        print('+ [%-20s] %s ' % (nm, lgr))
        if not isinstance(lgr, logging.PlaceHolder):
            for h in lgr.handlers:
                print('     %s' % h)

Producción:

<RootLogger root (DEBUG)>
     <TimedRotatingFileHandler /path/to/myapp.log (DEBUG)>
     <StreamHandler <stdout> (DEBUG)>
+ [concurrent.futures  ] <Logger concurrent.futures (DEBUG)>
+ [concurrent          ] <logging.PlaceHolder object at 0x7f72f624eba8>
+ [asyncio             ] <Logger asyncio (DEBUG)>
+ [myapp               ] <Logger myapp (DEBUG)>
+ [flask.app           ] <Logger flask.app (DEBUG)>
+ [flask               ] <Logger flask (DEBUG)>
+ [werkzeug            ] <Logger werkzeug (ERROR)>

  • Me gustan tus detalles concisos, gran “tenedor”

    -Mickey Perlstein

    18 de junio de 2020 a las 13:24

  • Esto también enumeró el FileHandler que definí en un archivo de configuración en RootLogger (el código de Mickey no).

    – Roberto

    4 de junio de 2021 a las 11:05

Otro enfoque podría ser usar un archivo de configuración JSON o YAML que se carga en un diccionario que luego puede ver/manipular antes de pasarlo a logger.config.

import yaml
import logging.config

with open (LOG_CONFIG, 'rt') as f:
   config=yaml.safe_load(f)
   config['handlers']['error_file_handler']['filename']='foo'
logging.config.dictConfig(config)

Avatar de usuario de Sicro
sicro

Volver a eliminar controladores: si ayuda a alguien, quería eliminar todos los controladores para todos los registros que había creado (estaba aprendiendo sobre el registro de Python) y se me ocurrió esto:

def log_close():
    # Get all loggers
    loggers = [logging.getLogger(name) if 'your_app_name' in name else None for name in logging.root.manager.loggerDict]

    # For each valid logger remove all handlers
    for log in loggers:
        if log != None:
            while bool(len(log.handlers)):
                for handler in log.handlers:
                    log.removeHandler(handler)
# Set up log
log = logging.getLogger('your_app_name')
log.setLevel('DEBUG')
log_format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
date_format="%Y-%m-%d %H:%M:%S"
formatter = logging.Formatter(log_format, date_format)
log_filename="your_app_name.log"
log_write_mode="w+"
file_handler = logging.FileHandler(log_filename, log_write_mode)
file_handler.setFormatter(formatter)
log.addHandler(file_handler)
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
log.addHandler(console_handler)

¿Ha sido útil esta solución?