我有几个带有自己线程的进程都正在写入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.stdout,sys.__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)