diff --git a/coba/context/loggers.py b/coba/context/loggers.py index 17beba67..2d0ebde8 100644 --- a/coba/context/loggers.py +++ b/coba/context/loggers.py @@ -297,6 +297,20 @@ def filter(self, log: Union[str,Exception]) -> str: elif isinstance(log, CobaException): return f"EXCEPTION: {log}" else: - tb = ''.join(traceback.format_tb(log.__traceback__)) - msg = ''.join(traceback.TracebackException.from_exception(log).format_exception_only()) - return f"Unexpected exception:\n\n{tb}\n {msg}" + return f'Unexpected exception:\n\n{self.format_exception(log)}' + + def format_exception(self, ex: Exception): + + out = [] + + if ex.__cause__ is not None: + out.append(self.format_exception(ex.__cause__)) + out.append("The above exception was the direct cause of the following exception:\n") + + tb = ''.join(traceback.format_tb(ex.__traceback__)) + msg = ''.join(traceback.TracebackException.from_exception(ex).format_exception_only()) + + if tb : out.append(tb) + if msg: out.append(f' {msg}') + + return '\n'.join(out) diff --git a/coba/tests/test_context_loggers.py b/coba/tests/test_context_loggers.py index 0c449136..c0c5bb4a 100644 --- a/coba/tests/test_context_loggers.py +++ b/coba/tests/test_context_loggers.py @@ -603,10 +603,9 @@ def test_filter_exception(self): log = decorator.filter(exception) - tb = ''.join(traceback.format_tb(exception.__traceback__)) msg = ''.join(traceback.TracebackException.from_exception(exception).format_exception_only()) - expected_log = f"Unexpected exception:\n\n{tb}\n {msg}" + expected_log = f"Unexpected exception:\n\n {msg}" self.assertEqual(log, expected_log) @@ -627,6 +626,27 @@ def test_filter_exception_raise(self): self.assertEqual(log, expected_log) + def test_filter_exception_raise_with_caues(self): + + decorator = ExceptLog() + outer_ex = Exception("Out Exception") + inner_ex = Exception("In Exception") + + try: + raise inner_ex from outer_ex + except Exception as ex: + log = decorator.filter(ex) + + tb = ''.join(traceback.format_tb(ex.__traceback__)) + msg = ''.join(traceback.TracebackException.from_exception(ex).format_exception_only()) + + expected_log = ( + 'Unexpected exception:\n\n Exception: Out Exception\n\nThe above exception ' + f'was the direct cause of the following exception:\n\n{tb}\n {msg}' + ) + + self.assertEqual(log, expected_log) + def test_filter_coba_exception(self): decorator = ExceptLog()