2010-02-25 16 views
34

Ho bisogno di avviare una serie di processi di lunga durata con subprocess.Popen, e vorrei avere il stdout e stderr da ogni piped automaticamente per separare i file di registro. Ogni processo verrà eseguito contemporaneamente per diversi minuti e desidero scrivere due file di registro (stdout e stderr) per processo durante l'esecuzione dei processi.output di piping di sottoprocesso.Popen a file

Devo chiamare continuamente p.communicate() su ogni processo in un ciclo al fine di aggiornare ogni file di log, o c'è qualche modo per richiamare il comando originale Popen in modo che stdout e stderr sono in streaming automaticamente per aprire handle di file?

risposta

34

Per the docs,

stdin, stdout e stderr precisare le programmi eseguiti ingresso standard, output standard e errore standard handle di file, rispettivamente. I valori validi sono PIPE, un file esistente descrittore (un numero intero positivo), un oggetto file esistente e Nessuno.

Quindi, solo passare l'open-per-scrittura di oggetti di file come argomenti con nome e stdout=stderr= e si dovrebbe andare bene!

+0

Grazie. Avrei potuto giurare di averlo provato prima e ho avuto un errore, ma è esattamente quello che speravo funzionasse. –

+0

Questo non funziona per me. Sono contemporaneamente in esecuzione due processi e salvo lo stdout e lo stderr da entrambi in un unico file di registro. Se l'output diventa troppo grande, uno dei subprocessi si blocca; non so quale. Non riesco a utilizzare la formattazione in un commento, quindi aggiungerò una "risposta" di seguito. – jasper77

53

È possibile passare stdout e stderr come parametri per Popen()

subprocess.Popen(self, args, bufsize=0, executable=None, stdin=None, stdout=None, 
       stderr=None, preexec_fn=None, close_fds=False, shell=False, 
       cwd=None, env=None, universal_newlines=False, startupinfo=None, 
       creationflags=0) 

Per esempio

>>> import subprocess 
>>> with open("stdout.txt","wb") as out, open("stderr.txt","wb") as err: 
... subprocess.Popen("ls",stdout=out,stderr=err) 
... 
<subprocess.Popen object at 0xa3519ec> 
>>> 
+3

Woa! Non avevo idea che potessi concatenare 'open's come quello in un gestore di contesto. #mindblown – hwjp

+0

Non funziona per me! 'con aperto (" server.log "," wb ") come fuori: sp.call (server_cmd, stdout = out)' – Ayush

2

Sono contemporaneamente in esecuzione due sottoprocessi e il salvataggio dell'output da entrambi in un singolo file di registro. Ho anche creato un timeout per gestire i sottoprocessi appesi. Quando l'output diventa troppo grande, il timeout si attiva sempre e nessuno dello stdout di entrambi i processi secondari viene salvato nel file di registro. La risposta posta da Alex sopra non lo risolve.

# Currently open log file. 
log = None 

# If we send stdout to subprocess.PIPE, the tests with lots of output fill up the pipe and 
# make the script hang. So, write the subprocess's stdout directly to the log file. 
def run(cmd, logfile): 
    #print os.getcwd() 
    #print ("Running test: %s" % cmd) 
    global log 
    p = subprocess.Popen(cmd, shell=True, universal_newlines = True, stderr=subprocess.STDOUT, stdout=logfile) 
    log = logfile 
    return p 


# To make a subprocess capable of timing out 
class Alarm(Exception): 
    pass 

def alarm_handler(signum, frame): 
    log.flush() 
    raise Alarm 


#### 
## This function runs a given command with the given flags, and records the 
## results in a log file. 
#### 
def runTest(cmd_path, flags, name): 

    log = open(name, 'w') 

    print >> log, "header" 
    log.flush() 

    cmd1_ret = run(cmd_path + "command1 " + flags, log) 
    log.flush() 
    cmd2_ret = run(cmd_path + "command2", log) 
    #log.flush() 
    sys.stdout.flush() 

    start_timer = time.time() # time how long this took to finish 

    signal.signal(signal.SIGALRM, alarm_handler) 
    signal.alarm(5) #seconds 

    try: 
    cmd1_ret.communicate() 

    except Alarm: 
    print "myScript.py: Oops, taking too long!" 
    kill_string = ("kill -9 %d" % cmd1_ret.pid) 
    os.system(kill_string) 
    kill_string = ("kill -9 %d" % cmd2_ret.pid) 
    os.system(kill_string) 
    #sys.exit() 

    end_timer = time.time() 
    print >> log, "closing message" 

    log.close()