45

我有一个 Python 脚本,它使用“打印”打印到标准输出。我最近通过 Python Logger 添加了日志记录,并希望这样做,如果启用了日志记录,这些打印语句将转到记录器。我不想修改或删除这些打印语句。

我可以通过执行'log.info(“some info msg”)'来记录。我希望能够做这样的事情:

if logging_enabled:
  sys.stdout=log.info
print("test")

如果启用了日志记录,则应该记录“test”,就像我做了 log.info("test") 一样。如果未启用日志记录,则应将“test”打印到屏幕上。

这可能吗?我知道我可以以类似的方式将标准输出定向到文件(请参阅:将打印重定向到日志文件

4

7 回答 7

37

你有两个选择:

  1. 打开一个日志文件并用它替换 sys.stdout,而不是一个函数:

    log = open("myprog.log", "a")
    sys.stdout = log
    
    >>> print("Hello")
    >>> # nothing is printed because it goes to the log file instead.
    
  2. 将 print 替换为您的日志功能:

    # If you're using python 2.x, uncomment the next line
    #from __future__ import print_function
    print = log.info
    
    >>> print("Hello!")
    >>> # nothing is printed because log.info is called instead of print
    
于 2012-06-20T16:44:20.227 回答
22

当然,您既可以打印到标准输出,也可以附加到日志文件,如下所示:

# Uncomment the line below for python 2.x
#from __future__ import print_function

import logging

logging.basicConfig(level=logging.INFO, format='%(message)s')
logger = logging.getLogger()
logger.addHandler(logging.FileHandler('test.log', 'a'))
print = logger.info

print('yo!')
于 2013-07-16T16:52:07.890 回答
21

另一种方法是将记录器包装在一个对象中,该对象将调用转换write为记录器的log方法。

Ferry Boender 就是这样做的,根据 GPL 许可其网站的帖子中提供。下面的代码基于此,但解决了原始代码的两个问题:

  1. 该类没有实现程序退出时调用的 flush 方法。
  2. 该类不会缓冲换行符上的写入,因为 io.TextIOWrapper 对象应该会在奇数点产生换行符。
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

这使您可以轻松地将所有输出路由到您选择的记录器。如果需要,如果您以后需要恢复它,您可以在替换它之前保存sys.stdout和/或按照其他人在此线程中提到的方法。sys.stderr

于 2016-03-29T22:27:06.237 回答
13

一个更简单的选择,

import logging, sys
logging.basicConfig(filename='path/to/logfile', level=logging.DEBUG)
logger = logging.getLogger()
sys.stderr.write = logger.error
sys.stdout.write = logger.info
于 2017-10-27T18:29:58.120 回答
2

你真的应该这样做:通过调整你的日志配置来使用print语句或其他东西,这取决于设置。不要覆盖print行为,因为将来可能引入的某些设置(例如,由您或其他人使用您的模块)可能实际上将其输出到stdout您将遇到问题。

有一个处理程序应该将您的日志消息重定向到正确的流(文件stdout或任何其他类似文件)。它被调用并与模块StreamHandler捆绑在一起。logging

所以基本上在我看来你应该做,你说你不想做的事情:print用实际的日志记录替换语句。

于 2012-06-20T16:54:58.097 回答
2

一旦你定义了你的记录器,即使有多个打印参数,也可以使用它来使打印重定向到记录器。

print = lambda *tup : logger.info(str(" ".join([str(x) for x in tup]))) 
于 2019-05-17T14:05:50.170 回答
0

下面的剪辑在我的 PySpark 代码中完美运行。如果有人需要以防万一理解-->

import os
import sys
import logging
import logging.handlers

log = logging.getLogger(__name_)

handler = logging.FileHandler("spam.log")
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler.setFormatter(formatter)
log.addHandler(handler)
sys.stderr.write = log.error 
sys.stdout.write = log.info 

(将在同一目录中的“spam.log”中记录每个错误,控制台/标准输出上不会有任何内容)

(将在同一目录中的“spam.log”中记录所有信息,控制台/标准输出上不会出现任何内容)

在两个文件以及控制台中打印输出错误/信息删除以上两行。

快乐编码干杯!!!

于 2019-10-12T03:10:36.207 回答