values setlevel loggeradapter info example disable_existing_loggers python logging module global-variables

setlevel - Python: módulo de registro-globalmente



python logging example (4)

Como no he encontrado una respuesta satisfactoria, me gustaría profundizar un poco en la respuesta a la pregunta para dar una idea del funcionamiento y las intenciones de la biblioteca de logging , que viene con la biblioteca estándar de Python.

A diferencia del enfoque del OP (póster original), la biblioteca separa claramente la interfaz del registrador y la configuración del propio registrador.

La configuración de los controladores es una prerrogativa del desarrollador de la aplicación que usa su biblioteca.

Eso significa que no debe crear una clase de registrador personalizada y configurar el registrador dentro de esa clase agregando cualquier configuración o lo que sea.

La biblioteca de logging presenta cuatro componentes: registradores , manejadores , filtros y formateadores .

  • Los madereros exponen la interfaz que utiliza directamente el código de la aplicación.
  • Los manejadores envían los registros de registro (creados por los registradores) al destino apropiado.
  • Los filtros proporcionan una instalación de grano más fino para determinar qué registro registra para producir.
  • Los formateadores especifican el diseño de los registros en el resultado final.

Una estructura de proyecto común se ve así:

Project/ |-- .../ | |-- ... | |-- project/ | |-- package/ | | |-- __init__.py | | |-- module.py | | | |-- __init__.py | |-- project.py | |-- ... |-- ...

Dentro de su código (como en module.py ) se refiere a la instancia de registro de su módulo para registrar los eventos en sus niveles específicos.

Una buena convención para usar al nombrar registradores es usar un registrador de nivel de módulo, en cada módulo que utiliza el registro, nombrado de la siguiente manera:

logger = logging.getLogger(__name__)

La variable especial __name__ refiere al nombre de su módulo y se ve como project.package.module dependiendo de la estructura del código de su aplicación.

module.py (y cualquier otra clase) podría ser esencialmente así:

import logging ... log = logging.getLogger(__name__) class ModuleClass: def do_something(self): log.debug(''do_something() has been called!'')

¡El registrador en cada módulo propagará cualquier evento al registrador padre que a su vez pasa la información a su manejador adjunto! De forma análoga a la estructura del paquete / módulo de python, el registrador principal está determinado por el espacio de nombres utilizando "nombres de módulo de puntos". Es por eso que tiene sentido inicializar el registrador con la variable especial __name__ (en el ejemplo anterior el nombre coincide con la cadena "project.package.module" ).

Hay dos opciones para configurar el registrador globalmente:

  • Cree una instancia de un registrador en project.py con el nombre __package__ que equivale a "proyecto" en este ejemplo y, por lo tanto, es el registrador padre de los registradores de todos los submódulos. Solo es necesario agregar un manejador y formateador apropiado a este registrador.

  • Configure un registrador con un manejador y formateador en el script de ejecución (como main.py ) con el nombre del paquete superior.

Al desarrollar una biblioteca que utiliza el registro, debe tener cuidado de documentar cómo la biblioteca utiliza el registro, por ejemplo, los nombres de los registradores utilizados.

El script de ejecución, como main.py por ejemplo, finalmente podría verse más o menos así:

import logging from project import App def setup_logger(): # create logger logger = logging.getLogger(''project'') logger.setLevel(logging.DEBUG) # create console handler and set level to debug ch = logging.StreamHandler() ch.setLevel(level) # create formatter formatter = logging.Formatter(''%(asctime)s [%(levelname)s] %(name)s: %(message)s'') # add formatter to ch ch.setFormatter(formatter) # add ch to logger logger.addHandler(ch) if __name__ == ''__main__'' and __package__ is None: setup_logger() app = App() app.do_some_funny_stuff()

El método call log.setLevel(...) especifica el mensaje de registro de menor gravedad que manejará un registrador, pero no necesariamente el resultado. Simplemente significa que el mensaje se pasa al manejador siempre que el nivel de gravedad del mensaje sea mayor que (o igual) que el establecido. Pero el controlador es responsable de manejar el mensaje de registro (imprimiéndolo o guardándolo, por ejemplo).

Por lo tanto, la biblioteca de logging ofrece un enfoque estructurado y modular que solo necesita ser explotado de acuerdo con sus necesidades.

Documentación de registro

Hola, me preguntaba cómo implementar un registrador global que podría usarse en todas partes con su propia configuración:

yo tengo

class customLogger(logging.Logger): ...

en un archivo con sus formateadores y otras cosas. El registrador funciona perfectamente por sí mismo.

Importe este módulo en mi archivo main.py y creo un objeto como este:

self.log = log.customLogger(arguments)

