2012-12-17 77 views
5

我正在編寫一個研究工具,最近我從使用「打印」語句切換到使用Python內置的記錄器功能。我推斷,這樣可以讓用戶選擇將輸出轉儲到文件,並將其轉儲到屏幕上。從外部應用程序記錄

到目前爲止這麼好。我在Python中的部分代碼使用「logger.info」和「logger.error」轉儲到屏幕和文件。 「記錄器」是模塊範圍的記錄器。這部分工作就像一個魅力。

但是,在幾個地方,我使用「subprocess.call」通過shell運行可執行文件。所以在整個代碼,我有這樣

proc = subprocess.call(command) 

行此命令的輸出將打印到屏幕上,一如既往,但它不會轉儲到用戶指定的文件。

一個可能的辦法是打開一個管道文件:

proc = subprocess.call(command, stdout=f, stderr=subprocess.OUTPUT) 

但這隻會轉儲到文件,而不是到屏幕上。

基本上,我的問題歸結爲:有沒有一種方法可以利用我現有的記錄器,而無需爲專門用於subprocess.call的文件構造另一個處理程序? (也許通過將輸出重定向到記錄器?)或者,根據當前的設置,這是不可能的?如果是後者,我該如何改進設置?

(哦也,這將是巨大的,如果日誌記錄是在「實時」,這樣從可執行的消息,因爲他們收到的記錄。)

感謝您的幫助! :)

+1

Lennart Regebro的[StreamLogger類](http://stackoverflow.com/a/4838875/190597)將在您的情況下很好地工作。 – unutbu

+0

感謝您的參考!這對我的情況非常有用。 –

回答

3

而不是管道stdout到一個文件,你可以管它到一個PIPE,然後從該PIPE讀取並寫入記錄器。事情是這樣的:

proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.OUTPUT) 
for line in proc.stdout: 
    logging.info(line) 

但是,還有一個更簡單的答案是:你必須使用一個類文件對象與文件句柄,但您可以創建一個在穿過每行logging管的頂部。你可以自己寫這個對象,但是,@unutbu說,有人已經在this question中完成了它。所以:

with StreamLogger(logging.INFO) as out: 
    proc = subprocess.call(command, stdout=out, stderr=subprocess.OUTPUT) 

當然,你也可以暫時換stdout寫入記錄儀和剛剛經歷過的輸出,例如,使用this confusingly identically-named class

with StreamLogger('stdout'): 
    proc = subprocess.call(command, stderr=subprocess.OUTPUT) 
+0

感謝您參考上一個鏈接中的代碼。這是一個有趣的閱讀。 –

3

unutbu's comment好;你應該看看Lennart's answer

你需要的是類似的tee的功能,但subprocess模塊工作在OS手柄的水平,這意味着由子進程寫入的數據無法通過Python代碼可以看出,說一些文件 - 像你寫的東西,它會記錄和打印寫入它的任何東西。

除了使用Lennart的回答,你可以使用第三方庫如sarge(披露:我是它的維護者)做這種事情。它不僅適用於日誌記錄。假設你有一個生成的輸出,如程序:

# echotest.py 
import time 
for i in range(10): 
    print('Message %d' % (i + 1)) 

,你想捕捉它在你的腳本,日誌,並將其打印到屏幕:

#subptest.py 
from sarge import capture_stdout 
import logging 
import sys 

logging.basicConfig(filename='subptest.log', filemode='w', 
        level=logging.INFO) 

p = capture_stdout('python echotest.py', async=True) 
while True: 
    line = p.stdout.readline() 
    line = line.strip() 
    # depending on how the child process generates output, 
    # sometimes you won't see anything for a bit. Hence only print and log 
    # if you get something 
    if line: 
     print(line) 
     logging.info(line) 

    # Check to see when we can stop - after the child is done. 
    # The return code will be set to the value of the child's exit code, 
    # so it won't be None any more. 

    rc = p.commands[0].process.poll() 
    # if no more output and subprocess is done, break 
    if not line and rc is not None: 
     break 

如果你運行上面的腳本,你就會得到打印到控制檯:

$ python subptest.py 
Message 1 
Message 2 
Message 3 
Message 4 
Message 5 
Message 6 
Message 7 
Message 8 
Message 9 
Message 10 

當我們檢查日誌文件中,我們看到:

$ cat subptest.log 
INFO:root:Message 1 
INFO:root:Message 2 
INFO:root:Message 3 
INFO:root:Message 4 
INFO:root:Message 5 
INFO:root:Message 6 
INFO:root:Message 7 
INFO:root:Message 8 
INFO:root:Message 9 
INFO:root:Message 10 
+0

感謝您的提示! :) –