-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(related_issues): API to find groups caused by the same root error #66992
Merged
Merged
Changes from 15 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
7c22665
feat(related_issues): Function to find groups that share the same err…
armenzg 2a3ed0a
Initial endpoint
armenzg 9a1fba5
Fix: group endpoint
armenzg ac7b35a
Minor test refactor
armenzg 8ea8539
Working tests
armenzg 6ad3dbb
Minor refactor
armenzg 39f28cc
Move under issues directory
armenzg 9fe38a3
Few more touches
armenzg 582ef11
Comment
armenzg 7a50235
Merge branch 'master' into feat/same-root/related_issues/armenzg
armenzg f160cfe
Fixing typing issues
armenzg 5354a19
Keep comment about feature flag
armenzg 8fee0e2
Update related_issues.py
armenzg c97f46f
Update README.md
armenzg ca63bf6
Merge branch 'master' into feat/same-root/related_issues/armenzg
armenzg 74edddb
Minor change
armenzg 7d7b75b
Update issues matching rules
armenzg d1a03d1
range query
armenzg 2107598
Merge branch 'master' into feat/same-root/related_issues/armenzg
armenzg 3ed0265
Smaller limit
armenzg fa06db7
Add feature flags
armenzg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
from rest_framework.request import Request | ||
from rest_framework.response import Response | ||
|
||
from sentry.api.api_owners import ApiOwner | ||
from sentry.api.api_publish_status import ApiPublishStatus | ||
from sentry.api.base import region_silo_endpoint | ||
from sentry.api.bases.group import GroupEndpoint | ||
from sentry.issues.related import find_related_issues | ||
from sentry.models.group import Group | ||
|
||
|
||
@region_silo_endpoint | ||
class RelatedIssuesEndpoint(GroupEndpoint): | ||
owner = ApiOwner.ISSUES | ||
publish_status = {"GET": ApiPublishStatus.EXPERIMENTAL} | ||
|
||
def get(self, _: Request, group: Group) -> Response: | ||
related_issues = find_related_issues(group) | ||
return Response({key: [g.id for g in groups] for key, groups in related_issues.items()}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Summary | ||
|
||
Issues in Sentry are created based on unique fingerprints based on the information from an event (e.g. the stack trace or the message). The Related Issues feature associates different issues based on the heuristics we will describe. This satisfies the desire of many customers to act on various issues together. | ||
|
||
In the future, we will be implementing super groups ([read Armin's RFC on supergroups](https://github.com/getsentry/rfcs/pull/29)). | ||
|
||
## Same root cause | ||
|
||
In many cases, a bug or an environmental failure will create many Sentry issues which can be merged. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
"""This module exports a function to find related issues. It groups them by type.""" | ||
|
||
from sentry.models.group import Group | ||
|
||
from .same_root_cause import same_root_cause_analysis | ||
|
||
__all__ = ["find_related_issues"] | ||
|
||
RELATED_ISSUES_ALGORITHMS = { | ||
"same_root_cause": same_root_cause_analysis, | ||
} | ||
|
||
|
||
def find_related_issues(group: Group) -> dict[str, list[Group]]: | ||
related_issues = {} | ||
for key, func in RELATED_ISSUES_ALGORITHMS.items(): | ||
related_issues[key] = func(group) | ||
|
||
return related_issues or {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Module to evaluate if groups have the same root cause | ||
# | ||
# The first case this module handles is environmental failures. | ||
# | ||
# Refer to README in module for more details. | ||
from typing import Any | ||
|
||
from sentry.models.group import Group | ||
|
||
|
||
def same_root_cause_analysis(group: Group) -> list[Group]: | ||
"""Analyze and create a group set if the group was caused by the same root cause.""" | ||
# XXX: This function is not optimal since we can't query the data field which is a GzippedDictField | ||
project_groups = Group.objects.filter(project=group.project_id) | ||
same_error_type_groups = [g for g in project_groups if compare_groups(g, group)] | ||
return same_error_type_groups or [] | ||
|
||
|
||
def compare_groups(groupA: Group, groupB: Group) -> bool: | ||
return match_criteria(_extract_values(groupA), _extract_values(groupB)) | ||
|
||
|
||
def match_criteria(a: dict[str, str | None], b: dict[str, str | None]) -> bool: | ||
# XXX: In future iterations we will be able to use similar titles rather than an exact match | ||
return a["type"] == b["type"] and a["title"] == b["title"] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is very simplistic but it works in a lot of cases. |
||
|
||
|
||
def _extract_values(group: Group) -> dict[str, Any]: | ||
return {"title": group.title, "type": group.data.get("metadata", {}).get("type")} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
from typing import Any | ||
|
||
from django.urls import reverse | ||
|
||
from sentry.testutils.cases import APITestCase | ||
from sentry.testutils.silo import region_silo_test | ||
|
||
|
||
@region_silo_test | ||
class RelatedIssuesTest(APITestCase): | ||
endpoint = "sentry-api-0-issues-related-issues" | ||
|
||
def setUp(self) -> None: | ||
super().setUp() | ||
self.login_as(user=self.user) | ||
self.organization = self.create_organization(owner=self.user) | ||
self.error_type = "ApiTimeoutError" | ||
self.error_value = "Timed out attempting to reach host: api.github.com" | ||
# You need to set this value in your test before calling the API | ||
self.group_id = None | ||
|
||
def reverse_url(self) -> str: | ||
return reverse(self.endpoint, kwargs={"issue_id": self.group_id}) | ||
|
||
def _data(self, type: str, value: str) -> dict[str, Any]: | ||
return {"type": "error", "metadata": {"type": type, "value": value}} | ||
|
||
def test_same_root_related_issues(self) -> None: | ||
# This is the group we're going to query about | ||
group = self.create_group(data=self._data(self.error_type, self.error_value)) | ||
self.group_id = group.id | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will allow |
||
|
||
groups_data = [ | ||
self._data("ApiError", self.error_value), | ||
self._data(self.error_type, "Unreacheable host: api.github.com"), | ||
self._data(self.error_type, ""), | ||
# Only this group will be related | ||
self._data(self.error_type, self.error_value), | ||
] | ||
# XXX: See if we can get this code to be closer to how save_event generates groups | ||
for datum in groups_data: | ||
self.create_group(data=datum) | ||
|
||
response = self.get_success_response() | ||
# The UI will then make normal calls to get issues-stats | ||
# For instance, this URL | ||
# https://us.sentry.io/api/0/organizations/sentry/issues-stats/?groups=4741828952&groups=4489703641&statsPeriod=24h | ||
assert response.json() == {"same_root_cause": [1, 5]} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is unbounded, you should use
RangeQuerySetWrapper
here and also limit the number of groups returnedThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would also probably be helpful to just fetch the fields you need rather than the entire
Group
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. Thanks, Dan!