Pero obviamente no puedo acceder a este objeto desde otras partes de mi código. ¿Estoy usando un enfoque equivocado? ¿Hay una mejor manera de hacer esto?


Cree una instancia de customLogger en su módulo de registro y customLogger como singleton; solo use la instancia importada, en lugar de la clase.


Puede pasarle una cadena con una subcadena común antes del primer período. Las partes de la cadena separadas por el punto (".") Se pueden usar para diferentes clases / módulos / archivos / etc. Al igual que (específicamente la parte logger = logging.getLogger(loggerName) ):

def getLogger(name, logdir=LOGDIR_DEFAULT, level=logging.DEBUG, logformat=FORMAT): base = os.path.basename(__file__) loggerName = "%s.%s" % (base, name) logFileName = os.path.join(logdir, "%s.log" % loggerName) logger = logging.getLogger(loggerName) logger.setLevel(level) i = 0 while os.path.exists(logFileName) and not os.access(logFileName, os.R_OK | os.W_OK): i += 1 logFileName = "%s.%s.log" % (logFileName.replace(".log", ""), str(i).zfill((len(str(i)) + 1))) try: #fh = logging.FileHandler(logFileName) fh = RotatingFileHandler(filename=logFileName, mode="a", maxBytes=1310720, backupCount=50) except IOError, exc: errOut = "Unable to create/open log file /"%s/"." % logFileName if exc.errno is 13: # Permission denied exception errOut = "ERROR ** Permission Denied ** - %s" % errOut elif exc.errno is 2: # No such directory errOut = "ERROR ** No such directory /"%s/"** - %s" % (os.path.split(logFileName)[0], errOut) elif exc.errno is 24: # Too many open files errOut = "ERROR ** Too many open files ** - Check open file descriptors in /proc/<PID>/fd/ (PID: %s)" % os.getpid() else: errOut = "Unhandled Exception ** %s ** - %s" % (str(exc), errOut) raise LogException(errOut) else: formatter = logging.Formatter(logformat) fh.setLevel(level) fh.setFormatter(formatter) logger.addHandler(fh) return logger class MainThread: def __init__(self, cfgdefaults, configdir, pidfile, logdir, test=False): self.logdir = logdir logLevel = logging.DEBUG logPrefix = "MainThread_TEST" if self.test else "MainThread" try: self.logger = getLogger(logPrefix, self.logdir, logLevel, FORMAT) except LogException, exc: sys.stderr.write("%s/n" % exc) sys.stderr.flush() os._exit(0) else: self.logger.debug("-------------------- MainThread created. Starting __init__() --------------------") def run(self): self.logger.debug("Initializing ReportThreads..") for (group, cfg) in self.config.items(): self.logger.debug(" ------------------------------ GROUP ''%s'' CONFIG ------------------------------ " % group) for k2, v2 in cfg.items(): self.logger.debug("%s <==> %s: %s" % (group, k2, v2)) try: rt = ReportThread(self, group, cfg, self.logdir, self.test) except LogException, exc: sys.stderr.write("%s/n" % exc) sys.stderr.flush() self.logger.exception("Exception when creating ReportThread (%s)" % group) logging.shutdown() os._exit(1) else: self.threads.append(rt) self.logger.debug("Threads initialized.. /"%s/"" % ", ".join([t.name for t in self.threads])) for t in self.threads: t.Start() if not self.test: self.loop() class ReportThread: def __init__(self, mainThread, name, config, logdir, test): self.mainThread = mainThread self.name = name logLevel = logging.DEBUG self.logger = getLogger("MainThread%s.ReportThread_%s" % ("_TEST" if self.test else "", self.name), logdir, logLevel, FORMAT) self.logger.info("init database...") self.initDB() # etc.... if __name__ == "__main__": # ..... MainThread(cfgdefaults=options.cfgdefaults, configdir=options.configdir, pidfile=options.pidfile, logdir=options.logdir, test=options.test)


Use logging.getLogger(name) para crear un registrador global nombrado.

main.py

import log logger = log.setup_custom_logger(''root'') logger.debug(''main message'') import submodule

log.py

import logging def setup_custom_logger(name): formatter = logging.Formatter(fmt=''%(asctime)s - %(levelname)s - %(module)s - %(message)s'') handler = logging.StreamHandler() handler.setFormatter(formatter) logger = logging.getLogger(name) logger.setLevel(logging.DEBUG) logger.addHandler(handler) return logger

submodule.py

import logging logger = logging.getLogger(''root'') logger.debug(''submodule message'')

Salida

2011-10-01 20:08:40,049 - DEBUG - main - main message 2011-10-01 20:08:40,050 - DEBUG - submodule - submodule message