将Python'print'输出重定向到Logger

时间:2012-06-20 16:35:32

标签: python logging stdout

我有一个Python脚本,它使用'Print'打印到stdout。我最近通过Python Logger添加了日志记录,并希望如果启用了日志记录,这些打印语句将转到logger。我不想修改或删除这些打印语句。

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

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

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

这可能吗?我知道我可以以类似的方式将stdout指向文件(参见:redirect prints to log file

7 个答案:

答案 0 :(得分:19)

您有两种选择:

  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. 用日志功能替换打印:

    # 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
    

答案 1 :(得分:9)

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

Ferry Boender在provided under the GPL license a posthis website中执行此操作https://studysoup.com/western-kentucky-university/econ-202/one-week-of-notes/econ-202-notes-week-9?id=864095

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

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

答案 2 :(得分:8)

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

# 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!')

答案 3 :(得分:4)

一个更简单的选项,

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

答案 4 :(得分:2)

您真的应该这样做:通过调整您的日志记录配置以使用print语句或其他方式,具体取决于设置。不要覆盖print行为,因为将来可能会引入的某些设置(例如,您或其他人使用您的模块)实际上可能会将其输出到stdout并且您将拥有问题。

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

所以基本上我认为你应该这样做,你说过你不想做的事:用实际的日志记录替换print语句。

答案 5 :(得分:1)

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

print = lambda *tup : logger.info(str(" ".join([str(x) for x in tup]))) 

答案 6 :(得分: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”中的每个错误记录在同一目录中,控制台/ stdout上将没有任何内容)

(将“ spam.log”中的所有信息记录在同一目录中,控制台/ stdout上将没有任何内容)

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

快乐编码 干杯!!!