8000 fix: Wrong behavior of attach_stacktrace · etherscan-io/sentry-python@e0c075a · GitHub
[go: up one dir, main page]

Skip to content

Commit e0c075a

Browse files
committed
fix: Wrong behavior of attach_stacktrace
1 parent 56ca47f commit e0c075a

File tree

3 files changed

+76
-54
lines changed

3 files changed

+76
-54
lines changed

sentry_sdk/client.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
handle_in_app,
1212
get_type_name,
1313
capture_internal_exceptions,
14+
current_stacktrace,
1415
logger,
1516
)
1617
from sentry_sdk.transport import make_transport
@@ -73,6 +74,14 @@ def _prepare_event(self, event, hint, scope):
7374
if event is None:
7475
return
7576

77+
if (
78+
"exception" not in event
79+
and "stacktrace" not in event
80+
and self.options["attach_stacktrace"]
81+
):
82+
with capture_internal_exceptions():
83+
event["stacktrace"] = current_stacktrace()
84+
7685
for key in "release", "environment", "server_name", "dist":
7786
if event.get(key) is None:
7887
event[key] = self.options[key]

sentry_sdk/utils.py

Lines changed: 55 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -162,17 +162,26 @@ def get_type_module(cls):
162162
return mod
163163

164164

165+
def should_hide_frame(frame):
166+
try:
167+
mod = frame.f_globals["__name__"]
168+
return mod.startswith("sentry_sdk.")
169+
except (AttributeError, KeyError):
170+
pass
171+
172+
for flag_name in "__traceback_hide__", "__tracebackhide__":
173+
try:
174+
if frame.f_locals[flag_name]:
175+
return True
176+
except Exception:
177+
pass
178+
179+
return False
180+
181+
165182
def iter_stacks(tb):
166183
while tb is not None:
167-
skip = False
168-
for flag_name in "__traceback_hide__", "__tracebackhide__":
169-
try:
170-
if tb.tb_frame.f_locals[flag_name]:
171-
skip = True
172-
except Exception:
173-
pass
174-
175-
if not skip:
184+
if not should_hide_frame(tb.tb_frame):
176185
yield tb
177186
tb = tb.tb_next
178187

@@ -242,19 +251,6 @@ def get_source_context(frame, tb_lineno):
242251
return [], None, []
243252

244253

245-
def skip_internal_frames(frame):
246-
tb = frame
247-
while tb is not None:
248-
try:
249-
mod = tb.tb_frame.f_globals["__name__"]
250-
if not mod.startswith("sentry_sdk."):
251-
break
252-
except (AttributeError, KeyError):
253-
pass
254-
tb = tb.tb_next
255-
return tb
256-
257-
258254
def safe_str(value):
259255
try:
260256
return text_type(value)
@@ -308,8 +304,7 @@ def extract_locals(frame):
308304
return rv
309305

310306

311-
def frame_from_traceback(tb, with_locals=True):
312-
frame = tb.tb_frame
307+
def serialize_frame(frame, tb_lineno=None, with_locals=True):
313308
f_code = getattr(frame, "f_code", None)
314309
if f_code:
315310
abs_path = frame.f_code.co_filename
@@ -322,14 +317,17 @@ def frame_from_traceback(tb, with_locals=True):
322317
except Exception:
323318
module = None
324319

325-
pre_context, context_line, post_context = get_source_context(frame, tb.tb_lineno)
320+
if tb_lineno is None:
321+
tb_lineno = frame.f_lineno
322+
323+
pre_context, context_line, post_context = get_source_context(frame, tb_lineno)
326324

