将subprocess.Popen的stdout和stderr发送到logging模块

4
我想使用Python的subprocess.Popen启动一个应用程序,并将应用程序的stdout和stderr输出发送到日志记录模块,以便每次应用程序向stdout/stderr发送某些内容/某些行时,它会显示为logging.INFO("This is whats in stdout")。由于该应用程序是一个守护进程,因此它不会(也不应该)终止。有没有一种简单的方法来实现这个目标,或者我必须经常使用一个单独的线程来检查进程输出?
3个回答

5

以下是我从j-f-sebastian的回答中整理出来的可重用类:

import subprocess
from threading import Thread

class BackgroundPopen(subprocess.Popen):
    @staticmethod
    def prefix_handler(prefix, io):
        return lambda line: io.write(prefix + line)

    @staticmethod
    def _proxy_lines(pipe, handler):
        with pipe:
            for line in pipe:
                handler(line)

    def __init__(self, out_handler, err_handler, *args, **kwargs):
        kwargs['stdout'] = subprocess.PIPE
        kwargs['stderr'] = subprocess.PIPE
        super(self.__class__, self).__init__(*args, **kwargs)
        Thread(target=self._proxy_lines, args=[self.stdout, out_handler]).start()
        Thread(target=self._proxy_lines, args=[self.stderr, err_handler]).start()

1
在这个例子中,prefix_handler 是一个可能的 out_handlererr_handler 的示例;它不会覆盖 subprocess.Popen 中的任何内容,因此可以安全地省略。 - artoonie

4

线程是一种简单且便携的消费输出的方式(未经测试):

#!/usr/bin/env python
import logging
from subprocess Popen, PIPE, STDOUT
from threading import Thread

def consume_lines(pipe, consume):
    with pipe:
        for line in iter(pipe.readline, b''): #NOTE: workaround read-ahead bug
            consume(line)

logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s')
consume = lambda line: logging.info('this is whats in the output: %r', line)

process = Popen(command, stdout=PIPE, stderr=STDOUT, bufsize=1)
Thread(target=consume_lines, args=[process.stdout, consume]).start()
process.wait()

3

根据我的经验,单独的线程是可行的方法。这就是我 sarge 库使用的方式 - 它在底层使用线程来捕获子进程的输出。实际上,除非我在 subprocess.Popen 调用中合并两个输出流,否则我通常会使用两个线程(一个用于 stdout,一个用于 stderr)。


这个答案如果能提供一个代码示例会更好(我知道链接的页面上有一个)。 - Superbest
还有一种使用非阻塞流的替代方法,只需在主线程中捕获它,同时等待子进程完成:https://dev59.com/hF_Va4cB1Zd3GeqPYvnM#9115366。你认为这种方法与线程的想法相比如何? - CMCDragonkai
@CMCDragonkai 那个例子使用了 select,所以对于 Windows 不是最理想的选择。 - Vinay Sajip

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接