Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

locals() and globals() in stack trace on exception (Python)

While stack traces are useful in Python, most often the data at the root of the problem are missing - is there a way of making sure that at least locals() (and possibly globals()) are added to printed stacktrace?

like image 258
LetMeSOThat4U Avatar asked Oct 22 '13 09:10

LetMeSOThat4U


2 Answers

This is a Box of Pandora. Values can be very large in printed form; printing all locals in a stack trace can easily lead to new problems just due to error output. That's why this is not implemented in general in Python.

In small examples, though, i. e. if you know that your values aren't too large to be printed properly, you can step along the traceback yourself:

import sys
import traceback

def c():
  clocal = 1001
  raise Exception("foo")

def b():
  blocal = 23
  c()

def a():
  alocal = 42
  b()

try:
  a()
except Exception:
  frame = sys.exc_info()[2]
  formattedTb = traceback.format_tb(frame)    
  frame = frame.tb_next
  while frame:
    print formattedTb.pop(0), '\t', frame.tb_frame.f_locals
    frame = frame.tb_next

The output will be sth like this:

  File "/home/alfe/tmp/stacktracelocals.py", line 19, in <module>
    a()
        {'alocal': 42}
  File "/home/alfe/tmp/stacktracelocals.py", line 16, in a
    b()
        {'blocal': 23}
  File "/home/alfe/tmp/stacktracelocals.py", line 12, in b
    c()
        {'clocal': 1001}

And you can, of course, install your own except hook as thg435 suggested in his answer.

like image 93
Alfe Avatar answered Nov 11 '22 14:11

Alfe


You can install your own exception hook and output what you need from there:

import sys, traceback

def excepthook(type, value, tb):
    traceback.print_exception(type, value, tb)

    while tb.tb_next:
        tb = tb.tb_next

    print >>sys.stderr, 'Locals:',  tb.tb_frame.f_locals
    print >>sys.stderr, 'Globals:', tb.tb_frame.f_globals

sys.excepthook = excepthook

def x():
    y()

def y():
    foo = 1
    bar = 0

    foo/bar

x()

To print vars from each frame in a traceback, change the above loop to

    while tb:
        print >>sys.stderr, 'Locals:',  tb.tb_frame.f_locals
        print >>sys.stderr, 'Globals:', tb.tb_frame.f_globals
        tb = tb.tb_next
like image 39
georg Avatar answered Nov 11 '22 14:11

georg