Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"exclusive_time": 643.100167,
"description": "https://s1.sentry-cdn.com/_static/dist/sentry/chunks/app_components_charts_utils_tsx-app_utils_performance_quickTrace_utils_tsx-app_utils_withPage-3926ec.bc434924850c44d4057f.js",
"op": "resource.script",
"span_id": "b66a5642da1edb52",
"span_id": "c77b6753eb2fec63",
"parent_span_id": "a0c39078d1570b00",
"trace_id": "0102834d0bf74d388ce0b1e15329f731",
"data": {
Expand Down
9 changes: 0 additions & 9 deletions src/sentry/features/temporary.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ def register_temporary_features(manager: FeatureManager) -> None:
manager.add("organizations:alerts-timeseries-comparison", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=False)
# Enable anomaly detection feature for EAP spans
manager.add("organizations:anomaly-detection-eap", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enable anomaly detection threshold data endpoint
manager.add("organizations:anomaly-detection-threshold-data", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enables the cron job to auto-enable codecov integrations.
manager.add("organizations:auto-enable-codecov", OrganizationFeature, FeatureHandlerStrategy.INTERNAL, api_expose=False)
# Enabled for orgs that participated in the code review beta
Expand Down Expand Up @@ -169,13 +167,8 @@ def register_temporary_features(manager: FeatureManager) -> None:
manager.add("organizations:invite-members-rate-limits", OrganizationFeature, FeatureHandlerStrategy.INTERNAL, default=True, api_expose=False)
# Enables streamlined issue details UI for all users of an organization without opt-out
manager.add("organizations:issue-details-streamline-enforce", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enables sorting spans for issue detection
manager.add("organizations:issue-detection-sort-spans", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enable AI-generated titles for issue views
manager.add("organizations:issue-view-ai-title", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enable Large HTTP Payload Detector Improvements
manager.add("organizations:large-http-payload-detector-improvements", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)

manager.add("organizations:mep-use-default-tags", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=False)
# Migrate Orgs to new Azure DevOps Integration
manager.add("organizations:migrate-azure-devops-integration", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
Expand Down Expand Up @@ -393,8 +386,6 @@ def register_temporary_features(manager: FeatureManager) -> None:
manager.add("organizations:sentry-toolbar-ui", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, default=False, api_expose=True)
# Enable suspect feature flags endpoint.
manager.add("organizations:feature-flag-suspect-flags", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enable suspect commit information in workflow notification emails
manager.add("organizations:suspect-commits-in-emails", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, default=False, api_expose=False)
# Enable suspect feature tags endpoint.
manager.add("organizations:issues-suspect-tags", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Lets organizations manage grouping configs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from datetime import timedelta
from typing import Any

from sentry import features
from sentry.issues.grouptype import PerformanceLargeHTTPPayloadGroupType
from sentry.issues.issue_occurrence import IssueEvidence
from sentry.models.organization import Organization
Expand Down Expand Up @@ -133,12 +132,8 @@ def _is_span_eligible(self, span: Span) -> bool:
if span_data and span_data.get("http.request.prefetch"):
return False

if features.has(
"organizations:large-http-payload-detector-improvements",
self.organization,
):
if any(path in description for path in self.filtered_paths):
return False
if any(path in description for path in self.filtered_paths):
return False

return True

Expand Down
19 changes: 9 additions & 10 deletions src/sentry/issue_detection/performance_detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import sentry_sdk

from sentry import features, nodestore, options, projectoptions
from sentry import nodestore, options, projectoptions
from sentry.models.options.project_option import ProjectOption
from sentry.models.organization import Organization
from sentry.models.project import Project
Expand Down Expand Up @@ -348,15 +348,14 @@ def _detect_performance_problems(
with sentry_sdk.start_span(op="function", name="get_detection_settings"):
detection_settings = get_detection_settings(project.id, organization)

if standalone or features.has("organizations:issue-detection-sort-spans", organization):
# The performance detectors expect the span list to be ordered/flattened in the way they
# are structured in the tree. This is an implicit assumption in the performance detectors.
# So we build a tree and flatten it depth first.
# TODO: See if we can update the detectors to work without this assumption so we can
# just pass it a list of spans.
with sentry_sdk.start_span(op="performance_detection", name="sort_spans"):
tree, segment_id = build_tree(data.get("spans", []))
data = {**data, "spans": flatten_tree(tree, segment_id)}
# The performance detectors expect the span list to be ordered/flattened in the way they
# are structured in the tree. This is an implicit assumption in the performance detectors.
# So we build a tree and flatten it depth first.
# TODO: See if we can update the detectors to work without this assumption so we can
# just pass it a list of spans.
with sentry_sdk.start_span(op="performance_detection", name="sort_spans"):
tree, segment_id = build_tree(data.get("spans", []))
data = {**data, "spans": flatten_tree(tree, segment_id)}

with sentry_sdk.start_span(op="initialize", name="PerformanceDetector"):
detectors: list[PerformanceDetector] = [
Expand Down
6 changes: 1 addition & 5 deletions src/sentry/notifications/notifications/activity/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from django.utils.html import format_html
from django.utils.safestring import SafeString

from sentry import features
from sentry.db.models import Model
from sentry.integrations.types import ExternalProviders
from sentry.notifications.helpers import get_reason_context
Expand Down Expand Up @@ -140,10 +139,7 @@ def get_context(self, provider: ExternalProviders | None = None) -> MutableMappi
"enhanced_privacy": enhanced_privacy,
}

if (
features.has("organizations:suspect-commits-in-emails", self.group.organization)
and self.group
):
if self.group:
context["commits"] = get_suspect_commits_by_group_id(
project=self.project, group_id=self.group.id
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from rest_framework.request import Request
from rest_framework.response import Response

from sentry import features
from sentry.api.api_owners import ApiOwner
from sentry.api.api_publish_status import ApiPublishStatus
from sentry.api.base import region_silo_endpoint
Expand Down Expand Up @@ -112,11 +111,6 @@ def get(self, request: Request, organization: Organization, detector_id: str) ->

Pass `legacy_alert=true` query param to treat detector_id as a legacy alert rule ID.
"""
if not features.has(
"organizations:anomaly-detection-threshold-data", organization, actor=request.user
):
raise ResourceDoesNotExist

start = request.GET.get("start")
end = request.GET.get("end")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe('MetricDetectorDetailsChart', () => {

describe('anomaly threshold cutoff message', () => {
const organization = OrganizationFixture({
features: ['anomaly-detection-threshold-data', 'visibility-explore-view'],
features: ['visibility-explore-view'],
});

const anomalyDetector = MetricDetectorFixture({
Expand Down
15 changes: 15 additions & 0 deletions static/app/views/detectors/edit.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,11 @@ describe('DetectorEdit', () => {
body: mockDetector,
});

MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/detectors/${mockDetector.id}/anomaly-data/`,
body: [],
});

render(<DetectorEdit />, {
organization,
initialRouterConfig,
Expand Down Expand Up @@ -673,6 +678,11 @@ describe('DetectorEdit', () => {
body: dynamicDetector,
});

MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/detectors/${dynamicDetector.id}/anomaly-data/`,
body: [],
});

render(<DetectorEdit />, {
organization,
initialRouterConfig: {
Expand All @@ -699,6 +709,11 @@ describe('DetectorEdit', () => {
body: mockDetector,
});

MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/detectors/${mockDetector.id}/anomaly-data/`,
body: [],
});

// Current data for chart
MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/events-stats/`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ describe('useMetricDetectorAnomalyThresholds', () => {
});

it('does not fetch data when detectionType is not dynamic', () => {
const organization = OrganizationFixture({
features: ['anomaly-detection-threshold-data'],
});
const organization = OrganizationFixture();

const anomalyDataRequest = MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/detectors/123/anomaly-data/`,
Expand Down Expand Up @@ -42,9 +40,7 @@ describe('useMetricDetectorAnomalyThresholds', () => {
});

it('fetches data when detectionType is dynamic', async () => {
const organization = OrganizationFixture({
features: ['anomaly-detection-threshold-data'],
});
const organization = OrganizationFixture();

const mockData = [
{
Expand Down Expand Up @@ -86,9 +82,7 @@ describe('useMetricDetectorAnomalyThresholds', () => {
});

it('does not fetch data when detectionType is undefined', () => {
const organization = OrganizationFixture({
features: ['anomaly-detection-threshold-data'],
});
const organization = OrganizationFixture();

const anomalyDataRequest = MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/detectors/123/anomaly-data/`,
Expand Down Expand Up @@ -118,9 +112,7 @@ describe('useMetricDetectorAnomalyThresholds', () => {
});

it('includes legacy_alert query param when isLegacyAlert is true', async () => {
const organization = OrganizationFixture({
features: ['anomaly-detection-threshold-data'],
});
const organization = OrganizationFixture();

const mockData = [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ export function useMetricDetectorAnomalyThresholds({
const organization = useOrganization();
const theme = useTheme();

const hasAnomalyDataFlag = organization.features.includes(
'anomaly-detection-threshold-data'
);
const isAnomalyDetection = detectionType === 'dynamic';

const {
Expand All @@ -82,9 +79,7 @@ export function useMetricDetectorAnomalyThresholds({
{
staleTime: 0,
enabled:
hasAnomalyDataFlag &&
isAnomalyDetection &&
Boolean(detectorId && startTimestamp && endTimestamp),
isAnomalyDetection && Boolean(detectorId && startTimestamp && endTimestamp),
}
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -805,9 +805,7 @@ function ProjectPerformance() {
performanceIssueSettings[DetectorConfigAdmin.LARGE_HTTP_PAYLOAD_ENABLED]
),
disabledReason,
visible: organization.features.includes(
'large-http-payload-detector-improvements'
),
visible: true,
},
],
initiallyCollapsed: issueType !== IssueType.PERFORMANCE_LARGE_HTTP_PAYLOAD,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from sentry.incidents.grouptype import MetricIssue
from sentry.snuba.subscriptions import create_snuba_subscription
from sentry.testutils.cases import APITestCase
from sentry.testutils.helpers.features import with_feature
from sentry.testutils.skips import requires_snuba
from sentry.workflow_engine.models import DataSourceDetector
from tests.sentry.workflow_engine.test_base import BaseWorkflowTest
Expand Down Expand Up @@ -39,7 +38,6 @@ def setUp(self):
data_source=self.data_source, detector=self.detector
)

@with_feature("organizations:anomaly-detection-threshold-data")
def test_missing_parameters(self):
response = self.get_error_response(
self.organization.slug, self.detector.id, end="1729179000.0", status_code=400
Expand All @@ -51,7 +49,6 @@ def test_missing_parameters(self):
)
assert response.data["detail"] == "start and end parameters are required"

@with_feature("organizations:anomaly-detection-threshold-data")
def test_invalid_parameters(self):
response = self.get_error_response(
self.organization.slug,
Expand All @@ -62,7 +59,6 @@ def test_invalid_parameters(self):
)
assert response.data["detail"] == "start and end must be valid timestamps"

@with_feature("organizations:anomaly-detection-threshold-data")
def test_no_subscription_found(self):
# Delete the data source to simulate missing subscription
DataSourceDetector.objects.filter(detector=self.detector).delete()
Expand All @@ -75,7 +71,6 @@ def test_no_subscription_found(self):
)
assert response.data["detail"] == "Could not find query subscription for detector"

@with_feature("organizations:anomaly-detection-threshold-data")
@patch(
"sentry.workflow_engine.endpoints.organization_detector_anomaly_data.get_anomaly_threshold_data_from_seer"
)
Expand All @@ -91,7 +86,6 @@ def test_seer_error(self, mock_get_data):
)
assert response.data["detail"] == "Unable to fetch anomaly detection threshold data"

@with_feature("organizations:anomaly-detection-threshold-data")
@patch(
"sentry.workflow_engine.endpoints.organization_detector_anomaly_data.get_anomaly_threshold_data_from_seer"
)
Expand All @@ -118,7 +112,6 @@ def test_successful_fetch(self, mock_get_data):
assert mock_get_data.call_args.kwargs["start"] == 1729178100.0
assert mock_get_data.call_args.kwargs["end"] == 1729179000.0

@with_feature("organizations:anomaly-detection-threshold-data")
def test_permission_denied(self):
self.login_as(self.create_user())

Expand All @@ -130,17 +123,6 @@ def test_permission_denied(self):
status_code=403,
)

def test_feature_flag_disabled(self):
"""Test that endpoint returns 404 when feature flag is disabled"""
self.get_error_response(
self.organization.slug,
self.detector.id,
start="1729178100.0",
end="1729179000.0",
status_code=404,
)

@with_feature("organizations:anomaly-detection-threshold-data")
def test_invalid_detector_id(self):
"""Test that non-numeric detector IDs return 404"""
self.get_error_response(
Expand Down Expand Up @@ -177,7 +159,6 @@ def setUp(self):
self.alert_rule.snuba_query = self.snuba_query
self.alert_rule.save()

@with_feature("organizations:anomaly-detection-threshold-data")
@patch(
"sentry.workflow_engine.endpoints.organization_detector_anomaly_data.get_anomaly_threshold_data_from_seer"
)
Expand Down Expand Up @@ -208,7 +189,6 @@ def test_successful_fetch_legacy_alert(self, mock_get_data):
# Verify the subscription passed to seer is the one linked to the alert rule
assert mock_get_data.call_args.kwargs["subscription"] == self.subscription

@with_feature("organizations:anomaly-detection-threshold-data")
def test_legacy_alert_not_found(self):
"""Test that non-existent alert rule ID returns 404."""
self.get_error_response(
Expand All @@ -220,7 +200,6 @@ def test_legacy_alert_not_found(self):
status_code=404,
)

@with_feature("organizations:anomaly-detection-threshold-data")
def test_legacy_alert_missing_subscription(self):
"""Test error when alert rule has no query subscription."""
# Delete the subscription to simulate missing subscription
Expand All @@ -236,7 +215,6 @@ def test_legacy_alert_missing_subscription(self):
)
assert response.data["detail"] == "Could not find query subscription for alert rule"

@with_feature("organizations:anomaly-detection-threshold-data")
@patch(
"sentry.workflow_engine.endpoints.organization_detector_anomaly_data.get_anomaly_threshold_data_from_seer"
)
Expand All @@ -254,7 +232,6 @@ def test_legacy_alert_seer_error(self, mock_get_data):
)
assert response.data["detail"] == "Unable to fetch anomaly detection threshold data"

@with_feature("organizations:anomaly-detection-threshold-data")
def test_legacy_alert_permission_denied(self):
"""Test that users without access get 403."""
self.login_as(self.create_user())
Expand All @@ -267,14 +244,3 @@ def test_legacy_alert_permission_denied(self):
end="1729179000.0",
status_code=403,
)

def test_legacy_alert_feature_flag_disabled(self):
"""Test that endpoint returns 404 when feature flag is disabled."""
self.get_error_response(
self.organization.slug,
self.alert_rule.id,
legacy_alert="true",
start="1729178100.0",
end="1729179000.0",
status_code=404,
)
Loading
Loading