我有一个cplusplus共享库,带有一个c接口,可以在stdout中写入日志条目.我在使用ctypes库的
python应用程序中使用它. python应用程序使用日志记录库来写入日志条目.
我需要做的是捕获共享库的stdout条目以使用日志记录模块写入日志条目.换句话说,我想将c库的stdout条目重定向到日志记录模块,因此我可以使用日志记录来使用其处理程序写入文件和控制台.
我发现可以捕获stdout(see this SO question),但只有当c模块调用结束时我才能访问它,因此它对于日志记录是无用的.我想要一种无阻塞的方式来访问stdout条目.
最小的例子如下.
module.cpp(使用g -fPIC -shared module.cpp -o module.so编译)
#include <unistd.h>
#include <iostream>
using namespace std;
extern "C" int callme()
{
cout<<"Hello world\n";
sleep(2);
cout<<"Some words\n";
sleep(2);
cout<<"Goodby world\n";
return 0;
}
调用它的python应用程序:
import ctypes as ct
import logging
format='%(asctime)s - %(levelname)s - %(message)s', level=logging.DEBUG
logging.basicConfig(format=format)
logging.debug('This logging modules works like a charm!')
mymodule = ct.CDLL('./module.so')
mymodule.callme()
logging.info('I want to capture the shared library log entries')
logging.warning('Can I?')
这会产生:
2016-02-04 16:16:35,976 - DEBUG - This logging modules works like a charm!
Hello world
Some words
Goodby world
2016-02-04 16:16:39,979 - INFO - I want to capture the shared library log entries
2016-02-04 16:16:39,979 - WARNING - Can I?
我可以访问c库,因此也欢迎需要在库中进行修改的解决方案.
最佳答案 您应该能够通过在C模块调用运行时从线程中的管道读取来修改链接答案中的代码.以下应该可以工作,虽然我还没有使用长时间运行的模块调用来测试它:
def redirected_printed_output(module_call):
# the pipe would fail for some reason if I didn't write to stdout at some point
# so I write a space, then backspace (will show as empty in a normal terminal)
sys.stdout.write(' \b')
pipe_out, pipe_in = os.pipe()
# save a copy of stdout
stdout = os.dup(1)
# replace stdout with our write pipe
os.dup2(pipe_in, 1)
# check if we have more to read from the pipe
def more_data():
r, _, _ = select.select([pipe_out], [], [], 0)
return bool(r)
# read the pipe, writing to (former) stdout
def write_pipe_to_stdout():
while more_data():
os.write(stdout, os.read(pipe_out, 1024))
done = False
def read_loop():
# rewrite the pipe out to stdout in a loop while the call is running
while not done:
write_pipe_to_stdout()
# Finish the remnants
write_pipe_to_stdout()
t = threading.Thread(target=read_loop)
t.start()
module_call()
done = True
t.join() # wait for the thread to finish
# put stdout back in place
os.dup2(stdout, 1)
我测试了它如下(OSX):
import ctypes
libc = ctypes.CDLL('libc.dylib')
def zomg():
for i in xrange(5):
libc.printf('libc stdout: %d\n', i)
time.sleep(1)
redirected_printed_output(zomg)