2012-01-15 13 views
7

Estoy escribiendo una clase contenedora para usar con un administrador de flujo de trabajo. Me gustaría iniciar sesión resultado de una aplicación (proceso hijo ejecuta a través de subprocess.Popen) de una manera determinada:¿Puedo dividir/fusionar flujos de salida del subproceso.Popen?

  • stdout del niño debe ir a un archivo de registro y para stdout de los padres,
  • stderr de la el niño debe ir a un archivo de registro diferente, pero también al stdout del padre.

I.e. todas las salidas desde el niño debe llegar a fusionó en stdout (como con subprocess.Popen(..., stderr=subprocess.STDOUT), por lo que se puede reservar stderr de mensajes de registro desde la propia envoltura. Por otro lado, las corrientes del niño deben ir a diferentes archivos para permitir la validación independiente.

He intentado utilizar una clase de ayuda "Tee" para unir dos flujos (stdout y el archivo de registro) juntos, de modo que Tee.write escribe en ambas transmisiones. Sin embargo, esto no se puede pasar a Popen porque "subproceso" usa funciones de nivel de sistema operativo para escribir (ver aquí: http://bugs.python.org/issue1631).

El problema con mi solución actual (fragmento de código a continuación, adaptado principalmente de here) es esa salida en stdout puede no aparecer en el orden correcto.

¿Cómo puedo superar esto? ¿O debería usar un enfoque completamente diferente? (Si me quedo con el código de abajo, ¿Cómo elegir un valor para el número de bytes en os.read?)

import subprocess, select, sys, os 

call = ... # set this 
process = subprocess.Popen(call, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
logs = {process.stdout: open("out.log", "w"), process.stderr: open("err.log", "w")} 
done = {process.stdout: False, process.stderr: False} 
while (process.poll() is None) or (not all(done.values())): 
    ready = select.select([process.stdout, process.stderr], [], [])[0] 
    for stream in ready: 
     data = os.read(stream.fileno(), 1) 
     if data: 
      sys.stdout.write(data) 
      logs[stream].write(data) 
     else: 
      done[stream] = True 
logs[process.stdout].close() 
logs[process.stderr].close() 

Por cierto, this solution usando "fcntl" no ha funcionado para mí. Y todavía no podía entender cómo adaptar this solution a mi caso, así que no lo he intentado.

Respuesta

1

Si establece shell=True, puede pasar una cadena de comandos para subproceso que incluye tuberías, redirecciones, y el tee command.

+0

Gracias. Después de analizarlo, algo como esto podría ser una solución: http://unix.stackexchange.com/a/6431 Sin embargo, todavía estaría interesado en una solución de Python. – Hendrik

Cuestiones relacionadas