Redirect Python 'print' output to Logger

前端 未结 7 1878
北荒
北荒 2020-12-02 17:31

I have a Python script that makes use of \'Print\' for printing to stdout. I\'ve recently added logging via Python Logger and would like to make it so these print statement

7条回答
  •  温柔的废话
    2020-12-02 17:40

    One more method is to wrap the logger in an object that translates calls to write to the logger's log method.

    Ferry Boender does just this, provided under the GPL license in a post on his website. The code below is based on this but solves two issues with the original:

    1. The class doesn't implement the flush method which is called when the program exits.
    2. The class doesn't buffer the writes on newline as io.TextIOWrapper objects are supposed to which results in newlines at odd points.
    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):
            temp_linebuf = self.linebuf + buf
            self.linebuf = ''
            for line in temp_linebuf.splitlines(True):
                # From the io.TextIOWrapper docs:
                #   On output, if newline is None, any '\n' characters written
                #   are translated to the system default line separator.
                # By default sys.stdout.write() expects '\n' newlines and then
                # translates them so this is still cross platform.
                if line[-1] == '\n':
                    self.logger.log(self.log_level, line.rstrip())
                else:
                    self.linebuf += line
    
        def flush(self):
            if self.linebuf != '':
                self.logger.log(self.log_level, self.linebuf.rstrip())
            self.linebuf = ''
    
    
    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
    
    

    This allows you to easily route all output to a logger of your choice. If needed, you can save sys.stdout and/or sys.stderr as mentioned by others in this thread before replacing it if you need to restore it later.

提交回复
热议问题