编辑:由于似乎没有解决方案,或者我正在做一些人都不知道的非标准操作-我将修订我的问题,并问:当python应用正在制作日志时,完成记录的最佳方法是什么?很多系统调用?
我的应用程序有两种模式。在交互模式下,我希望所有输出都转到屏幕以及日志文件中,包括所有系统调用的输出。在守护程序模式下,所有输出进入日志。守护程序模式使用时效果很好os.dup2()。我找不到在不修改每个系统调用的情况下以交互方式将所有输出“发送”到日志的方法。
os.dup2()
换句话说,我想要python应用程序生成的任何输出(包括系统调用output)的命令行“ tee”的功能。
澄清:
要重定向所有输出,我可以执行以下操作,并且效果很好:
# 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命令,因此不必分别处理它们的每个输出也很不错。
简而言之,除了复制而不是重定向外,我想做同样的事情。
乍一想,我认为简单地反转即可dup2。为什么不呢?这是我的测试:
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”应与屏幕上显示的相同。
由于你很习惯从代码中生成外部进程,因此可以使用tee它本身。我不知道有什么Unix系统调用可以完全做到这tee一点。
# 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)
你还可以tee使用多处理程序包进行仿真(如果使用的是Python 2.5或更早版本,则可以使用处理程序)。
tee
更新资料
这是与Python 3.3+兼容的版本:
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)
我之前也遇到过同样的问题,发现此片段非常有用:
class Tee(object): def __init__(self, name, mode): self.file = open(name, mode) self.stdout = sys.stdout sys.stdout = self def __del__(self): sys.stdout = self.stdout self.file.close() def write(self, data): self.file.write(data) self.stdout.write(data) def flush(self): self.file.flush()