仅将特定线程的标准输出重定向到文件

ATO*_*TOA 7 python stdout

我有几个带有自己线程的进程都正在写入stdout,我对此很满意。现在,我必须添加另一个线程,该线程将向标准输出转储大量垃圾,我不希望这样做。

有什么方法可以将stdout单个线程的重定向到文件?

更新资料

owobeid所述,我尝试了此操作...我将重定向stderr到文件...

def startServer():
    fd = os.open("foo.txt", os.O_RDWR|os.O_CREAT )
    fd2 = 2
    os.dup2(fd, fd2)

    # rest of the code

if __name__ == '__main__':
    threading.Thread(target=startServer).start()
    raise Exception("My Exception")
Run Code Online (Sandbox Code Playgroud)

问题:stderr整个应用程序都被重定向。即使Exception消息也被重定向到文件中,即使它在线程之外。

小智 5

我在寻找一种可以做到这一点的方法时偶然发现了这篇文章。我想制作一个交互式Python控制台,该控制台使用ajax将请求代理到服务器,并仅返回正在执行的线程的所有输出。我最终弄清楚了,想分享我的解决方案。

werkzeugpython库随附一个类,该类local.LocalProxy可以使模块级函数的行为类似于属性。例如,这将使sys.stdout行为完全正常,但将通过LocalProxy类进行代理。

import sys
import werkzeug
sys.stdout = werkzeug.local.LocalProxy(lambda: sys.stdout)
Run Code Online (Sandbox Code Playgroud)

对此进行扩展,然后我编写了一个函数来代替lambda上面的StringIO对象(如果它是另一个线程):

import threading
import sys
import cStringIO
import werkzeug

thread_proxies = {}
def redirect():
    ident = threading.currentThread().ident
    thread_proxies[ident] = cStringIO.StringIO()
    return thread_proxies[ident]

def proxy():
    ident = threading.currentThread().ident
    return thread_proxies.get(ident, sys.stdout)

sys.stdout = werkzeug.local.LocalProxy(proxy)
Run Code Online (Sandbox Code Playgroud)

然后在我要重定向的任何线程中,我都可以调用:

string_io = redirect()
Run Code Online (Sandbox Code Playgroud)

现在所有要输出的内容sys.stdout现在都写入了StringIO对象。


可是等等!我需要捕捉sys.stdoutsys.__stdout__sys.stderr,和sys.__stderr__,所以我写了这个库,我叫stdout_helpers我的代码库:

import threading
import sys
import cStringIO
from werkzeug import local

# Save all of the objects for use later.
orig___stdout__ = sys.__stdout__
orig___stderr__ = sys.__stderr__
orig_stdout = sys.stdout
orig_stderr = sys.stderr
thread_proxies = {}


def redirect():
    """
    Enables the redirect for the current thread's output to a single cStringIO
    object and returns the object.

    :return: The StringIO object.
    :rtype: ``cStringIO.StringIO``
    """
    # Get the current thread's identity.
    ident = threading.currentThread().ident

    # Enable the redirect and return the cStringIO object.
    thread_proxies[ident] = cStringIO.StringIO()
    return thread_proxies[ident]


def stop_redirect():
    """
    Enables the redirect for the current thread's output to a single cStringIO
    object and returns the object.

    :return: The final string value.
    :rtype: ``str``
    """
    # Get the current thread's identity.
    ident = threading.currentThread().ident

    # Only act on proxied threads.
    if ident not in thread_proxies:
        return

    # Read the value, close/remove the buffer, and return the value.
    retval = thread_proxies[ident].getvalue()
    thread_proxies[ident].close()
    del thread_proxies[ident]
    return retval


def _get_stream(original):
    """
    Returns the inner function for use in the LocalProxy object.

    :param original: The stream to be returned if thread is not proxied.
    :type original: ``file``
    :return: The inner function for use in the LocalProxy object.
    :rtype: ``function``
    """
    def proxy():
        """
        Returns the original stream if the current thread is not proxied,
        otherwise we return the proxied item.

        :return: The stream object for the current thread.
        :rtype: ``file``
        """
        # Get the current thread's identity.
        ident = threading.currentThread().ident

        # Return the proxy, otherwise return the original.
        return thread_proxies.get(ident, original)

    # Return the inner function.
    return proxy


def enable_proxy():
    """
    Overwrites __stdout__, __stderr__, stdout, and stderr with the proxied
    objects.
    """
    sys.__stdout__ = local.LocalProxy(_get_stream(sys.__stdout__))
    sys.__stderr__ = local.LocalProxy(_get_stream(sys.__stderr__))
    sys.stdout = local.LocalProxy(_get_stream(sys.stdout))
    sys.stderr = local.LocalProxy(_get_stream(sys.stderr))


def disable_proxy():
    """
    Overwrites __stdout__, __stderr__, stdout, and stderr with the original
    objects.
    """
    sys.__stdout__ = orig___stdout__
    sys.__stderr__ = orig___stderr__
    sys.stdout = orig_stdout
    sys.stderr = orig_stderr
Run Code Online (Sandbox Code Playgroud)

现在,在我的应用程序启动时,我致电:

stdout_helpers.enable_proxy()
Run Code Online (Sandbox Code Playgroud)

现在我在任何线程中调用:

string_io = stdout_helpers.redirect()
Run Code Online (Sandbox Code Playgroud)


owo*_*eid -3

使用dup2将输出重定向到您选择的文件。将 fd 设置为文件描述符,将 fd2 设置为 1(stdout)。

注意:在生成的线程中执行此操作,而不是在主线程中。

  • 批准的答案无效。请参阅@umichscoots 提供的答案 (3认同)