values setlevel practices logger info example best python logging python-3.x stdout

setlevel - python logging best practices



Cómo redireccionar stdout y stderr a logger en Python (6)

Tengo un registrador que tiene un RotatingFileHandler . Quiero redireccionar todos los Stdout y Stderr al registrador. ¿Cómo hacerlo?


Como evolución a la respuesta de Cameron Gagnon, he mejorado la clase LoggerWriter para:

class LoggerWriter(object): def __init__(self, writer): self._writer = writer self._msg = '''' def write(self, message): self._msg = self._msg + message while ''/n'' in self._msg: pos = self._msg.find(''/n'') self._writer(self._msg[:pos]) self._msg = self._msg[pos+1:] def flush(self): if self._msg != '''': self._writer(self._msg) self._msg = ''''

Ahora las excepciones no controladas se ven mejor:

2018-07-31 13:20:37,482 - ERROR - Traceback (most recent call last): 2018-07-31 13:20:37,483 - ERROR - File "mf32.py", line 317, in <module> 2018-07-31 13:20:37,485 - ERROR - main() 2018-07-31 13:20:37,486 - ERROR - File "mf32.py", line 289, in main 2018-07-31 13:20:37,488 - ERROR - int('''') 2018-07-31 13:20:37,489 - ERROR - ValueError: invalid literal for int() with base 10: ''''


Con color añadido a la respuesta de Vinay Sajip:

class LoggerWriter: def __init__(self, logger, level): self.logger = logger self.level = level def write(self, message): if message != ''/n'': self.logger.log(self.level, message) def flush(self): pass


No tengo suficiente representante para comentar, pero quería agregar la versión de esto que funcionó para mí en caso de que otros se encuentren en una situación similar.

class LoggerWriter: def __init__(self, level): # self.level is really like using log.debug(message) # at least in my case self.level = level def write(self, message): # if statement reduces the amount of newlines that are # printed to the logger if message != ''/n'': self.level(message) def flush(self): # create a flush method so things can be flushed when # the system wants to. Not sure if simply ''printing'' # sys.stderr is the correct way to do it, but it seemed # to work properly for me. self.level(sys.stderr)

y esto se vería algo así como:

log = logging.getLogger(''foobar'') sys.stdout = LoggerWriter(log.debug) sys.stderr = LoggerWriter(log.warning)


Puedes usar el administrador de contexto redirect_stdout:

import logging from contextlib import redirect_stdout logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) logging.write = lambda msg: logging.info(msg) if msg != ''/n'' else None with redirect_stdout(logging): print(''Test'')

o así

import logging from contextlib import redirect_stdout logger = logging.getLogger(''Meow'') logger.setLevel(logging.INFO) formatter = logging.Formatter( fmt=''[{name}] {asctime} {levelname}: {message}'', datefmt=''%m/%d/%Y %H:%M:%S'', style=''{'' ) ch = logging.StreamHandler() ch.setLevel(logging.INFO) ch.setFormatter(formatter) logger.addHandler(ch) logger.write = lambda msg: logger.info(msg) if msg != ''/n'' else None with redirect_stdout(logger): print(''Test'')


Si se trata de un sistema todo en Python (es decir, no hay bibliotecas C que escriban directamente en fds, como preguntó Ignacio Vázquez-Abrams), entonces es posible que pueda utilizar un enfoque como se sugiere here :

class LoggerWriter: def __init__(self, logger, level): self.logger = logger self.level = level def write(self, message): if message != ''/n'': self.logger.log(self.level, message)

y luego configure sys.stdout y sys.stderr en instancias de LoggerWriter .


Todas las respuestas anteriores parecen tener problemas para agregar nuevas líneas adicionales donde no son necesarias. La solución que mejor me funciona es de http://www.electricmonk.nl/log/2011/08/14/redirect-stdout-and-stderr-to-a-logger-in-python/ , donde demuestra cómo envíe tanto stdout como stderr al registrador:

import logging import sys class StreamToLogger(object): """ Fake file-like stream object that redirects writes to a logger instance. """ def __init__(self, logger, log_level=logging.INFO): self.logger = logger self.log_level = log_level self.linebuf = '''' def write(self, buf): for line in buf.rstrip().splitlines(): self.logger.log(self.log_level, line.rstrip()) logging.basicConfig( level=logging.DEBUG, format=''%(asctime)s:%(levelname)s:%(name)s:%(message)s'', filename="out.log", filemode=''a'' ) stdout_logger = logging.getLogger(''STDOUT'') sl = StreamToLogger(stdout_logger, logging.INFO) sys.stdout = sl stderr_logger = logging.getLogger(''STDERR'') sl = StreamToLogger(stderr_logger, logging.ERROR) sys.stderr = sl print "Test to standard out" raise Exception(''Test to standard error'')

La salida se ve como:

2011-08-14 14:46:20,573:INFO:STDOUT:Test to standard out 2011-08-14 14:46:20,573:ERROR:STDERR:Traceback (most recent call last): 2011-08-14 14:46:20,574:ERROR:STDERR: File "redirect.py", line 33, in 2011-08-14 14:46:20,574:ERROR:STDERR:raise Exception(''Test to standard error'') 2011-08-14 14:46:20,574:ERROR:STDERR:Exception 2011-08-14 14:46:20,574:ERROR:STDERR:: 2011-08-14 14:46:20,574:ERROR:STDERR:Test to standard error

Tenga en cuenta que self.linebuf = '''' es donde se maneja la descarga, en lugar de implementar una función de descarga.