How can I automatically print the stack trace to stdout on any uncaught exceptions ?
I am using
pipe = subprocess.Popen(cmd, shell=False, cwd=cwd, env=env,stdout=open(pth,'w'),stderr=open(pth,'w'))
On uncaught Exception, the file will only contain Unhandled Exception: but I'd like in addition the trace to be written to my logfile.
Moreover I'd like 开发者_C百科the original trace if the exception had been reraised
Thanks
In the child process initialize the logging
module and assign sys.stdout = LoggerFile()
. Then any exception not handled within the child process will be written to your log file instead of to standard out. If you want it to be written to both, enhance the LoggerFile
class.
Please note that because the child process is a completely separate interpreter, with its own separate execution stack, exceptions occurring within the child process cannot be propagated back to the parent process. But you could send encoded messages to simulate that.
from functools import partial
from itertools import imap
def text_coerce(encoding):
u"given encoding returns function that takes bytes or characters and returns characters"
def decode(data):
u"if given characters returns them; if given bytes decodes them"
if isinstance(data, StringType): # really bytes
return data.decode(encoding)
else: return data
return decode
def consume(iterable):
u"consume all values from an iterable in a loop"
while True:
try:
iterable.next()
except StopIteration:
break
class LoggerFile(object):
u"a non-seekable character-based file-like object that logs all data written to it"
def __init__(self, logger=None, level=logging.INFO, encoding='UTF-8'):
if logger is None: logger = logging.getLogger()
self._encoder = text_coerce(encoding)
self._log = partial(logger.log, level)
self.writelines = partial(map, self.write)
self.close = lambda: None # pretends to close
self.flush = lambda: None # pretends to flush
self.mode = 'w'
def write(self, message):
u"write() results in exactly one log message; same for the print statement when replacing stdout"
message = self._encoder(message).rstrip()
if message != u'': self._log(message)
def writelines(self, message):
consume(imap(self.write, message.split(u'\n')))
Thanks a lot to all. Wberry's solution works but is not necessary. It works fine using just
f = open(pth,'w');
pipe = subprocess.Popen(cmd,shell=False,cwd=cwd,env=env,stdout=f,stderr=f)
My problem came from redifining excepthook somewhere else (so that it enables Eclipse's breakpoint). I fixed it (switching to original sys.excepthook()
when needed).
@patrys: I open it once. It was a misleading one-line shortcut. Apologies.
精彩评论