From 6af75df5f72bb639140bb491b27d759c82936e68 Mon Sep 17 00:00:00 2001 From: David Herberth Date: Wed, 6 May 2026 18:23:45 +0200 Subject: [PATCH] ref(otel): Graduate otel endpoints/features --- CHANGELOG.md | 6 ++ relay-dynamic-config/src/feature.rs | 24 +++-- relay-dynamic-config/src/project.rs | 12 ++- .../src/endpoints/integrations/otlp.rs | 3 +- tests/integration/test_otlp_logs.py | 3 - tests/integration/test_spans.py | 100 ------------------ tests/integration/test_spansv2_otel.py | 5 +- 7 files changed, 30 insertions(+), 123 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4ca247dee2..869e404b31d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +**Features**: + +- Enable OTLP endpoints by default. ([#5951](https://github.com/getsentry/relay/pull/5951)) + ## 26.4.2 **Features**: diff --git a/relay-dynamic-config/src/feature.rs b/relay-dynamic-config/src/feature.rs index b952cf1402a..6febf8f625e 100644 --- a/relay-dynamic-config/src/feature.rs +++ b/relay-dynamic-config/src/feature.rs @@ -7,6 +7,8 @@ use serde::{Deserialize, Serialize}; pub const GRADUATED_FEATURE_FLAGS: &[Feature] = &[ Feature::UserReportV2Ingest, Feature::IngestUnsampledProfiles, + Feature::DeprecatedOtelTracesEndpoint, + Feature::DeprecatedOtelLogsEndpoint, Feature::DeprecatedExtractSpansFromEvent, Feature::DeprecatedStandaloneSpanIngestion, ]; @@ -39,16 +41,6 @@ pub enum Feature { /// Serialized as `organizations:profiling`. #[serde(rename = "organizations:profiling")] Profiling, - /// Enable standalone span ingestion via the `/traces/` OTel endpoint. - /// - /// Serialized as `organizations:relay-otlp-traces-endpoint`. - #[serde(rename = "organizations:relay-otlp-traces-endpoint")] - OtelTracesEndpoint, - /// Enable logs ingestion via the `/logs/` OTel endpoint. - /// - /// Serialized as `organizations:relay-otel-logs-endpoint`. - #[serde(rename = "organizations:relay-otel-logs-endpoint")] - OtelLogsEndpoint, /// Enable playstation crash dump ingestion via the `/playstation/` endpoint. /// /// Serialized as `organizations:relay-playstation-ingestion`. @@ -134,6 +126,18 @@ pub enum Feature { #[doc(hidden)] #[serde(rename = "organizations:indexed-spans-extraction")] DeprecatedExtractSpansFromEvent, + /// Enable standalone span ingestion via the `/traces/` OTel endpoint. + /// + /// This feature has graduated and is hard-coded for external Relays. + #[doc(hidden)] + #[serde(rename = "organizations:relay-otlp-traces-endpoint")] + DeprecatedOtelTracesEndpoint, + /// Enable logs ingestion via the `/logs/` OTel endpoint. + /// + /// This feature has graduated and is hard-coded for external Relays. + #[doc(hidden)] + #[serde(rename = "organizations:relay-otel-logs-endpoint")] + DeprecatedOtelLogsEndpoint, /// Enable standalone span ingestion. /// /// Serialized as `organizations:standalone-span-ingestion`. diff --git a/relay-dynamic-config/src/project.rs b/relay-dynamic-config/src/project.rs index e52ceda1732..9efe7e57d32 100644 --- a/relay-dynamic-config/src/project.rs +++ b/relay-dynamic-config/src/project.rs @@ -293,15 +293,19 @@ fn is_false(value: &bool) -> bool { #[cfg(test)] mod tests { - use crate::Feature; - use super::*; #[test] fn graduated_feature_flag_gets_inserted() { let mut project_config = ProjectConfig::default(); - assert!(!project_config.features.has(Feature::UserReportV2Ingest)); + for feature in GRADUATED_FEATURE_FLAGS { + assert!(!project_config.features.has(*feature)); + } + project_config.sanitize(false); - assert!(project_config.features.has(Feature::UserReportV2Ingest)); + + for feature in GRADUATED_FEATURE_FLAGS { + assert!(project_config.features.has(*feature)); + } } } diff --git a/relay-server/src/endpoints/integrations/otlp.rs b/relay-server/src/endpoints/integrations/otlp.rs index 12f5d2c27d0..44a07616c78 100644 --- a/relay-server/src/endpoints/integrations/otlp.rs +++ b/relay-server/src/endpoints/integrations/otlp.rs @@ -40,7 +40,6 @@ mod traces { let envelope = builder .with_type(SpansIntegration::OtelV1 { format }) - .with_required_feature(Feature::OtelTracesEndpoint) .build(); common::handle_envelope(&state, envelope) @@ -71,7 +70,7 @@ mod logs { let envelope = builder .with_type(LogsIntegration::OtelV1 { format }) - .with_required_feature(Feature::OtelLogsEndpoint) + .with_required_feature(Feature::OurLogsIngestion) .build(); common::handle_envelope(&state, envelope) diff --git a/tests/integration/test_otlp_logs.py b/tests/integration/test_otlp_logs.py index ef3c1b43eb9..188bdd84488 100644 --- a/tests/integration/test_otlp_logs.py +++ b/tests/integration/test_otlp_logs.py @@ -22,7 +22,6 @@ def test_otlp_logs_conversion( project_config = mini_sentry.add_full_project_config(project_id) project_config["config"]["features"] = [ "organizations:ourlogs-ingestion", - "organizations:relay-otel-logs-endpoint", ] project_config["config"]["retentions"] = { "log": {"standard": 30, "downsampled": 13 * 30}, @@ -189,7 +188,6 @@ def test_otlp_logs_multiple_records( project_config = mini_sentry.add_full_project_config(project_id) project_config["config"]["features"] = [ "organizations:ourlogs-ingestion", - "organizations:relay-otel-logs-endpoint", ] project_config["config"]["retentions"] = { "log": {"standard": 30, "downsampled": 13 * 30}, @@ -324,7 +322,6 @@ def test_otlp_logs_size_limits(mini_sentry, relay): project_config = mini_sentry.add_full_project_config(project_id) project_config["config"]["features"] = [ "organizations:ourlogs-ingestion", - "organizations:relay-otel-logs-endpoint", ] relay = relay(mini_sentry, options={"limits": {"max_log_size": 50}, **TEST_CONFIG}) diff --git a/tests/integration/test_spans.py b/tests/integration/test_spans.py index 9a4bcb6b891..702ca218ce1 100644 --- a/tests/integration/test_spans.py +++ b/tests/integration/test_spans.py @@ -10,7 +10,6 @@ from sentry_relay.consts import DataCategory from sentry_sdk.envelope import Envelope, Item, PayloadRef -from .asserts import time_within_delta from .test_store import make_transaction TEST_CONFIG = { @@ -476,105 +475,6 @@ def envelope_with_transaction_and_spans(start: datetime, end: datetime) -> Envel return envelope -def make_otel_span(start, end): - return { - "resourceSpans": [ - { - "scopeSpans": [ - { - "spans": [ - { - "traceId": "89143b0763095bd9c9955e8175d1fb24", - "spanId": "d342abb1214ca182", - "name": "my 2nd OTel span", - "startTimeUnixNano": str(int(start.timestamp() * 1e9)), - "endTimeUnixNano": str(int(end.timestamp() * 1e9)), - "kind": 4, - "attributes": [ - { - "key": "sentry.exclusive_time", - "value": { - "doubleValue": (end - start).total_seconds() - * 1e3, - }, - }, - ], - "links": [ - { - "traceId": "89143b0763095bd9c9955e8175d1fb24", - "spanId": "e342abb1214ca183", - "attributes": [ - { - "key": "link_int_key", - "value": { - "intValue": "123", - }, - }, - ], - }, - ], - }, - ], - }, - ], - }, - ], - } - - -def test_otel_endpoint_disabled(mini_sentry, relay): - relay = relay( - mini_sentry, - { - "outcomes": { - "emit_outcomes": True, - "batch_size": 1, - "batch_interval": 1, - "source": "relay", - } - }, - ) - project_id = 42 - mini_sentry.add_full_project_config(project_id) - - end = datetime.now(timezone.utc) - timedelta(seconds=1) - start = end - timedelta(milliseconds=500) - relay.send_otel_span( - project_id, - json=make_otel_span(start, end), - ) - - assert mini_sentry.get_outcomes(2) == [ - { - "org_id": 1, - "key_id": 123, - "project_id": 42, - "outcome": 3, - "reason": "feature_disabled", - "category": category.value, - "quantity": 1, - "source": "relay", - "timestamp": time_within_delta(), - } - for category in [DataCategory.SPAN, DataCategory.SPAN_INDEXED] - ] - - # Second attempt will cause a 403 response: - with pytest.raises(HTTPError) as exc_info: - relay.send_otel_span( - project_id, - json=make_otel_span(start, end), - ) - response = exc_info.value.response - assert response.status_code == 403 - assert response.json() == { - "detail": "event submission rejected with_reason: FeatureDisabled(OtelTracesEndpoint)" - } - - # No envelopes were received: - assert mini_sentry.captured_envelopes.empty() - - def test_span_ingestion_with_performance_scores( mini_sentry, relay_with_processing, spans_consumer ): diff --git a/tests/integration/test_spansv2_otel.py b/tests/integration/test_spansv2_otel.py index 60fd6060ea8..4d297b13939 100644 --- a/tests/integration/test_spansv2_otel.py +++ b/tests/integration/test_spansv2_otel.py @@ -48,10 +48,7 @@ def test_span_ingestion( relay = relay(relay_with_processing()) project_id = 42 - project_config = mini_sentry.add_full_project_config(project_id) - project_config["config"]["features"] = [ - "organizations:relay-otlp-traces-endpoint", - ] + mini_sentry.add_full_project_config(project_id) ts = datetime.now(timezone.utc)