2013-06-20 49 views
0

使用記錄器打印出stdout和stderr來記錄文件。我已經做到了這一點:在使用記錄器時在stderr文件中打印stdout

def log(process): 

    logger = logging.getLogger('logging_errors') 
    if not len(logger.handlers): 
     logger.setLevel(logging.DEBUG) 
     formatter = logging.Formatter('%(levelname)s %(asctime)s %(module)s %(message)s') 

     handler_stderr = logging.FileHandler('stderr.log') 
     handler_stderr.setLevel(logging.WARNING) 
     handler_stderr.setFormatter(formatter) 
     logger.addHandler(handler_stderr) 

     handler_stdout = logging.FileHandler('stdout.log') 
     handler_stdout.setLevel(logging.DEBUG) 
     handler_stdout.setFormatter(formatter) 
     logger.addHandler(handler_stdout) 
    return logger.error(process.stderr.read()) 
    return logger.info(process.stdout.read()) 

的處理被傳遞到這個功能,可以是這樣的:

proc = subprocess.Popen(['FastTree -nt test.fasta'], stdin = None, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell=True) 
proc.wait() 
log(proc) 

我的問題是,標準輸出沒有得到打印到標準輸出。日誌文件,我在stdout.log文件中得到stderr。 stderr.log文件是正確的。任何關於這個的指針?

回答

2

你有

return logger.error(process.stderr.read()) 
return logger.info(process.stdout.read()) 

第二return說法沒有得到執行,所以進程的stdout從未記錄。從這些語句中刪除return,你會發現輸出出現在stdout.log

你得到stderr輸出在stdout.log因爲所有記錄的事件都傳遞給這兩個處理程序。

+0

我這樣做,我確實得到了正確的標準輸出,但它只運行一個進程。我添加了一個額外的過程,但它忽略了它。 – bioinf80

0

,你可以創建了兩個記錄器,一個用於標準輸出,另一個用於標準錯誤,但你會寫

info_logger.info(out) 
error_logger.error(err) 

這是重複的,因爲你必須同時選擇合適的記錄儀和相應的水平當它們都包含基本相同的信息時。

所以,我們可以得到一些小鴿友,並使用robert's LevelFilter創建一個具有兩個過濾處理程序的記錄器。每個處理器都有一個過濾器,只接受的LogRecords其級別小於或等於end_level

handler.addFilter(LevelFilter(end_level)) 

同時,聲明

handler.setLevel(begin_level) 

導致handler只接受那些將LogRecords其水平更高比begin_level。結合起來,我們有一個處理程序只接受那些級別在begin_levelend_level之間的LogRecords。因此,您可以讓一個處理程序處理DEBUG和INFO LogRecords,併爲WARNING,ERROR和CRITICAL LogRecords創建第二個處理程序。

全部放在一起,你可以使用這樣的事情:

import logging 
import subprocess 

class LevelFilter(logging.Filter): 
    """ 
    https://stackoverflow.com/a/7447596/190597 (robert) 
    """ 
    def __init__(self, level): 
     self.level = level 

    def filter(self, record): 
     return record.levelno <= self.level 

def splitlevel_logger(name, outpath='stderr.log', errpath='stdout.log', 
         fmt='%(levelname)s %(asctime)s %(module)s %(message)s'): 
    formatter = logging.Formatter(fmt) 
    logger = logging.getLogger() 
    logger.setLevel(logging.DEBUG) 
    for filename, begin_level, end_level in (
      (outpath, logging.WARNING, logging.CRITICAL), 
      (errpath, logging.DEBUG, logging.INFO)): 
     handler = logging.FileHandler(filename, 'w') 
     handler.setLevel(begin_level) 
     handler.addFilter(LevelFilter(end_level)) 
     handler.setFormatter(formatter) 
     logger.addHandler(handler) 
    return logger 

def log(out='', err=''): 
    if out: 
     logger.info(out) 
    if err: 
     logger.error(err) 

logger = splitlevel_logger(__name__) 
cmd = 'FastTree -nt test.fasta' 
proc = subprocess.Popen(cmd, 
         stdout = subprocess.PIPE, 
         stderr = subprocess.PIPE, shell=True) 
log(*proc.communicate()) 

順便說一句,請注意關於subprocess.Popen.wait警告:

警告

[POPEN。等待]將使用stdout = PIPE和/或stderr = PIPE時發生死鎖,並且子進程生成en只需輸出到管道,以阻止 等待OS管道緩衝區接受更多數據。使用溝通() 來避免這一點。

因此,在上述情況下使用Popen.wait可能會有問題。使用Popen.communicate可以避免此問題。 或者,如果您想讀取並記錄從子流程輸出的輸出(而不是僅在子流程完成後才接收)use threadingselect.select

相關問題