diff --git a/src/sentry/grouping/fingerprinting.py b/src/sentry/grouping/fingerprinting.py index f843d1b04fc1f1..9601d3175e4614 100644 --- a/src/sentry/grouping/fingerprinting.py +++ b/src/sentry/grouping/fingerprinting.py @@ -57,6 +57,17 @@ class InvalidFingerprintingConfig(Exception): pass +def get_crashing_thread(threads): + if len(threads) == 1: + return threads[0] + filtered = [x for x in threads if x and x.get("crashed")] + if len(filtered) == 1: + return filtered[0] + filtered = [x for x in threads if x and x.get("current")] + if len(filtered) == 1: + return filtered[0] + + class EventAccess: def __init__(self, event): self.event = event @@ -139,8 +150,9 @@ def _push_frame(frame): frames = get_path(self.event, "stacktrace", "frames", filter=True) if not frames: threads = get_path(self.event, "threads", "values", filter=True) - if threads and len(threads) == 1: - frames = get_path(threads, 0, "stacktrace", "frames") + thread = get_crashing_thread(threads) + if thread is not None: + frames = get_path(thread, "stacktrace", "frames") for frame in frames or (): _push_frame(frame) diff --git a/tests/sentry/grouping/fingerprint_inputs/fingerprint-two-threads.json b/tests/sentry/grouping/fingerprint_inputs/fingerprint-two-threads.json new file mode 100644 index 00000000000000..58768ba44a1795 --- /dev/null +++ b/tests/sentry/grouping/fingerprint_inputs/fingerprint-two-threads.json @@ -0,0 +1,66 @@ +{ + "_fingerprinting_rules": [ + { + "matchers": [ + ["function", "main"] + ], + "fingerprint": ["in-main"] + } + ], + "threads": { + "values": [ + { + "stacktrace": { + "frames": [ + { + "function": "main", + "abs_path": "foo/baz.c", + "filename": "foo/baz.c", + "lineno": 1, + "in_app": true + } + ] + }, + "name": "Main Thread", + "current": true, + "crashed": true, + "raw_stacktrace": { + "frames": [ + { + "function": "", + "lineno": 1, + "in_app": true + } + ] + }, + "id": 42 + }, + { + "stacktrace": { + "frames": [ + { + "function": "main", + "abs_path": "foo/baz.c", + "filename": "foo/baz.c", + "lineno": 1, + "in_app": true + } + ] + }, + "name": "Other Thread", + "current": false, + "crashed": false, + "raw_stacktrace": { + "frames": [ + { + "function": "", + "lineno": 1, + "in_app": true + } + ] + }, + "id": 43 + } + ] + } +} diff --git a/tests/sentry/grouping/similarity/snapshots/test_features/test_similarity_extract_fingerprinting/fingerprint_two_threads.pysnap b/tests/sentry/grouping/similarity/snapshots/test_features/test_similarity_extract_fingerprinting/fingerprint_two_threads.pysnap new file mode 100644 index 00000000000000..00b77b5efd1ebf --- /dev/null +++ b/tests/sentry/grouping/similarity/snapshots/test_features/test_similarity_extract_fingerprinting/fingerprint_two_threads.pysnap @@ -0,0 +1,7 @@ +--- +created: '2021-10-09T08:58:47.042020Z' +creator: sentry +source: tests/sentry/grouping/similarity/test_features.py +--- +similarity:2020-07-23:fingerprint:ident-shingle: "in-main" +similarity:2020-07-23:stacktrace:frames-ident: [["filename","baz.c"],["function","main"]] diff --git a/tests/sentry/grouping/snapshots/test_fingerprinting/test_event_hash_variant/fingerprint_two_threads.pysnap b/tests/sentry/grouping/snapshots/test_fingerprinting/test_event_hash_variant/fingerprint_two_threads.pysnap new file mode 100644 index 00000000000000..58f60a58ae954f --- /dev/null +++ b/tests/sentry/grouping/snapshots/test_fingerprinting/test_event_hash_variant/fingerprint_two_threads.pysnap @@ -0,0 +1,35 @@ +--- +created: '2021-10-09T08:26:55.655641Z' +creator: sentry +source: tests/sentry/grouping/test_fingerprinting.py +--- +config: + rules: + - attributes: {} + fingerprint: + - in-main + matchers: + - - function + - main + version: 1 +fingerprint: +- in-main +title: +variants: + app: + component: + contributes: false + contributes_to_similarity: true + hint: custom fingerprint takes precedence + type: component + custom-fingerprint: + matched_rule: function:"main" -> "in-main" + type: custom-fingerprint + values: + - in-main + system: + component: + contributes: false + contributes_to_similarity: true + hint: custom fingerprint takes precedence + type: component