Skip to content

Commit 7900d40

Browse files
authored
feat(issues): Add project-level enable option for LLM issue detection (#112710)
Add `ai_issue_detection_enabled` to the performance issue detection settings. also adds settings for specific issue types and filtering for those issue types if the setting is off
1 parent 5aa127c commit 7900d40

File tree

3 files changed

+43
-0
lines changed

3 files changed

+43
-0
lines changed

src/sentry/issues/endpoints/project_performance_issue_settings.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
update_performance_settings,
1919
)
2020
from sentry.issues.grouptype import (
21+
AIDetectedGeneralGroupType,
2122
GroupType,
2223
PerformanceConsecutiveDBQueriesGroupType,
2324
PerformanceConsecutiveHTTPQueriesGroupType,
@@ -85,6 +86,13 @@ class ConfigurableThresholds(Enum):
8586
SQL_INJECTION_QUERY_VALUE_LENGTH = "sql_injection_query_value_length_threshold"
8687
WEB_VITALS = "web_vitals_detection_enabled"
8788
WEB_VITALS_COUNT = "web_vitals_count"
89+
AI_ISSUE_DETECTION = "ai_issue_detection_enabled"
90+
AI_DETECTED_HTTP = "ai_detected_http_enabled"
91+
AI_DETECTED_DB = "ai_detected_db_enabled"
92+
AI_DETECTED_RUNTIME_PERFORMANCE = "ai_detected_runtime_performance_enabled"
93+
AI_DETECTED_SECURITY = "ai_detected_security_enabled"
94+
AI_DETECTED_CODE_HEALTH = "ai_detected_code_health_enabled"
95+
AI_DETECTED_GENERAL = "ai_detected_general_enabled"
8896

8997

9098
project_settings_to_group_map: dict[str, type[GroupType]] = {
@@ -103,6 +111,7 @@ class ConfigurableThresholds(Enum):
103111
InternalProjectOptions.FUNCTION_DURATION_REGRESSION.value: ProfileFunctionRegressionType,
104112
ConfigurableThresholds.DB_QUERY_INJECTION.value: QueryInjectionVulnerabilityGroupType,
105113
ConfigurableThresholds.WEB_VITALS.value: WebVitalsGroup,
114+
ConfigurableThresholds.AI_ISSUE_DETECTION.value: AIDetectedGeneralGroupType,
106115
}
107116
"""
108117
A mapping of the management settings to the group type that the detector spawns.
@@ -125,6 +134,12 @@ class ConfigurableThresholds(Enum):
125134
ConfigurableThresholds.HTTP_OVERHEAD_REQUEST_DELAY.value: ConfigurableThresholds.HTTP_OVERHEAD.value,
126135
ConfigurableThresholds.SQL_INJECTION_QUERY_VALUE_LENGTH.value: ConfigurableThresholds.DB_QUERY_INJECTION.value,
127136
ConfigurableThresholds.WEB_VITALS_COUNT.value: ConfigurableThresholds.WEB_VITALS.value,
137+
ConfigurableThresholds.AI_DETECTED_HTTP.value: ConfigurableThresholds.AI_ISSUE_DETECTION.value,
138+
ConfigurableThresholds.AI_DETECTED_DB.value: ConfigurableThresholds.AI_ISSUE_DETECTION.value,
139+
ConfigurableThresholds.AI_DETECTED_RUNTIME_PERFORMANCE.value: ConfigurableThresholds.AI_ISSUE_DETECTION.value,
140+
ConfigurableThresholds.AI_DETECTED_SECURITY.value: ConfigurableThresholds.AI_ISSUE_DETECTION.value,
141+
ConfigurableThresholds.AI_DETECTED_CODE_HEALTH.value: ConfigurableThresholds.AI_ISSUE_DETECTION.value,
142+
ConfigurableThresholds.AI_DETECTED_GENERAL.value: ConfigurableThresholds.AI_ISSUE_DETECTION.value,
128143
}
129144
"""
130145
A mapping of threshold setting to the parent setting that manages it's detection.
@@ -199,6 +214,13 @@ class ProjectPerformanceIssueSettingsSerializer(serializers.Serializer):
199214
function_duration_regression_detection_enabled = serializers.BooleanField(required=False)
200215
db_query_injection_detection_enabled = serializers.BooleanField(required=False)
201216
web_vitals_detection_enabled = serializers.BooleanField(required=False)
217+
ai_issue_detection_enabled = serializers.BooleanField(required=False)
218+
ai_detected_http_enabled = serializers.BooleanField(required=False)
219+
ai_detected_db_enabled = serializers.BooleanField(required=False)
220+
ai_detected_runtime_performance_enabled = serializers.BooleanField(required=False)
221+
ai_detected_security_enabled = serializers.BooleanField(required=False)
222+
ai_detected_code_health_enabled = serializers.BooleanField(required=False)
223+
ai_detected_general_enabled = serializers.BooleanField(required=False)
202224
sql_injection_query_value_length_threshold = serializers.IntegerField(
203225
required=False, min_value=3, max_value=10
204226
)

src/sentry/projectoptions/defaults.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
"function_duration_regression_detection_enabled": True,
107107
"db_query_injection_detection_enabled": False,
108108
"web_vitals_detection_enabled": True,
109+
"ai_issue_detection_enabled": True,
109110
}
110111

111112
DEFAULT_PROJECT_PERFORMANCE_GENERAL_SETTINGS = {

src/sentry/tasks/llm_issue_detection/detection.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,15 @@ def get_base_platform(platform: str | None) -> str | None:
168168
"Deprecation Warning": AIDetectedCodeHealthGroupType,
169169
}
170170

171+
GROUP_TYPE_TO_SETTING: dict[type[GroupType], str] = {
172+
AIDetectedHTTPGroupType: "ai_detected_http_enabled",
173+
AIDetectedDBGroupType: "ai_detected_db_enabled",
174+
AIDetectedRuntimePerformanceGroupType: "ai_detected_runtime_performance_enabled",
175+
AIDetectedSecurityGroupType: "ai_detected_security_enabled",
176+
AIDetectedCodeHealthGroupType: "ai_detected_code_health_enabled",
177+
AIDetectedGeneralGroupType: "ai_detected_general_enabled",
178+
}
179+
171180

172181
def get_group_type_for_title(title: str) -> type[GroupType]:
173182
return TITLE_TO_GROUP_TYPE.get(title, AIDetectedGeneralGroupType)
@@ -180,6 +189,13 @@ def create_issue_occurrence_from_detection(
180189
"""
181190
Create and produce an IssueOccurrence from an LLM-detected issue.
182191
"""
192+
group_type = get_group_type_for_title(detected_issue.title)
193+
setting_key = GROUP_TYPE_TO_SETTING.get(group_type)
194+
if setting_key:
195+
perf_settings = project.get_option("sentry:performance_issue_settings", default={})
196+
if not perf_settings.get(setting_key, True):
197+
return
198+
183199
event_id = uuid4().hex
184200
occurrence_id = uuid4().hex
185201
detection_time = datetime.now(UTC)
@@ -307,6 +323,10 @@ def detect_llm_issues_for_project(project_id: int) -> None:
307323
if not has_access:
308324
return
309325

326+
perf_settings = project.get_option("sentry:performance_issue_settings", default={})
327+
if not perf_settings.get("ai_issue_detection_enabled", True):
328+
return
329+
310330
evidence_traces = get_project_top_transaction_traces_for_llm_detection(
311331
project_id, limit=TRANSACTION_BATCH_SIZE, start_time_delta_minutes=START_TIME_DELTA_MINUTES
312332
)

0 commit comments

Comments
 (0)