Implement ui.error() and output them at end of offlinimap sync

Output all raised Exceptions error strings to the error log. If we are
in debug mode, we also output the traceback of the exception.

Save all exceptions that occur during the run time to a Queue and output
them all again when the offlineimap sync is finished.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
This commit is contained in:
Sebastian Spaeth 2011-08-11 12:22:34 +02:00 committed by Nicolas Sebrecht
parent 61e50b3b1a
commit f937a86571

View File

@ -21,6 +21,7 @@ import time
import sys import sys
import traceback import traceback
import threading import threading
from Queue import Queue
import offlineimap import offlineimap
debugtypes = {'':'Other offlineimap related sync messages', debugtypes = {'':'Other offlineimap related sync messages',
@ -47,6 +48,8 @@ class UIBase:
s.debugmsglen = 50 s.debugmsglen = 50
s.threadaccounts = {} s.threadaccounts = {}
s.logfile = None s.logfile = None
s.exc_queue = Queue()
"""saves all occuring exceptions, so we can output them at the end"""
################################################## UTILS ################################################## UTILS
def _msg(s, msg): def _msg(s, msg):
@ -82,6 +85,39 @@ class UIBase:
else: else:
s._msg("WARNING: " + msg) s._msg("WARNING: " + msg)
def error(self, exc, exc_traceback=None, msg=None):
"""Log a message at severity level ERROR
Log Exception 'exc' to error log, possibly prepended by a preceding
error "msg", detailing at what point the error occurred.
In debug mode, we also output the full traceback that occurred
if one has been passed in via sys.exc_traceback.
Also save the Exception to a stack that can be output at the end
of the sync run when offlineiamp exits. It is recommended to
always pass in exceptions if possible, so we can give the user
the best debugging info.
One example of such a call might be:
ui.error(exc, sys.exc_traceback, msg="While syncing Folder %s in "
"repo %s")
"""
cur_thread = threading.currentThread()
if msg:
self._msg("ERROR [%s]: %s\n %s" % (cur_thread, msg, exc))
else:
self._msg("ERROR [%s]: %s" % (cur_thread, exc))
if not self.debuglist:
# only output tracebacks in debug mode
exc_traceback = None
# push exc on the queue for later output
self.exc_queue.put((msg, exc, exc_traceback))
if exc_traceback:
self._msg(traceback.format_tb(exc_traceback))
def registerthread(s, account): def registerthread(s, account):
"""Provides a hint to UIs about which account this particular """Provides a hint to UIs about which account this particular
thread is processing.""" thread is processing."""
@ -315,12 +351,24 @@ class UIBase:
def mainException(s): def mainException(s):
s._msg(s.getMainExceptionString()) s._msg(s.getMainExceptionString())
def terminate(s, exitstatus = 0, errortitle = None, errormsg = None): def terminate(self, exitstatus = 0, errortitle = None, errormsg = None):
"""Called to terminate the application.""" """Called to terminate the application."""
if errormsg <> None: #print any exceptions that have occurred over the run
if errortitle <> None: if not self.exc_queue.empty():
sys.stderr.write('ERROR: %s\n\n%s\n'%(errortitle, errormsg)) self._msg("\nERROR: Exceptions occurred during the run!")
while not self.exc_queue.empty():
msg, exc, exc_traceback = self.exc_queue.get()
if msg:
self._msg("ERROR: %s\n %s" % (msg, exc))
else: else:
self._msg("ERROR: %s" % (exc))
if exc_traceback:
self._msg("\nTraceback:\n%s" %"".join(
traceback.format_tb(exc_traceback)))
if errormsg and errortitle:
sys.stderr.write('ERROR: %s\n\n%s\n'%(errortitle, errormsg))
elif errormsg:
sys.stderr.write('%s\n' % errormsg) sys.stderr.write('%s\n' % errormsg)
sys.exit(exitstatus) sys.exit(exitstatus)