如何将 sys.stdout 复制到日志文件? [英] How to duplicate sys.stdout to a log file?

查看:83
本文介绍了如何将 sys.stdout 复制到日志文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于似乎没有解决方案,或者我正在做一些没有人知道的非标准的事情 - 我将修改我的问题以询问:当 python 应用程序完成日志记录的最佳方法是什么是否进行了大量系统调用?

Since it appears that there's either no solution, or I'm doing something so non-standard that nobody knows - I'll revise my question to also ask: What is the best way to accomplish logging when a python app is making a lot of system calls?

我的应用有两种模式.在交互模式下,我希望所有输出都转到屏幕和日志文件,包括来自任何系统调用的输出.在守护进程模式下,所有输出都进入日志.守护进程模式使用 os.dup2() 效果很好.我无法找到一种在交互模式下将所有输出tee"到日志的方法,而无需修改每个系统调用.

My app has two modes. In interactive mode, I want all output to go to the screen as well as to a log file, including output from any system calls. In daemon mode, all output goes to the log. Daemon mode works great using os.dup2(). I can't find a way to "tee" all output to a log in interactive mode, without modifying each and every system call.

换句话说,我想要由 python 应用程序生成的任何输出的命令行tee"的功能,包括系统调用输出.

In other words, I want the functionality of the command line 'tee' for any output generated by a python app, including system call output.

澄清:

为了重定向所有输出,我做了这样的事情,而且效果很好:

To redirect all output I do something like this, and it works great:

# open our log file
so = se = open("%s.log" % self.name, 'w', 0)

# re-open stdout without buffering
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

# redirect stdout and stderr to the log file opened above
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())

这样做的好处是它不需要来自其余代码的特殊打印调用.该代码还运行一些 shell 命令,因此不必单独处理它们的每个输出也很好.

The nice thing about this is that it requires no special print calls from the rest of the code. The code also runs some shell commands, so it's nice not having to deal with each of their output individually as well.

简单地说,我想做同样的事情,除了复制而不是重定向.

Simply, I want to do the same, except duplicating instead of redirecting.

起初,我认为简单地反转 dup2 应该可以工作.为什么不呢?这是我的测试:

At first thought, I thought that simply reversing the dup2's should work. Why doesn't it? Here's my test:

import os, sys

### my broken solution:
so = se = open("a.log", 'w', 0)
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

os.dup2(sys.stdout.fileno(), so.fileno())
os.dup2(sys.stderr.fileno(), se.fileno())
###

print("foo bar")

os.spawnve("P_WAIT", "/bin/ls", ["/bin/ls"], {})
os.execve("/bin/ls", ["/bin/ls"], os.environ)

文件a.log"应该与屏幕上显示的相同.

The file "a.log" should be identical to what was displayed on the screen.

推荐答案

由于您习惯于从代码中生成外部进程,因此您可以使用 tee 本身.我不知道有任何 Unix 系统调用完全符合 tee 的作用.

Since you're comfortable spawning external processes from your code, you could use tee itself. I don't know of any Unix system calls that do exactly what tee does.

# Note this version was written circa Python 2.6, see below for
# an updated 3.3+-compatible version.
import subprocess, os, sys

# Unbuffer output (this ensures the output is in the correct order)
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

tee = subprocess.Popen(["tee", "log.txt"], stdin=subprocess.PIPE)
os.dup2(tee.stdin.fileno(), sys.stdout.fileno())
os.dup2(tee.stdin.fileno(), sys.stderr.fileno())

print "\nstdout"
print >>sys.stderr, "stderr"
os.spawnve("P_WAIT", "/bin/ls", ["/bin/ls"], {})
os.execve("/bin/ls", ["/bin/ls"], os.environ)

您还可以使用 multiprocessingtee> 包(如果您使用的是 Python 2.5 或更早版本,则使用 processing).

You could also emulate tee using the multiprocessing package (or use processing if you're using Python 2.5 or earlier).

更新

这是一个与 Python 3.3+ 兼容的版本:

Here is a Python 3.3+-compatible version:

import subprocess, os, sys

tee = subprocess.Popen(["tee", "log.txt"], stdin=subprocess.PIPE)
# Cause tee's stdin to get a copy of our stdin/stdout (as well as that
# of any child processes we spawn)
os.dup2(tee.stdin.fileno(), sys.stdout.fileno())
os.dup2(tee.stdin.fileno(), sys.stderr.fileno())

# The flush flag is needed to guarantee these lines are written before
# the two spawned /bin/ls processes emit any output
print("\nstdout", flush=True)
print("stderr", file=sys.stderr, flush=True)

# These child processes' stdin/stdout are 
os.spawnve("P_WAIT", "/bin/ls", ["/bin/ls"], {})
os.execve("/bin/ls", ["/bin/ls"], os.environ)

这篇关于如何将 sys.stdout 复制到日志文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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