Skip to content
This repository was archived by the owner on Jun 13, 2023. It is now read-only.

Commit a3b2b4f

Browse files
authored
feat(event.py): add exception frames (#291)
1 parent 5f977ff commit a3b2b4f

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

epsagon/event.py

+15-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
"""
44

55
from __future__ import absolute_import
6+
import sys
67
import time
8+
import inspect
79
import uuid
810
from .common import ErrorCode
911

@@ -111,12 +113,24 @@ def set_exception(
111113
function
112114
:param from_logs: True if the exception was captured from logging
113115
"""
114-
115116
self.error_code = ErrorCode.EXCEPTION
116117
self.exception['type'] = type(exception).__name__
117118
self.exception['message'] = str(exception)
118119
self.exception['traceback'] = traceback_data
119120
self.exception['time'] = time.time()
121+
122+
# Adding python frames (input data of functions in stack) in python 3.
123+
# Ignoring filenames with /epsagon since they are ours.
124+
if sys.version_info.major == 3:
125+
self.exception['frames'] = {
126+
'/'.join([
127+
frame.filename,
128+
frame.function,
129+
str(frame.lineno)
130+
]): frame.frame.f_locals
131+
for frame in inspect.trace()
132+
if '/epsagon' not in frame.filename and frame.frame.f_locals
133+
}
120134
self.exception.setdefault('additional_data', {})['handled'] = handled
121135
if from_logs:
122136
self.exception['additional_data']['from_logs'] = True

tests/wrappers/test_python_function.py

+35
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
1+
import sys
12
import mock
23
import pytest
4+
from collections import namedtuple
35
from epsagon import trace_factory
46
import epsagon.constants
57

68
trace_mock = mock.MagicMock()
79

10+
Frame = namedtuple('Frame', 'f_locals')
11+
FrameInfo = namedtuple(
12+
'FrameInfo',
13+
'frame, filename, lineno, function, code_context, index'
14+
)
815

916
def setup_function(func):
1017
trace_factory.use_single_trace = True
@@ -62,3 +69,31 @@ def wrapped_function(event, context):
6269
trace_mock.prepare.assert_called_once()
6370
trace_mock.send_traces.assert_not_called()
6471
trace_mock.set_runner.assert_not_called()
72+
73+
74+
@mock.patch(
75+
'inspect.trace',
76+
return_value=[FrameInfo(
77+
frame=Frame(f_locals={'param': 'value'}),
78+
filename='filename',
79+
lineno=1,
80+
function='function',
81+
code_context=['code_context'],
82+
index=0,
83+
)]
84+
)
85+
def test_function_wrapper_function_exception_frames(_, trace_transport):
86+
@epsagon.python_wrapper()
87+
def wrapped_function():
88+
raise TypeError('test')
89+
90+
with pytest.raises(TypeError):
91+
wrapped_function()
92+
93+
assert len(trace_transport.last_trace.events) == 1
94+
event = trace_transport.last_trace.events[0]
95+
if sys.version_info.major == 3:
96+
assert event.exception['frames'] == {
97+
'filename/function/1': {'param': 'value'}
98+
}
99+

0 commit comments

Comments
 (0)