# HG changeset patch # User Tuomo Valkonen # Date 1516485136 0 # Node ID aaf1a281a3fe19f39b54d3eebf79adf92f0f0562 # Parent 5a988a2c262460a743687e3fd4dc57bcc649df54 More error reporting diff -r 5a988a2c2624 -r aaf1a281a3fe backup.py --- a/backup.py Sat Jan 20 21:27:05 2018 +0000 +++ b/backup.py Sat Jan 20 21:52:16 2018 +0000 @@ -23,6 +23,14 @@ else: return logging.ERROR +def safe_get_int(t, x): + if x in t: + tmp=t[x] + if isinstance(tmp, int): + return tmp + return None + + class Backup: def __decode_config(self, cfg): @@ -104,22 +112,36 @@ for status in iter(self.borg_instance.read_log, None): logging.debug(str(status)) t=status['type'] - #may_indicate_finished=False + + errors_this_message=False + callback=None + if t=='progress_percent': - if 'current' in status and 'total' in status: + current=safe_get_int(status, 'current') + total=safe_get_int(status, 'total') + if current is not None and total is not None: with self.lock: - self.current_operation.progress_current=status['current'] - self.current_operation.progress_total=status['total'] + self.current_operation.progress_current=current + self.current_operation.progress_total=total status, callback=self.__status_unlocked() - if callback: - callback(self, status) + elif t=='archive_progress': + original_size=safe_get_int(status, 'original_size') + compressed_size=safe_get_int(status, 'compressed_size') + deduplicated_size=safe_get_int(status, 'deduplicated_size') + if original_size is not None and original_size is not None and deduplicated_size is not None: + with self.lock: + self.current_operation.original_size=original_size + self.current_operation.compressed_size=compressed_size + self.current_operation.deduplicated_size=deduplicated_size + status, callback=self.__status_unlocked() + + elif t=='progress_message': pass - elif t=='progress_message': - #may_indicate_finished=True - pass + elif t=='file_status': pass + elif t=='log_message': if 'levelname' not in status: status['levelname']='ERROR' @@ -127,13 +149,22 @@ status['message']='UNKNOWN' if 'name' not in status: status['name']='borg' - logging.log(translate_loglevel(status['levelname']), - status['name'] + ': ' + status['message']) - # set success=False? + lvl=translate_loglevel(status['levelname']) + logging.log(lvl, status['name'] + ': ' + status['message']) + if lvl>=logging.WARNING: + errors_this_message=True elif t=='exception': - success=False + errors_this_message=True elif t=='unparsed_error': - success=False + errors_this_message=True + + if errors_this_message: + with self.lock: + self.current_operation.errors=True + status, callback=self.__status_unlocked() + + if callback: + callback(self, status) logging.debug('Waiting for borg subprocess to terminate in log thread') @@ -359,6 +390,9 @@ status['name']=self.name + if 'errors' not in status: + status['errors']=False + if 'when_monotonic' in status: status['when']=(status['when_monotonic'] -time.monotonic()+time.time()) diff -r 5a988a2c2624 -r aaf1a281a3fe ui.py --- a/ui.py Sat Jan 20 21:27:05 2018 +0000 +++ b/ui.py Sat Jan 20 21:52:16 2018 +0000 @@ -10,13 +10,13 @@ INACTIVE=0 ACTIVE=1 -ERROR=2 +ERRORS=2 -traynames={INACTIVE: 'B.', ACTIVE: 'B!', ERROR: 'B?'} +traynames={INACTIVE: 'B.', ACTIVE: 'B!', ERRORS: 'B?'} def combine_state(state1, state2): - if state1==ERROR or state2==ERROR: - return ERROR + if state1==ERRORS or state2==ERRORS: + return ERRORS elif state1==ACTIVE or state2==ACTIVE: return ACTIVE else: @@ -24,6 +24,7 @@ def make_title(status): state=INACTIVE + if status['type']=='scheduled': # Operation scheduled when=status['when'] @@ -44,7 +45,7 @@ detail='' if 'detail' in status and status['detail']: if status['detail']=='retry': - state=ERROR + state=ERRORS detail=status['detail']+' ' title="%s (%s%s %s)" % (status['name'], detail, status['operation'], whenstr) elif status['type']=='current': @@ -58,6 +59,9 @@ # Should be unscheduled, nothing running title=status['name'] + if status['errors']: + state=ERRORS + return title, state