Normally when there’s an exception in your Python code, you’ll be pleasantly shown a very detailed and long stacktrace full of information, sometimes useful or sometimes not. This stacktrace can be very noisy and it will take a while to look through all the code to pinpoint the issue. It’s a lot more useful to see the last line in your application code where the issue occurs. Also, there are cases that you need to capture an inner exception and somehow keep the relevant information for later debugging. This is when a more succint, relevant stacktrace is much needed.
This is also useful when you need to serialize the exception since Python doesn’t support serialization of Exceptions so you’ll have to resort to do a string conversion str(e)
.
The solution is to the traceback
module and some very vaguely documented code to help you go down the stack to get to the right information.
import traceback
import os
def exception_message_with_line_number(e):
stack_level = 1 # we start at the last line of the exception
stack = None
cwd = os.getcwd()
# traverse the stack to grab the first application code that throw an exception
while stack_level < 1000:
stack = traceback.extract_tb(e.__traceback__, -stack_level)[0]
if not stack.filename.startswith(cwd):
stack_level += 1
else:
break
filename, lineno, line = stack.filename, stack.lineno, stack.line
return (
type(e).__name__ + "::" + str(e) + "@" +
filename + ":" + str(lineno) + " `" + line + "`"
)
try:
raise Exception("give me my stack")
except Exception as e:
print(exception_message_with_line_number(e))
Running the above will produce:
Exception::give me my stack@/path/to/your/script.py:25 `raise Exception("give me my stack")`
Happy hacking!
Leave a Reply