327325
rv = {
328326
"filename": abs_path and os.path.basename(abs_path) or None,
329327
"abs_path": os.path.abspath(abs_path),
330328
"function": function or "<unknown>",
331329
"module": module,
332-
"lineno": tb.tb_lineno,
330+
"lineno": tb_lineno,
333331
"pre_context": pre_context,
334332
"context_line": context_line,
335333
"post_context": post_context,
@@ -339,8 +337,30 @@ def frame_from_traceback(tb, with_locals=True):
339337
return rv
340338

341339

342-
def stacktrace_from_traceback(tb, with_locals=True):
343-
return {"frames": [frame_from_traceback(tb, with_locals) for tb in iter_stacks(tb)]}
340+
def stacktrace_from_traceback(tb=None, with_locals=True):
341+
return {
342+
"frames": [
343+
serialize_frame(
344+
tb.tb_frame, tb_lineno=tb.tb_lineno, with_locals=with_locals
345+
)
346+
for tb in iter_stacks(tb)
347+
]
348+
}
349+
350+
351+
def current_stacktrace(with_locals=True):
352+
__tracebackhide__ = True
353+
frames = []
354+
355+
f = sys._getframe()
356+
while f is not None:
357+
if not should_hide_frame(f):
358+
frames.append(serialize_frame(f, with_locals=with_locals))
359+
f = f.f_back
360+
361+
frames.reverse()
362+
363+
return {"frames": frames}
344364

345365

346366
def get_errno(exc_value):
@@ -356,23 +376,19 @@ def single_exception_from_error_tuple(
356376
mechanism_meta = mechanism.setdefault("meta", {})
357377
mechanism_meta.setdefault("errno", {"code": errno})
358378

359-
rv = {
379+
if client_options is None:
380+
with_locals = True
381+
else:
382+
with_locals = client_options["with_locals"]
383+
384+
return {
360385
"module": get_type_module(exc_type),
361386
"type": get_type_name(exc_type),
362387
"value": safe_str(exc_value),
363388
"mechanism": mechanism,
389+
"stacktrace": stacktrace_from_traceback(tb, with_locals),
364390
}
365391

366-
if client_options is None or client_options["attach_stacktrace"]:
367-
if client_options is None:
368-
with_locals = True
369-
else:
370-
with_locals = client_options["with_locals"]
371-
372-
rv["stacktrace"] = stacktrace_from_traceback(tb, with_locals)
373-
374-
return rv
375-
376392

377393
def exceptions_from_error_tuple(exc_info, client_options=None, mechanism=None):
378394
exc_type, exc_value, tb = exc_info
@@ -453,9 +469,6 @@ def exc_info_from_error(error):
453469
exc_value = error
454470
exc_type = type(error)
455471

456-
if tb is not None:
457-
tb = skip_internal_frames(tb)
458-
459472
return exc_type, exc_value, tb
460473

461474

tests/test_client.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -95,27 +95,27 @@ def test_with_locals_disabled():
9595
def test_attach_stacktrace_enabled():
9696
events = []
9797
hub = Hub(Client(attach_stacktrace=True, transport=events.append))
98-
try:
99-
1 / 0
100-
except Exception:
101-
hub.capture_exception()
98+
99+
def foo():
100+
bar()
101+
102+
def bar():
103+
hub.capture_message("HI")
104+
105+
foo()
102106

103107
event, = events
104-
exception, = event["exception"]["values"]
105-
assert exception["stacktrace"]["frames"]
108+
functions = [x["function"] for x in event["stacktrace"]["frames"]]
109+
assert functions[-2:] == ["foo", "bar"]
106110

107111

108112
def test_attach_stacktrace_disabled():
109113
events = []
110114
hub = Hub(Client(attach_stacktrace=False, transport=events.append))
111-
try:
112-
1 / 0
113-
except Exception:
114-
hub.capture_exception()
115+
hub.capture_message("HI")
115116

116117
event, = events
117-
exception, = event["exception"]["values"]
118-
assert "stacktrace" not in event["exception"]["values"][0]
118+
assert "stacktrace" not in event
119119

120120

121121
def test_capture_event_works():

0 commit comments

Comments
 (0)
0