问题描述
我用 C 实现了共享库,它提供了一个函数 F
。每次我调用 F
时,它都会将其输出记录在文件 error.log
中。
现在我正在尝试从 python 脚本中捕获 F
生成的输出(我使用的是 python 2.7.5,由于我无法控制的原因,我无法更改)。
我想将写入 error.log
的数据流式传输到其他文件或 stdout
。我不能只是打开文件并解析它,因为它登录了更多的东西,包括 F
之前和之后运行的输出。我只对特定的执行感兴趣,我无法仅从日志中识别出该执行。这就是我尝试捕获输出的原因。
我尝试从 python 打开 error.log
,然后更改文件描述符以使其指向 stdout
,但这似乎不起作用(我对 stdout
和stderr
并且确实有效)。
我做的大概是
with open('error.log') as logfile:
with redirect_output(logfile,sys.stdout):
function_implemented_in_C()
其中 redirect_output
是我为执行重定向而实现的上下文管理器:
@contextmanager
def redirect_output(orig,dest):
orig_fd = orig.fileno()
with os.fdopen(os.dup(orig_fd)) as old_orig_fd:
os.dup2(dest.fileno(),orig_fd)
try:
yield orig
finally:
# clean and restore fd's
我无法让它工作。知道我做错了什么吗?
更新:
我将问题简化为一个简单的脚本,但它似乎仍然不起作用。我猜这与从共享库 (?) 中的函数生成的数据有关,因为如果我执行相同操作但从从 python 打开的文件中重定向 write
调用,它可以工作。这个例子工作正常:
import sys
import os
def foo():
f = open('dummy.txt','wb',buffering=0)
os.dup2(sys.stdout.fileno(),f.fileno())
f.write('some test data\n')
f.close()
if __name__ == '__main__':
foo()
但这没有
import sys
import os
def foo():
f = open('error.log',f.fileno())
function_implemented_in_C()
f.close()
if __name__ == '__main__':
foo()
解决方法
我正在回答我自己的问题,以防有人遇到同样的问题。
这里的问题是在 error.log
中产生输出的 C 函数会启动一个不同的进程来执行任务。这使得无法轻松地将文件写入重定向到 stdout
,因为文件描述符是特定于进程的。
因此,如果您的函数碰巧使用相同的过程产生输出,那么以下应该可以工作
import sys
import os
def foo():
f = open('dummy.txt','wb',buffering=0)
os.dup2(sys.stdout.fileno(),f.fileno())
f.write('some test data\n')
f.close()
if __name__ == '__main__':
foo()
如果不是这种情况,那么您可以通过设置从文件中读取的循环来解决问题,以便获取新写入的数据。类似的东西(我没有尝试过这段代码,所以它无法运行):
from multiprocessing import Process,Pipe
def foo(filename,pipe_conn):
with open(filename) as f:
while True:
line = f.readline()
do_something(line)
if pipe_conn.poll(0.01):
break
def bar(pipe_conn):
function_implemented_in_C()
pipe_conn.send(['done'])
pipe_conn.close()
if __name__ == '__main__':
parent_conn,child_conn = Pipe()
p = Process(target=bar,args=(child_conn,))
p.start()
foo(parent_conn)
p.join()