diff --git a/docs/internals/frontends.rst b/docs/internals/frontends.rst index e11a1a3f4..85b00134d 100644 --- a/docs/internals/frontends.rst +++ b/docs/internals/frontends.rst @@ -45,7 +45,7 @@ progress_message operation unique, opaque integer ID of the operation - msgid + :ref:`msgid ` Message ID of the operation (may be *none*) finished boolean indicating whether the operation has finished, only the last object for an *operation* @@ -58,7 +58,7 @@ progress_percent operation unique, opaque integer ID of the operation - msgid + :ref:`msgid ` Message ID of the operation (may be *none*) finished boolean indicating whether the operation has finished, only the last object for an *operation* @@ -90,6 +90,8 @@ log_message Name of the emitting entity message Formatted log message + :ref:`msgid ` + Message ID, may be *none* or absent Standard output --------------- @@ -188,3 +190,38 @@ comment Listing the contents of an archive can produce *a lot* of JSON. Each item (file, directory, ...) is described by one object in the *files* array of the :ref:`borg_list` output. Refer to the *borg list* documentation for the available keys and their meaning. + +.. _msgid: + +Message IDs +----------- + +Message IDs are strings that essentially give a log message or operation a name, without actually using the +full text, since texts change more frequently. Message IDs are unambiguous and reduce the need to parse +log messages. + +Assigned message IDs are: + +.. note:: + + This list is incomplete. + +Errors + - Archive.AlreadyExists + - Archive.DoesNotExist + - Archive.IncompatibleFilesystemEncodingError + - IntegrityError + - NoManifestError + - PlaceholderError + +Operations + - cache.begin_transaction + - cache.commit + - cache.sync + - repository.compact_segments + - repository.replay_segments + - repository.check_segments + - check.verify_data + - extract + - extract.permissions + - archive.delete diff --git a/src/borg/archiver.py b/src/borg/archiver.py index ad8a286d8..88fe23287 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -3287,7 +3287,7 @@ def main(): # pragma: no cover signal_handler('SIGUSR2', sig_trace_handler), \ signal_handler('SIGINFO', sig_info_handler): archiver = Archiver() - msg = tb = None + msg = msgid = tb = None tb_log_level = logging.ERROR try: args = archiver.get_args(sys.argv, os.environ.get('SSH_ORIGINAL_COMMAND')) @@ -3304,11 +3304,13 @@ def main(): # pragma: no cover exit_code = archiver.run(args) except Error as e: msg = e.get_message() + msgid = type(e).__qualname__ tb_log_level = logging.ERROR if e.traceback else logging.DEBUG tb = "%s\n%s" % (traceback.format_exc(), sysinfo()) exit_code = e.exit_code except RemoteRepository.RPCError as e: important = e.exception_class not in ('LockTimeout', ) + msgid = e.exception_class tb_log_level = logging.ERROR if important else logging.DEBUG if important: msg = e.exception_full @@ -3319,6 +3321,7 @@ def main(): # pragma: no cover exit_code = EXIT_ERROR except Exception: msg = 'Local Exception' + msgid = 'Exception' tb_log_level = logging.ERROR tb = '%s\n%s' % (traceback.format_exc(), sysinfo()) exit_code = EXIT_ERROR @@ -3329,14 +3332,16 @@ def main(): # pragma: no cover exit_code = EXIT_ERROR except SigTerm: msg = 'Received SIGTERM' + msgid = 'Signal.SIGTERM' tb_log_level = logging.DEBUG tb = '%s\n%s' % (traceback.format_exc(), sysinfo()) exit_code = EXIT_ERROR except SigHup: msg = 'Received SIGHUP.' + msgid = 'Signal.SIGHUP' exit_code = EXIT_ERROR if msg: - logger.error(msg) + logger.error(msg, msgid=msgid) if tb: logger.log(tb_log_level, tb) if args.show_rc: diff --git a/src/borg/logger.py b/src/borg/logger.py index 6d4a4402d..672c1e897 100644 --- a/src/borg/logger.py +++ b/src/borg/logger.py @@ -165,24 +165,38 @@ def create_logger(name=None): return self.__logger.setLevel(*args, **kw) def log(self, *args, **kw): + if 'msgid' in kw: + kw.setdefault('extra', {})['msgid'] = kw.pop('msgid') return self.__logger.log(*args, **kw) def exception(self, *args, **kw): + if 'msgid' in kw: + kw.setdefault('extra', {})['msgid'] = kw.pop('msgid') return self.__logger.exception(*args, **kw) def debug(self, *args, **kw): + if 'msgid' in kw: + kw.setdefault('extra', {})['msgid'] = kw.pop('msgid') return self.__logger.debug(*args, **kw) def info(self, *args, **kw): + if 'msgid' in kw: + kw.setdefault('extra', {})['msgid'] = kw.pop('msgid') return self.__logger.info(*args, **kw) def warning(self, *args, **kw): + if 'msgid' in kw: + kw.setdefault('extra', {})['msgid'] = kw.pop('msgid') return self.__logger.warning(*args, **kw) def error(self, *args, **kw): + if 'msgid' in kw: + kw.setdefault('extra', {})['msgid'] = kw.pop('msgid') return self.__logger.error(*args, **kw) def critical(self, *args, **kw): + if 'msgid' in kw: + kw.setdefault('extra', {})['msgid'] = kw.pop('msgid') return self.__logger.critical(*args, **kw) return LazyLogger(name) @@ -194,6 +208,8 @@ class JsonFormatter(logging.Formatter): 'levelname', 'name', 'message', + # msgid is an attribute we made up in Borg to expose a non-changing handle for log messages + 'msgid', ) # Other attributes that are not very useful but do exist: