Skip to content

Commit d43c82d

Browse files
committed
fix(metrics): preserve v2 for overridden endpoints
1 parent 2ca6bf3 commit d43c82d

4 files changed

Lines changed: 105 additions & 3 deletions

File tree

  • bin/agent-data-plane/src/cli
  • lib/saluki-components/src

bin/agent-data-plane/src/cli/run.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,8 @@ fn add_mrf_metrics_pipeline_to_blueprint(
518518

519519
let mrf_gateway_config = MrfMetricsGatewayConfiguration::new(mrf_config.clone(), config.clone());
520520
let mrf_metrics_config = DatadogMetricsConfiguration::from_configuration(config)
521-
.error_context("Failed to configure Multi-Region Failover Datadog Metrics encoder.")?;
521+
.error_context("Failed to configure Multi-Region Failover Datadog Metrics encoder.")?
522+
.with_metrics_endpoint_override(mrf_dd_url.clone());
522523

523524
let mrf_forwarder_config = DatadogForwarderConfiguration::from_configuration(config)
524525
.map(|config| {
@@ -571,7 +572,8 @@ fn add_autoscaling_failover_metrics_pipeline_to_blueprint(
571572

572573
let af_gateway_config = AutoscalingFailoverGatewayConfiguration::new(af_config);
573574
let af_metrics_config = DatadogMetricsConfiguration::from_configuration(config)
574-
.error_context("Failed to configure autoscaling failover metrics encoder.")?;
575+
.error_context("Failed to configure autoscaling failover metrics encoder.")?
576+
.with_v2_series_only();
575577
let cluster_agent_forwarder_config =
576578
ClusterAgentForwarderConfiguration::from_configuration(config, ca_url, ca_token)
577579
.error_context("Failed to configure Cluster Agent forwarder.")?;

lib/saluki-components/src/common/datadog/config.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,12 @@ impl ForwarderConfiguration {
395395
self.opw_metrics = OpwMetricsConfiguration::default();
396396
}
397397

398+
/// Forces series metrics routing to accept only V2 payloads.
399+
pub(crate) fn force_v2_series(&mut self) {
400+
self.data_plane_metrics_v3_series_enabled = false;
401+
self.v3_api.series.shadow_sites.clear();
402+
}
403+
398404
/// Builds resolved endpoints with routing metadata.
399405
///
400406
/// The normal primary and OPW metrics primary endpoints share the same dynamic API key source.

lib/saluki-components/src/encoders/datadog/metrics/mod.rs

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,16 +181,17 @@ fn selected_metrics_primary_endpoint<'a>(
181181
vector_use_v3_series: bool,
182182
) -> Option<(&'a str, bool)> {
183183
if opw_enabled {
184+
let opw_url = opw_url.trim();
184185
metrics_primary_url_can_resolve(opw_url).then_some((opw_url, opw_use_v3_series))
185186
} else if vector_enabled {
187+
let vector_url = vector_url.trim();
186188
metrics_primary_url_can_resolve(vector_url).then_some((vector_url, vector_use_v3_series))
187189
} else {
188190
None
189191
}
190192
}
191193

192194
fn metrics_primary_url_can_resolve(url: &str) -> bool {
193-
let url = url.trim();
194195
if url.is_empty() {
195196
return false;
196197
}
@@ -403,10 +404,14 @@ pub struct DatadogMetricsConfiguration {
403404
vector_metrics_use_v3_api_series: bool,
404405

405406
/// The Datadog site used to resolve the primary metrics endpoint.
407+
///
408+
/// Defaults to `datadoghq.com`.
406409
#[serde(default = "default_site")]
407410
site: String,
408411

409412
/// The optional explicit primary metrics endpoint.
413+
///
414+
/// Defaults to unset, in which case `site` determines the endpoint.
410415
#[serde(default, alias = "url", deserialize_with = "deserialize_dd_url")]
411416
dd_url: Option<String>,
412417

@@ -427,6 +432,27 @@ impl DatadogMetricsConfiguration {
427432
self
428433
}
429434

435+
/// Restricts endpoint-aware protocol selection to a single overridden metrics endpoint.
436+
///
437+
/// This mirrors a forwarder branch that replaces the normal primary endpoint and removes additional and
438+
/// OPW/Vector endpoints, such as Multi-Region Failover.
439+
pub fn with_metrics_endpoint_override(mut self, dd_url: String) -> Self {
440+
self.dd_url = Some(dd_url);
441+
self.additional_endpoints = AdditionalEndpoints::default();
442+
self.observability_pipelines_worker_metrics_enabled = false;
443+
self.vector_metrics_enabled = false;
444+
self
445+
}
446+
447+
/// Forces series metrics to use V2 without producing V3 shadow payloads.
448+
///
449+
/// This is used for local destinations that only accept the V2 series protocol, such as the Cluster Agent.
450+
pub fn with_v2_series_only(mut self) -> Self {
451+
self.data_plane_metrics_v3_series_enabled = false;
452+
self.v3_api.series.shadow_sample_rate = 0.0;
453+
self
454+
}
455+
430456
fn v3_payload_limits(&self) -> V3PayloadLimits {
431457
V3PayloadLimits::new(
432458
self.max_series_payload_size,
@@ -2057,6 +2083,52 @@ serializer_experimental_use_v3_api:
20572083
assert!(!config.requires_v2_series(false).expect("endpoints should resolve"));
20582084
}
20592085

2086+
#[test]
2087+
fn endpoint_override_uses_the_overridden_endpoint_protocol() {
2088+
let config = v3_series_config(
2089+
r#"
2090+
dd_url: https://primary.example.com
2091+
data_plane_metrics_v3_series_enabled: true
2092+
use_v3_api_series_enabled: "false"
2093+
serializer_experimental_use_v3_api:
2094+
series:
2095+
endpoints:
2096+
- https://primary.example.com
2097+
- https://v3-mrf.example.com
2098+
"#,
2099+
);
2100+
2101+
let v2_mrf_config = config
2102+
.clone()
2103+
.with_metrics_endpoint_override("https://v2-mrf.example.com".to_string());
2104+
let v3_mrf_config = config.with_metrics_endpoint_override("https://v3-mrf.example.com".to_string());
2105+
2106+
assert!(v2_mrf_config
2107+
.requires_v2_series(false)
2108+
.expect("V2 MRF endpoint should resolve"));
2109+
assert!(!v3_mrf_config
2110+
.requires_v2_series(false)
2111+
.expect("V3 MRF endpoint should resolve"));
2112+
}
2113+
2114+
#[test]
2115+
fn v2_series_only_override_keeps_v2_and_disables_shadowing() {
2116+
let config = v3_series_config(
2117+
r#"
2118+
data_plane_metrics_v3_series_enabled: true
2119+
use_v3_api_series_enabled: "true"
2120+
serializer_experimental_use_v3_api:
2121+
series:
2122+
shadow_sample_rate: 1.0
2123+
"#,
2124+
)
2125+
.with_v2_series_only();
2126+
2127+
assert!(!config.data_plane_metrics_v3_series_enabled);
2128+
assert_eq!(0.0, config.v3_api.series.shadow_sample_rate);
2129+
assert!(config.requires_v2_series(false).expect("endpoint should resolve"));
2130+
}
2131+
20602132
#[test]
20612133
fn agent_default_v3_does_not_enable_opw_only_encoder_mode() {
20622134
let series_config = UseV3ApiSeriesConfig::default();

lib/saluki-components/src/forwarders/cluster_agent/mod.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ impl ClusterAgentForwarderConfiguration {
5555
endpoint.set_dd_url(endpoint_url);
5656
endpoint.set_api_key(auth_token);
5757
forwarder_config.clear_opw_metrics_endpoint();
58+
forwarder_config.force_v2_series();
5859

5960
Ok(Self {
6061
forwarder_config,
@@ -250,13 +251,32 @@ mod tests {
250251
"enabled": true,
251252
"url": "https://opw.example.com"
252253
}
254+
},
255+
"data_plane_metrics_v3_series_enabled": true,
256+
"use_v3_api": {
257+
"series": {
258+
"enabled": "true"
259+
}
260+
},
261+
"serializer_experimental_use_v3_api": {
262+
"series": {
263+
"shadow_sites": ["example.com"]
264+
}
253265
}
254266
})),
255267
None,
256268
false,
257269
)
258270
.await;
259271

272+
let unmodified_forwarder =
273+
ForwarderConfiguration::from_configuration(&config).expect("forwarder configuration should parse");
274+
assert!(unmodified_forwarder.data_plane_metrics_v3_series_enabled());
275+
assert_eq!(
276+
&["example.com".to_string()],
277+
unmodified_forwarder.v3_api().series.shadow_sites.as_slice()
278+
);
279+
260280
let config = ClusterAgentForwarderConfiguration::from_configuration(
261281
&config,
262282
"https://cluster-agent.example.com".to_string(),
@@ -275,5 +295,7 @@ mod tests {
275295
"https://cluster-agent.example.com/"
276296
);
277297
assert_eq!(endpoints[0].endpoint().cached_api_key(), "secret-token");
298+
assert!(!config.forwarder_config.data_plane_metrics_v3_series_enabled());
299+
assert!(config.forwarder_config.v3_api().series.shadow_sites.is_empty());
278300
}
279301
}

0 commit comments

Comments
 (0)