Попробуйте вот такое решение. Код для Python 3. Основано на setprofile, так что может вам не подойти, если ваш код многопоточный.
import sys
import logging
LOG = logging.getLogger(__name__)
def handle_exception_with_locals(func):
def wrapped(*args, **kwargs):
locals = {}
def tracer(frame, event, arg):
""" Эта функция будет инспектировать код,
который будет выполнятся после того,
как она будет установлена профайлером.
Профайлер срабатывает только на события
retrun и call (при этом exception интерпретируется как return)
"""
nonlocal locals
if event == 'return':
locals = frame.f_locals.copy()
sys.setprofile(tracer)
try:
res = func(*args, **kwargs)
except Exception as e:
log_pattern = ('{}(*{}, **{}) failed with {}. ' +
'Local function variables: {}; ' +
'Global variables: {};')
LOG.error(log_pattern.format(
func.__name__, repr(args), repr(kwargs),
repr(e), repr(locals), repr(globals()))
)
raise
finally:
sys.setprofile(None)
return res
return wrapped
@handle_exception_with_locals
def test(a, b):
a = 16
b = 7
c = 9
raise ValueError('Oops!')
test(1, 2)