Python 子进程 - 过滤掉日志记录 [英] Python Subprocess - filter out logging

查看:73
本文介绍了Python 子进程 - 过滤掉日志记录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Python 3.6

我想从我使用 subprocess 模块运行的子进程中获取所有输入.我可以轻松地将此输出通过管道传输到日志文件,而且效果很好.

I want to take all input from a subprocess which I run with the subprocess module. I can easily pipe this output to a log file, and it works great.

但是,我想过滤掉很多行(来自我无法控制的模块的大量嘈杂输出).

But, I want to filter out a lot of the lines (lots of noisy output from modules I do not control).

def run_command(command, log_file):
    process = subprocess.Popen(command, stdout=subprocess.PIPE,
                               stderr=subprocess.STDOUT, bufsize=1,
                               universal_newlines=True)
    while True:
        output = process.stdout.readline()
        if output == '' and process.poll() is not None:
            break
        if output and not_noisy_line(output):
            log_file.write(output)
            log_file.flush()
    return process.poll()

但这在我的子进程和输出之间引入了竞争条件.

But this introduced a race condition between my subprocess and the output.

我创建了一个新方法和一个类来包装日志记录.

I created a new method and a class to wrap the logging.

def run_command(command, log_file):
    process = subprocess.run(command, stdout=QuiteLogger(log_file), stderr=QuiteLogger(log_file), timeout=120)
    return process.returncode

class QuiteLogger(io.TextIOWrapper):
    def write(self, data, encoding=sys.getdefaultencoding()):
        data = filter(data)
        super().write(data)

然而,这只是完全跳过了我的过滤器功能,我的 write 方法根本没有被子进程调用.(如果我调用 QuietLogger().write('asdasdsa') 它会通过过滤器)

This does however just completely skip my filter function, my write method is not called at all by the subprocess. (If I call QuietLogger().write('asdasdsa') it goes through the filters)

有什么线索吗?

推荐答案

这是一个有趣的情况,其中文件对象抽象部分崩溃.您的解决方案不起作用的原因是 subprocess 实际上并未使用您的 QuietLogger 而是从中获取原始文件号(然后将其重新打包为 io.TextIOWrapper 对象).

This is an interesting situation in which the file object abstraction partially breaks down. The reason your solution does not work, is because subprocess is not actually using your QuietLogger but is getting the raw file number out of it (then repackaging it as a io.TextIOWrapper object).

我不知道这是否是 subprocess 处理方式的内在限制,依赖于操作系统支持,或者这是否只是 Python 设计中的一个错误,但为了实现你想要什么,你需要使用标准的 subprocess.PIPE 然后滚动你自己的文件编写器.

I don't know if this is an intrinsic limitation in how the subprocess is handled, relying on OS support, or if this is just a mistake in the Python design, but in order to achieve what you want, you need to use the standard subprocess.PIPE and then roll your own file writer.

如果你可以等待子进程完成,那么它可以很容易地完成,使用 subprocess.run 然后从 CompletedProcess (<代码>p) 对象:

If you can wait for the subprocess to finish, then it can be trivially done, using the subprocess.run and then picking the stream out of the CompletedProcess (p) object:

p = subprocess.run(command, stdout=subprocess.PIPE, universal_newlines=True)

data = filter(p.stdout)

with open(logfile, 'w') as f:
    f.write(data)

如果您必须在生成时处理输出(因此,您不能等待 subprocess 结束),最简单的方法是求助于 subprocess.Popen 和线程:

If you must work with the ouput while it is being generated (thus, you cannot wait for the subprocess to end) the simplest way is to resort to subprocess.Popen and threads:

import subprocess
import threading

logfile ='tmp.txt'
filter_passed = lambda line: line[:3] != 'Bad'
command = ['my_cmd', 'arg']

def writer(p, logfile):
    with open(logfile, 'w') as f:
        for line in p.stdout:
            if filter_passed(line):
                f.write(line)

p = subprocess.Popen(command, stdout=subprocess.PIPE, universal_newlines=True)

t = threading.Thread(target=writer, args=(p,logfile))
t.start()

t.join()

这篇关于Python 子进程 - 过滤掉日志记录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