Reputation: 83
I'm debugging a complex program that has a block like this:
try:
lots()
of()
deeply()
nested()
code()
except BaseException as e:
log_error(str(e))
The error message that comes out is just Config file missing
but that's not much help to me.
I'd really like to see exactly were that message comes from. (Note that the error string is from an external program, so it's not searchable.)
If I use traceback
I only get to see the stack trace after it's been wound back to the handler, which is not useful. I'd like to see the traceback at the source of the exception.
Any ideas?
Thanks!
Upvotes: 0
Views: 2471
Reputation: 1
First and foremost, you should absolutely stick with the best practices and use the builtin module traceback
, as sugested by Roman.
But i found it quite a fun and interesting challenge to try and avoid traceback
, so i gave it a try to implement it myself.
Exceptions store their traces in the traceback attribute, which is a linked list. Each tb_next represents the next item in that list (in this case, it represents the previous place where the exception was handled).
Here's what i came up with:
def extract_stack_from_exception(exception):
"""
Extracts and returns the stack trace from the provided exception.
Args:
exception (Exception): The exception to extract the stack trace from.
Returns:
list[dict[str, str]]: A list of dictionaries containing the filename,
function name, and line number of each stack frame.
"""
stack = []
# Only interact with the traceback, if there is any traceback
if hasattr(exception, '__traceback__'):
# Grabs the traceback object
frame = exception.__traceback__
# Keep the loop alive if the frame is valid and has a "tb_next"
while frame and hasattr(frame, 'tb_next'):
stack.append({
'filename': frame.tb_frame.f_code.co_filename,
'function': frame.tb_frame.f_code.co_qualname,
'lineno': frame.tb_lineno,
})
# Moves the frame to the next "tb"
frame = frame.tb_next
return stack
It is a similar approach to the methods used inside the actual traceback
module (traceback.walk_tb
and traceback._walk_tb_with_full_positions
), where it iterates over that linked list structure reading those 3 items (filename, function, and line number).
Each tb
has a frame, it stores every attribute associated with the place where the exception was raised. So, for a simple trace, we just need the filename and method name.
You can read more about that method, and about the traceback
module itself here.
Upvotes: 0
Reputation: 543
For debugging purposes you can use traceback module to print stack trace
import traceback
try:
lots()
of()
deeply()
nested()
code()
except BaseException as e:
print traceback.format_exc()
log_error(str(e))
Upvotes: 2