|
8 | 8 | get_error_message, |
9 | 9 | iter_stacks, |
10 | 10 | ) |
| 11 | +from sentry_sdk.tracing_utils import _should_be_included |
11 | 12 | from sentry_sdk.integrations import Integration |
12 | 13 | from sentry_sdk.scope import add_global_event_processor |
13 | 14 |
|
|
19 | 20 | from sentry_sdk._types import Event, Hint |
20 | 21 |
|
21 | 22 |
|
| 23 | +def _is_frame_in_app(tb_frame): |
| 24 | + # type: (Any) -> bool |
| 25 | + client = sentry_sdk.get_client() |
| 26 | + if not client.is_active(): |
| 27 | + return True |
| 28 | + |
| 29 | + in_app_include = client.options.get("in_app_include") |
| 30 | + in_app_exclude = client.options.get("in_app_exclude") |
| 31 | + project_root = client.options.get("project_root") |
| 32 | + |
| 33 | + abs_path = tb_frame.tb_frame.f_code.co_filename |
| 34 | + namespace = tb_frame.tb_frame.f_globals.get("__name__") |
| 35 | + |
| 36 | + return _should_be_included( |
| 37 | + is_sentry_sdk_frame=False, |
| 38 | + namespace=namespace, |
| 39 | + in_app_include=in_app_include, |
| 40 | + in_app_exclude=in_app_exclude, |
| 41 | + abs_path=abs_path, |
| 42 | + project_root=project_root, |
| 43 | + ) |
| 44 | + |
| 45 | + |
22 | 46 | def _create_exception_fingerprint(exc_info): |
23 | 47 | # type: (Any) -> str |
24 | 48 | """ |
25 | | - Creates a unique fingerprint for an exception based on type, message, and traceback. |
26 | | -
|
27 | | - This replaces object identity comparison to prevent memory leaks while maintaining |
28 | | - accurate deduplication for the same exception (same type+message+traceback). |
29 | | -
|
30 | | - Memory usage: 64 bytes (SHA256 hex string) for the last seen exception fingerprint. |
| 49 | + Creates a unique fingerprint for an exception based on type, message, and in-app traceback. |
31 | 50 | """ |
32 | 51 | exc_type, exc_value, tb = exc_info |
33 | 52 |
|
34 | 53 | if exc_type is None or exc_value is None: |
35 | 54 | return "" |
36 | 55 |
|
37 | | - # Get exception type information |
38 | 56 | type_module = get_type_module(exc_type) or "" |
39 | 57 | type_name = get_type_name(exc_type) or "" |
40 | | - |
41 | | - # Get exception message |
42 | 58 | message = get_error_message(exc_value) |
43 | 59 |
|
44 | | - # Create traceback fingerprint from top frames (limit to avoid excessive memory usage) |
45 | 60 | tb_parts = [] |
46 | 61 | frame_count = 0 |
47 | | - max_frames = 10 # Limit frames to keep memory usage low |
48 | 62 |
|
49 | 63 | for tb_frame in iter_stacks(tb): |
50 | | - if frame_count >= max_frames: |
51 | | - break |
| 64 | + if not _is_frame_in_app(tb_frame): |
| 65 | + continue |
52 | 66 |
|
53 | | - # Extract key frame information for fingerprint |
54 | | - filename = tb_frame.tb_frame.f_code.co_filename or "" |
| 67 | + file_path = tb_frame.tb_frame.f_code.co_filename or "" |
| 68 | + file_name = file_path.split("/")[-1] if "/" in file_path else file_path |
55 | 69 | function_name = tb_frame.tb_frame.f_code.co_name or "" |
56 | 70 | line_number = str(tb_frame.tb_lineno) |
57 | | - |
58 | | - # Create a compact frame fingerprint |
59 | 71 | frame_fingerprint = "{}:{}:{}".format( |
60 | | - ( |
61 | | - filename.split("/")[-1] if "/" in filename else filename |
62 | | - ), # Just filename, not full path |
| 72 | + file_name, |
63 | 73 | function_name, |
64 | 74 | line_number, |
65 | 75 | ) |
66 | 76 | tb_parts.append(frame_fingerprint) |
67 | 77 | frame_count += 1 |
68 | 78 |
|
69 | | - # Combine all parts for the complete fingerprint |
70 | 79 | fingerprint_parts = [type_module, type_name, message, "|".join(tb_parts)] |
71 | | - |
72 | | - # Create SHA256 hash of the combined fingerprint |
73 | 80 | fingerprint_data = "||".join(fingerprint_parts).encode("utf-8", errors="replace") |
| 81 | + |
74 | 82 | return hashlib.sha256(fingerprint_data).hexdigest() |
75 | 83 |
|
76 | 84 |
|
|
0 commit comments