123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- # ------------------------------------------------
- # help
- # ------------------------------------------------
- """
- GO SubProcess - tools to call a subprocess in combination with logging
- Routines
- p = call( *popenargs )
- Call subprocess without logging.
- Returns an object with fields:
- retcode (integer)
- stdout (list of strings)
- stderr (list of strings)
- Raises a CallingError or StatusError on failure.
- p = log_call( *popenargs, logger=None, loglevel=0 )
- Call subprocess. After process is terminated, send the standard output
- and standard error to the logger. If no logger instance is applied,
- a standard logger to created. The standard output is written with
- loglevel logging.INFO or the level specified as argument ;
- the standard error is written with loggin.DEBUG.
- Returns an object with fields:
- retcode (integer)
- stdout (list of strings)
- stderr (list of strings)
- Raises a CallingError or StatusError on failure.
- p = watch_call( *popenargs, logger=None, loglevel=0 )
- Call subprocess and send standard output to logger while running.
- Standard error is redirected to standard output to maintain the
- order in which lines are written as good as possible.
- See arguments of 'log_call' for the logging arguments.
- Returns an object with fields:
- retcode (integer)
- stdout (list of strings)
- stderr (list of strings; empty)
- Raises a CallingError or StatusError on failure.
-
- Exceptions
- CallingError
- Raised when a command could not be started at all.
- Attribute: command
- StatusError
- Raised when a non-zero exit status is received from a command.
- Attributes: command, returncode, stdout, stderr
- Example
- # external:
- import logging
- # run command, log outputs:
- p = log_call( ['/bin/ls','-l'] )
-
- # idem, but log outside call:
- try :
- p = call( ['/bin/ls','-l'] )
- except CallingError as err :
- logging.error( err )
- raise Exception
- except StatusError as err :
- for line in err.stderr : logging.error(line)
- logging.error( err )
- raise Exception
- except Exception as err :
- logging.error( 'unknown error : %s' % err )
- raise Exception
- #endtry
- # display output:
- for line in p.stdout : logging.info(line)
- for line in p.stderr : logging.error(line)
- """
- # ------------------------------------------------
- # exceptions
- # ------------------------------------------------
- class Error( Exception ):
- """
- Base class for exceptions in this module.
- """
- pass
- # *
- class CallingError( Error ) :
- """
- This exception is raised when an attempt to call a command fails.
- Attributes:
- command # str or str list
- """
- def __init__( self, command, strerror ) :
- """
- Store exception attributes.
- """
- # store:
- self.command = command
- self.strerror = strerror
-
- def __str__( self ) :
- """
- Format error message.
- """
- # error message:
- return 'Error from calling "%s" : %s' % (self.command,self.strerror)
-
- # *
- class StatusError( Error ) :
- """
- This exception is raised when a called command returns a non-zero exit status.
- Attributes:
- command # str or str list
- returncode # integer return status
- stdout # str list
- stderr # str list
- """
- def __init__( self, command, returncode, stdout, stderr ) :
- """
- Store exception attributes.
- """
- # store:
- self.command = command
- self.returncode = returncode
- self.stdout = stdout
- self.stderr = stderr
-
- def __str__( self ) :
- """
- Format error message.
- """
- # error message:
- return 'Call "%s" returned non-zero status %i' % (str(self.command),self.returncode)
- # ------------------------------------------------
- # routines
- # ------------------------------------------------
- class call( object ) :
- def __init__( self, command, **kwargs ) :
- """
- Call subprocess and return object with returncode, output, and error.
- """
- # external:
- import subprocess
-
- # call suprocess, catch calling errors:
- try:
- p = subprocess.Popen( command,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- universal_newlines=True,
- **kwargs )
- except Exception as err:
- raise CallingError( command, err )
- # wait for process to terminate, receive standard output and error:
- stdout_str,stderr_str = p.communicate()
-
- # store outputs as lists of lines
- self.stdout = stdout_str.strip('\n').split('\n')
- self.stderr = stderr_str.strip('\n').split('\n')
- # store return code:
- self.returncode = p.returncode
-
- # error ?
- if self.returncode != 0 : raise StatusError(command,self.returncode,self.stdout,self.stderr)
- # ok
- return
- # *
- class log_call( object ) :
- def __init__( self, command, logger=None, loglevel=None, **kwargs ) :
- """
- Call subprocess and send standard output and error to logger.
- """
- # external:
- import logging
- import sys
- import subprocess
-
- # tools:
- import go_logging
- # setup logger to standard output if not provided as argument:
- if logger == None : logger = go_logging.defaultLogger()
- # logging levels:
- errlevel = logging.ERROR
- outlevel = logging.INFO
- if loglevel != None : outlevel = loglevel
-
- # init outputs:
- self.stdout = []
- self.stderr = []
- # call suprocess, catch calling errors:
- try:
- p = subprocess.Popen( command,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- **kwargs )
- except Exception as err:
- logger.error( str(err) )
- raise CallingError( command, err )
- # wait for process to terminate, receive standard output and error:
- stdout_str,stderr_str = p.communicate()
-
- # store outputs as lists of lines
- self.stdout = stdout_str.strip('\n').split('\n')
- self.stderr = stderr_str.strip('\n').split('\n')
-
- # write standard output and error to logger:
- for line in self.stdout : logger.log( outlevel, line )
- for line in self.stderr : logger.log( errlevel, line )
- # store return code:
- self.returncode = p.returncode
-
- # error ?
- if self.returncode != 0 : raise StatusError(command,self.returncode,self.stdout,self.stderr)
- # ok
- return
- # *
- class watch_call( object ) :
- def __init__( self, command, logger=None, loglevel=0, **kwargs ) :
- """
- Call subprocess and send standard output to logger while running.
- Standard error is redirected to standard output to maintain the
- order in which lines are written as good as possible.
- """
- # external:
- import logging
- import sys
- import subprocess
-
- # tools:
- import go_logging
- # setup logger to standard output if not provided as argument:
- if logger == None : logger = go_logging.defaultLogger()
- # logging levels:
- errlevel = logging.ERROR
- outlevel = logging.INFO
- if loglevel != 0 : outlevel = loglevel
-
- # init outputs:
- self.stdout = []
- self.stderr = []
- # call suprocess, catch calling errors:
- try :
- p = subprocess.Popen( command,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- universal_newlines=True,
- **kwargs )
- except Exception as err:
- logger.error( str(err) )
- raise CallingError( command, err )
- # wait for process to terminate:
- while p.poll() == None :
- line = p.stdout.readline() # read next line from standard output
- if line.strip():
- self.stderr.append(line.strip('\n'))
- logger.log( outlevel, line.strip('\n') )
- # read remaining lines:
- for line in p.stdout.readlines() :
- if line.strip():
- self.stderr.append(line.strip('\n')) # store
- logger.log( outlevel, line.strip('\n') ) # write
- # store return code:
- self.returncode = p.returncode
- # error ?
- if self.returncode != 0 : raise StatusError(command,self.returncode,self.stdout,self.stderr)
- # ok
- return
- # ------------------------------------------------
- # end
- # ------------------------------------------------
|