Skip to content

Dual shipping metrics support#704

Merged
shreyamalpani merged 9 commits intomainfrom
shreya.malpani/dual-ship-metrics-new
Jun 11, 2025
Merged

Dual shipping metrics support#704
shreyamalpani merged 9 commits intomainfrom
shreya.malpani/dual-ship-metrics-new

Conversation

@shreyamalpani
Copy link
Copy Markdown
Contributor

@shreyamalpani shreyamalpani commented Jun 9, 2025

Adds support for dual shipping metrics to endpoints configured using the additional_endpoints YAML or DD_ADDITIONAL_ENDPOINTS env var config.

For each configured endpoint/API key combination, we now create a separate MetricsFlusher to flush the same batch of metrics to multiple endpoints in parallel. Also, updates the retry logic to retry flushing for the specific flusher that encountered an error.

Tested dual shipping metrics to 2 additional orgs/endpoints including eu1.

Depends on dogstatsd changes: DataDog/serverless-components#20

SVLS-6884

@shreyamalpani shreyamalpani marked this pull request as ready for review June 9, 2025 17:18
@shreyamalpani shreyamalpani requested a review from a team as a code owner June 9, 2025 17:18
@astuyve
Copy link
Copy Markdown
Contributor

astuyve commented Jun 9, 2025

Can you rebase this with main? it's got a bunch of old commits which landed there a while ago

@shreyamalpani shreyamalpani force-pushed the shreya.malpani/dual-ship-metrics-new branch from cf7be12 to d05296e Compare June 9, 2025 20:34
@shreyamalpani shreyamalpani force-pushed the shreya.malpani/dual-ship-metrics-new branch from d05296e to e09063e Compare June 9, 2025 21:10
@astuyve astuyve requested a review from Copilot June 10, 2025 15:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Adds support for dual shipping metrics by introducing an additional_endpoints config field (from YAML or DD_ADDITIONAL_ENDPOINTS), wiring it into the EnvConfig merge logic, and updating component revisions.

  • Deserialize and test additional_endpoints in both YAML and env contexts
  • Merge additional_endpoints into EnvConfig when not provided via env
  • Bump serverless-components revisions; accidental license removal in LICENSE-3rdparty.yml

Reviewed Changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
bottlecap/src/config/yaml.rs Added additional_endpoints field and YAML parsing test
bottlecap/src/config/mod.rs Merge logic for additional_endpoints into runtime config
bottlecap/src/config/env.rs deserialize_additional_endpoints function, struct field, and tests
bottlecap/LICENSE-3rdparty.yml Removed third-party license block for datadog-fips
bottlecap/Cargo.toml Updated serverless-components git revisions
Comments suppressed due to low confidence (4)

bottlecap/LICENSE-3rdparty.yml:4239

  • The license block for datadog-fips was removed, which may violate third-party license compliance. Please restore the removed Apache-2.0 license text.
-         Licensed under the Apache License, Version 2.0 (the "License");

bottlecap/src/config/mod.rs:249

  • There’s no test for the merge behavior when both env and YAML provide additional_endpoints. Consider adding a unit test to validate that EnvConfig picks the correct source.
if config.additional_endpoints.is_empty() {

bottlecap/src/config/env.rs:4

  • The function deserialize_additional_endpoints relies on serde_json::Value but it isn’t imported; add use serde_json::Value; so the code will compile.
use tracing::error;

bottlecap/src/config/env.rs:292

  • The signature of deserialize_additional_endpoints expects a Deserializer, but in tests you’re passing a Value directly. Consider refactoring the function to accept a Value or use a proper Deserializer (e.g., serde_json::value::Deserializer) in tests.
let result = deserialize_additional_endpoints(input).unwrap();

Comment thread bottlecap/Cargo.toml
metric_flush_handles: FuturesOrdered<JoinHandle<MetricsRetryBatch>>,
}

struct MetricsRetryBatch {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventually we should move this to a metrics owned folder

Comment thread bottlecap/src/config/env.rs Outdated
Comment thread bottlecap/src/bin/bottlecap/main.rs Outdated
async fn blocking_flush_all(
logs_flusher: &LogsFlusher,
metrics_flusher: &mut MetricsFlusher,
metrics_flusher: &mut [MetricsFlusher],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we be more explicit here with Vec<...>? Just for readability

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially had this as Vec<...> but clippy doesn't like it

Comment thread bottlecap/src/bin/bottlecap/main.rs Outdated
tokio::join!(
logs_flusher.flush(None),
metrics_flusher.flush(),
futures::future::join_all(metrics_futures),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

Comment thread bottlecap/src/bin/bottlecap/main.rs
Comment on lines +916 to +932
for (endpoint_url, api_keys) in &config.additional_endpoints {
let dd_url = DdUrl::new(endpoint_url.clone()).expect("can't parse additional endpoint URL");
let prefix_override = MetricsIntakeUrlPrefixOverride::maybe_new(Some(dd_url), None);
let metrics_intake_url = MetricsIntakeUrlPrefix::new(None, prefix_override)
.expect("can't parse additional endpoint URL");

// Create a flusher for each endpoint URL and API key pair
for api_key in api_keys {
let additional_flusher_config = MetricsFlusherConfig {
api_key: api_key.clone(),
aggregator: metrics_aggr.clone(),
metrics_intake_url_prefix: metrics_intake_url.clone(),
https_proxy: config.https_proxy.clone(),
timeout: Duration::from_secs(config.flush_timeout),
retry_strategy: DsdRetryStrategy::Immediate(3),
};
flushers.push(MetricsFlusher::new(additional_flusher_config));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if this logic should live in main, not something to address now

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about this too, I can work on refactoring this when implementing dual shipping for log/traces if that could live together?

Comment thread bottlecap/src/bin/bottlecap/main.rs
Comment thread bottlecap/src/bin/bottlecap/main.rs Outdated
Comment thread bottlecap/src/bin/bottlecap/main.rs Outdated
flushers.push(MetricsFlusher::new(flusher_config));

for (endpoint_url, api_keys) in &config.additional_endpoints {
let dd_url = DdUrl::new(endpoint_url.clone()).expect("can't parse additional endpoint URL");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a few more expects here. While previously we've tolerated them, can we update this so the program doesn't crash if the user provides an invalid site? We can log a fatal error and then replace it with datadoghq.com maybe?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes sounds good

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed this, tested that it falls back and ships data as expected

Copy link
Copy Markdown
Contributor

@duncanista duncanista left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@shreyamalpani shreyamalpani merged commit b702295 into main Jun 11, 2025
46 checks passed
@shreyamalpani shreyamalpani deleted the shreya.malpani/dual-ship-metrics-new branch June 11, 2025 14:20
duncanpharvey pushed a commit that referenced this pull request Mar 10, 2026
Adds support for dual shipping metrics to endpoints configured using the
`additional_endpoints` YAML or `DD_ADDITIONAL_ENDPOINTS` env var config.

For each configured endpoint/API key combination, we now create a
separate `MetricsFlusher` to flush the same batch of metrics to multiple
endpoints in parallel. Also, updates the retry logic to retry flushing
for the specific flusher that encountered an error.

Tested dual shipping metrics to 2 additional orgs/endpoints including
eu1.

Depends on dogstatsd changes:
DataDog/serverless-components#20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants