2010-02-25 3 views
34

subprocess.Popen으로 많은 장기 실행 프로세스를 시작해야하며 각각 stdoutstderr을 자동으로 파이프하여 개별 로그 파일로 분리하려고합니다. 각 프로세스는 몇 분 동안 동시에 실행되며 프로세스가 실행될 때 두 개의 로그 파일 (stdoutstderr) 을 프로세스에 기록합니다. 서브 프로세스의 파이핑 출력

내가 지속적으로 각 로그 파일을 업데이트하기 위해 루프에서 각 프로세스에 p.communicate()를 호출해야합니까, 또는 stdoutstderr 자동으로 파일 핸들을 열 스트리밍되도록 원래 Popen 명령을 호출하는 몇 가지 방법은 무엇입니까?

답변

34

the docs 당을 위해 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) 

표준 입력, 표준 출력을 매개 변수로 stdoutstderr를 전달할 수 및 stderr는 실행 프로그램을 '지정 표준 입력, 표준 출력과 표준 오류 파일 핸들이 각각 있습니다. 유효한 값은 PIPE, 기존 파일 설명 자 (양의 정수), 기존 파일 오브젝트 및 없음입니다.

그래서 그냥 통과 오픈에 대한 쓰기를 명명 된 인수 stdout=stderr=로 파일 객체를 당신이 잘해야합니다!

+0

감사합니다. 나는 전에 그것을 시도하고 오류가 있다는 것을 맹세 할 수 있었지만 그것은 정확하게 내가 기대했던 것입니다. –

+0

그건 나를 위해 작동하지 않습니다. 두 프로세스를 동시에 실행하고 stdout과 stderr를 둘 다 하나의 로그 파일로 저장합니다. 출력이 너무 커지면 하위 프로세스 중 하나가 중단됩니다. 어느 쪽인지 모르겠다. 코멘트에 서식을 사용할 수 없으므로 아래에 "답변"을 추가하겠습니다. – jasper77

53

당신은, 예를

>>> 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! 나는 컨텍스트 관리자 (context manager)에서'열린 (open) '체인을 만들 수 있는지 전혀 몰랐다. #mindblown – hwjp

+0

나를 위해 작동하지 않습니다! 'with open ("server.log", "wb") out : sp.call (server_cmd, stdout = out)' – Ayush

2

동시에 두 개의 하위 프로세스를 실행하고 두 프로세스의 출력을 단일 로그 파일에 저장합니다. 또한 걸린 서브 프로세스를 처리하기위한 타임 아웃을 구축했습니다. 출력이 너무 커지면 시간 초과가 항상 트리거되고 하위 프로세스의 stdout은 로그 파일에 저장되지 않습니다. 위의 Alex에 의해 제기 된 대답은 그것을 해결하지 못합니다.

# 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()