Catch Python exception and save traceback text as string
Asked Answered
D

3

15

I'm trying to write a nice error handler for my code, so that when it fails, the logs, traceback and other relevant info get emailed to me.

I can't figure out how to take an exception object and extract the traceback.

I find the traceback module pretty confusing, mostly because it doesn't deal with exceptions at all. It just fetches some global variables from somewhere, assuming that I want the most recent exception. But what if I don't? What if I want to ignore some exception in my error handler? (e.g. if I fail to send me email and want to retry.)

What I want

import traceback as tb

# some function that will fail after a few recursions
def myfunc(x):
   assert x > 0, "oh no"
   return myfunc(x-1)

try:
    myfunc(3)
except Exception as e:
    traceback_str = tb.something(e)

Note that tb.something takes e as an argument.

There's lots of questions on Stack Overflow about using the traceback module to get a traceback string. The unique thing about this question is how to get it from the caught exception, instead of global variables.

Result:

traceback_str contains the string:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in myfunc
  File "<stdin>", line 3, in myfunc
  File "<stdin>", line 3, in myfunc
  File "<stdin>", line 2, in myfunc
AssertionError: oh no

Note that it contains not just the most recent function call, but the whole stack, and includes the "AssertionError" at the end

Damek answered 17/7, 2020 at 10:38 Comment(0)
D
21

The correct function for tb.something(e) is

''.join(tb.format_exception(None, e, e.__traceback__))
Damek answered 17/7, 2020 at 10:38 Comment(1)
Note from the docs: Since Python 3.10, instead of passing value and tb, an exception object can be passed as the first argument. If value and tb are provided, the first argument is ignored in order to provide backwards compatibility.Pulpiteer
V
1

This approach of this answer is new since Python 3.10. This reusable function writes the exception and traceback into a string buffer, and from there as a string.

import io
import traceback


def get_exception_traceback_str(exc: Exception) -> str:
    # Ref: https://stackoverflow.com/a/76584117/
    file = io.StringIO()
    traceback.print_exception(exc, file=file)
    return file.getvalue().rstrip()

Sample usage:

try:
    assert False, 'testing assertion'
except Exception as exc:
    error = get_exception_traceback_str(exc)

print(error)

Sample output:

Traceback (most recent call last):
  File "<input>", line 2, in <module>
AssertionError: testing assertion

Note: To just print the exception and traceback instead, you don't need it in a string, so consider using just traceback.print_exception(exc).

Vociferant answered 29/6, 2023 at 19:32 Comment(0)
C
0

For me @falsePockets' prints only the traceback. I've created this function, which would print the whole exception, including the type and the message:

def error_string(ex: Exception) -> str:
    return '\n'.join([
        ''.join(traceback.format_exception_only(None, ex)).strip(),
        ''.join(traceback.format_exception(None, ex, ex.__traceback__)).strip()
    ])
Councilor answered 25/5, 2023 at 13:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.