Merging a Python script's subprocess' stdout and stderr while keeping them distinguishable

前端 未结 6 1751
轮回少年
轮回少年 2020-12-04 14:44

I would like to direct a python script\'s subprocess\' stdout and stdin into the same file. What I don\'t know is how to make the lines from the two sources distinguishable?

6条回答
  •  天命终不由人
    2020-12-04 15:17

    I found myself having to tackle this problem recently, and it took a while to get something I felt worked correctly in most cases, so here it is! (It also has the nice side effect of processing the output via a python logger, which I've noticed is another common question here on Stackoverflow).

    Here is the code:

    import sys
    import logging
    import subprocess
    from threading import Thread
    
    logging.basicConfig(stream=sys.stdout,level=logging.INFO)
    logging.addLevelName(logging.INFO+2,'STDERR')
    logging.addLevelName(logging.INFO+1,'STDOUT')
    logger = logging.getLogger('root')
    
    pobj = subprocess.Popen(['python','-c','print 42;bargle'], 
        stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    
    def logstream(stream,loggercb):
        while True:
            out = stream.readline()
            if out:
                loggercb(out.rstrip())       
            else:
                break
    
    stdout_thread = Thread(target=logstream,
        args=(pobj.stdout,lambda s: logger.log(logging.INFO+1,s)))
    
    stderr_thread = Thread(target=logstream,
        args=(pobj.stderr,lambda s: logger.log(logging.INFO+2,s)))
    
    stdout_thread.start()
    stderr_thread.start()
    
    while stdout_thread.isAlive() and stderr_thread.isAlive():
         pass
    

    Here is the output:

    STDOUT:root:42
    STDERR:root:Traceback (most recent call last):
    STDERR:root:  File "", line 1, in 
    STDERR:root:NameError: name 'bargle' is not defined
    

    You can replace the subprocess call to do whatever you want, I just chose running python with a command that I knew would print to both stdout and stderr. The key bit is reading stderr and stdout each in a separate thread. Otherwise you may be blocking on reading one while there is data ready to be read on the other.

提交回复
热议问题