Skip to content

enhancement(datadog): add support for series V1 API#1646

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 4 commits into
mainfrom
tobz/dd-metrics-v1-api-series
May 13, 2026
Merged

enhancement(datadog): add support for series V1 API#1646
gh-worker-dd-mergequeue-cf854d[bot] merged 4 commits into
mainfrom
tobz/dd-metrics-v1-api-series

Conversation

@tobz
Copy link
Copy Markdown
Member

@tobz tobz commented May 13, 2026

Summary

This PR adds support for sending series metrics to the legacy series V1 API for Datadog destinations.

Prior to this, we only supported the series V2 API, the newer, Protocol Buffers-based API which superseded the old V1 API. Well... we want to allow using ADP in more configurations, and some customers still use the series V1 API, so here we are. :)

This PR implements support for the series V1 API, which is kind of self-evident, but we've made the following changes:

  • updated the existing Datadog Metrics encoder to support both series API versions (mutually exclusive) based on the configuration of use_v2_api.series
  • updated the configuration registry to account for use_v2_api.series, and update our supportability status for it
  • added a few unit tests, and a new correctness test, to assert that we're doing series V1 correctly

I also made three small changes to the correctness tooling outside of adding series V1 support:

  • make test-correctness-case runs with --no-tui now so that you can actually see all of the failing assertions (if any); no need for the TUI if you're just running a single case, really
  • added detection of diagnose-related requests for the two series API endpoints in datadog-intake: DDA will send dummy payloads when trying to hit those endpoints during diagnose/connectivity check runs... so now we directly detect them and log them as such to avoid having spurious failure messages in the datadog-intake logs
  • added normalization of the various ways we propagate the "host" value in different metrics output formats such that it makes it into the stele normalized metric as a tag, such that we can ensure we're properly comparing whatever the generated host value is, whether it's a tag or specialized field

Change Type

  • Bug fix
  • New feature
  • Non-functional (chore, refactoring, docs)
  • Performance

How did you test this PR?

  • Existing unit/correctness tests.
  • Added a new correctness test (dsd-v1-api-series) that runs in series V1 mode.

References

DADP-72

Closes #1641, #1642

@tobz tobz requested a review from a team as a code owner May 13, 2026 18:03
@tobz tobz added the type/enhancement An enhancement in functionality or support. label May 13, 2026
@dd-octo-sts dd-octo-sts Bot added area/components Sources, transforms, and destinations. area/test All things testing: unit/integration, correctness, SMP regression, etc. encoder/datadog-metrics Datadog Metrics encoder. forwarder/datadog Datadog forwarder. labels May 13, 2026
@tobz tobz changed the title enhancement(datadog metrics): add support for series V1 API enhancement(datadog): add support for series V1 API May 13, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 15dfdce32d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +639 to +642
fn get_input_separator(&self) -> Option<&'static [u8]> {
match self.endpoint {
MetricsEndpoint::SeriesV1 => Some(SERIES_V1_INPUT_SEPARATOR),
_ => None,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid separator framing before V1 payload sizing

When a V1 series payload is near the size limit, RequestBuilder::encode_inner writes get_input_separator() before it encodes and checks the next metric's size; if that next metric does not fit, the caller flushes the current payload with the separator already written, producing invalid JSON like {"series":[...,]}. This only affects the new /api/v1/series path when an uncompressed/compressed limit forces a flush, so the intake can reject otherwise valid batches.

Useful? React with 👍 / 👎.

@pr-commenter
Copy link
Copy Markdown

pr-commenter Bot commented May 13, 2026

Regression Detector (Agent Data Plane)

Run ID: 231ea44f-b066-415d-bbb2-416ab5d69de3
Baseline: f0a3687d · Comparison: 915a0ce9 · Diff

Optimization Goals: ✅ No significant changes detected

Fine details of change detection per experiment (35)

Experiments configured erratic: true are tagged (ignored) and skipped when determining which experiments regressed or improved. Experiments which are detected as erratic at runtime are tagged (erratic) to flag that the run's sample dispersion was high, but their regression / improvement signal still counts.

experiment goal Δ mean % links
dsd_uds_10mb_3k_contexts_cpu (erratic) cpu ⚪ +4.70 metrics profiles logs
otlp_ingest_metrics_5mb_memory memory ⚪ +3.30 metrics profiles logs
otlp_ingest_logs_5mb_cpu (ignored) cpu ⚪ +1.12 metrics profiles logs
otlp_ingest_traces_ottl_transform_5mb_cpu (erratic) cpu ⚪ +0.50 metrics profiles logs
dsd_uds_512kb_3k_contexts_cpu (erratic) cpu ⚪ +0.43 metrics profiles logs
otlp_ingest_traces_5mb_memory memory ⚪ +0.41 metrics profiles logs
otlp_ingest_traces_ottl_filtering_5mb_memory memory ⚪ +0.41 metrics profiles logs
otlp_ingest_traces_5mb_throughput throughput ⚪ -0.20 metrics profiles logs
otlp_ingest_traces_ottl_filtering_5mb_throughput throughput ⚪ -0.11 metrics profiles logs
quality_gates_rss_dsd_ultraheavy memory ⚪ +0.07 metrics profiles logs
dsd_uds_100mb_3k_contexts_throughput throughput ⚪ -0.01 metrics profiles logs
dsd_uds_512kb_3k_contexts_throughput throughput ⚪ -0.00 metrics profiles logs
dsd_uds_1mb_3k_contexts_throughput throughput ⚪ -0.00 metrics profiles logs
otlp_ingest_traces_ottl_transform_5mb_memory memory ⚪ -0.01 metrics profiles logs
dsd_uds_10mb_3k_contexts_throughput throughput ⚪ +0.01 metrics profiles logs
quality_gates_rss_dsd_low memory ⚪ -0.01 metrics profiles logs
otlp_ingest_logs_5mb_throughput (ignored) throughput ⚪ +0.01 metrics profiles logs
otlp_ingest_metrics_5mb_throughput throughput ⚪ +0.02 metrics profiles logs
dsd_uds_1mb_3k_contexts_memory memory ⚪ -0.02 metrics profiles logs
dsd_uds_500mb_3k_contexts_throughput throughput ⚪ +0.07 metrics profiles logs
quality_gates_rss_idle memory ⚪ -0.08 metrics profiles logs
quality_gates_rss_dsd_heavy memory ⚪ -0.09 metrics profiles logs
quality_gates_rss_dsd_medium memory ⚪ -0.16 metrics profiles logs
dsd_uds_512kb_3k_contexts_memory memory ⚪ -0.16 metrics profiles logs
dsd_uds_500mb_3k_contexts_cpu (erratic) cpu ⚪ -0.21 metrics profiles logs
dsd_uds_500mb_3k_contexts_memory memory ⚪ -0.22 metrics profiles logs
dsd_uds_10mb_3k_contexts_memory memory ⚪ -0.24 metrics profiles logs
otlp_ingest_metrics_5mb_cpu (erratic) cpu ⚪ -0.25 metrics profiles logs
dsd_uds_100mb_3k_contexts_memory memory ⚪ -0.28 metrics profiles logs
otlp_ingest_traces_5mb_cpu (erratic) cpu ⚪ -0.37 metrics profiles logs
dsd_uds_100mb_3k_contexts_cpu (erratic) cpu ⚪ -0.62 metrics profiles logs
otlp_ingest_traces_ottl_transform_5mb_throughput throughput ⚪ +1.71 metrics profiles logs
otlp_ingest_logs_5mb_memory (ignored) memory ⚪ -2.05 metrics profiles logs
otlp_ingest_traces_ottl_filtering_5mb_cpu (erratic) cpu ⚪ -2.92 metrics profiles logs
dsd_uds_1mb_3k_contexts_cpu (erratic) cpu 🟢 -5.80 metrics profiles logs
Bounds Checks: ✅ Passed (5)
experiment check replicates observed links
quality_gates_rss_dsd_heavy memory_usage 10/10 ✅ 122 MiB ≤ 140 MiB metrics profiles logs
quality_gates_rss_dsd_low memory_usage 10/10 ✅ 39.5 MiB ≤ 50 MiB metrics profiles logs
quality_gates_rss_dsd_medium memory_usage 10/10 ✅ 59.9 MiB ≤ 75 MiB metrics profiles logs
quality_gates_rss_dsd_ultraheavy memory_usage 10/10 ✅ 178 MiB ≤ 200 MiB metrics profiles logs
quality_gates_rss_idle memory_usage 10/10 ✅ 26.8 MiB ≤ 40 MiB metrics profiles logs
Explanation

A change is flagged as a regression when |Δ mean %| > 5.00% in the regressing direction for its optimization goal AND SMP marks the experiment as a regression (is_regression: true). Improvements use the matching criteria for the improving direction. Experiments configured erratic: true (tagged (ignored)) are skipped outright; experiments detected as erratic at runtime (tagged (erratic)) still count, since that flag describes sample dispersion rather than directional certainty. The Δ mean % cell is colored accordingly: 🟢 = improvement, 🔴 = regression, ⚪ = neutral. Reduction in CPU or memory is an improvement; reduction in ingress throughput is a regression.

Comment thread test/correctness/dsd-v1-api-series/config.yaml Outdated
Comment thread lib/saluki-components/src/encoders/datadog/metrics/mod.rs Outdated
Comment thread lib/saluki-components/src/encoders/datadog/metrics/mod.rs
Comment thread Makefile
@pr-commenter
Copy link
Copy Markdown

pr-commenter Bot commented May 13, 2026

Binary Size Analysis (Agent Data Plane)

Target: f0a3687 (baseline) vs 915a0ce (comparison) diff
Analysis Type: Stripped binaries (debug symbols excluded)
Baseline Size: 37.79 MiB
Comparison Size: 37.79 MiB
Size Change: +3.55 KiB (+0.01%)
Pass/Fail Threshold: +5%
Result: PASSED ✅

Changes by Module

Module File Size Symbols
core -32.05 KiB 1149
hyper_util +30.07 KiB 10
hyper -27.39 KiB 54
saluki_components::sources::otlp +19.00 KiB 21
serde_core +17.96 KiB 81
otlp_protos::otlp_include::opentelemetry -14.09 KiB 120
&mut serde_json -11.91 KiB 22
saluki_components::encoders::datadog +11.00 KiB 65
serde_json +11.00 KiB 30
prost +5.05 KiB 210
tracing -4.80 KiB 12
http_serde_ext +4.39 KiB 10
h2 +4.38 KiB 18
saluki_components::common::otlp -4.12 KiB 20
tokio_util -4.08 KiB 13
saluki_components::forwarders::otlp -4.02 KiB 2
serde_with -3.96 KiB 17
bytes +3.50 KiB 16
[sections] -3.44 KiB 8
anon.b68d523c8f9846ca5abc69776e187519.172.llvm.15111859790713813982 +3.33 KiB 1

Detailed Symbol Changes

    FILE SIZE        VM SIZE    
 --------------  -------------- 
  [NEW] +18.6Ki  [NEW] +18.4Ki    _<hyper_util::server::conn::auto::Connection<I,S,E> as core::future::future::Future>::poll::h12ac62a4f3751e08
  [NEW] +16.6Ki  [NEW] +16.5Ki    saluki_components::sources::otlp::metrics::runtime_metrics::RUNTIME_METRICS_MAPPINGS::_{{closure}}::h2b0da789c4758ba5
  [NEW] +12.8Ki  [NEW] +12.5Ki    _<saluki_components::encoders::datadog::metrics::MetricsEndpointEncoder as saluki_components::common::datadog::request_builder::EndpointEncoder>::encode::h0640d48f94042929
  +560% +11.1Ki  +616% +11.1Ki    _<saluki_components::sources::otlp::logs::translator::OtlpLogsTranslator as core::iter::traits::iterator::Iterator>::next::h3860cbd002a9a1e5
  [NEW] +8.66Ki  [NEW] +8.45Ki    _<saluki_components::encoders::datadog::metrics::DatadogMetrics as saluki_core::components::encoders::Encoder>::run::_{{closure}}::haf5e4300c95fc2ba
  [NEW] +7.82Ki  [NEW] +7.68Ki    _<serde_json::de::SeqAccess<R> as serde_core::de::SeqAccess>::next_element_seed::h7d6778903c1cffa1
  [NEW] +6.37Ki  [NEW] +6.21Ki    _<&mut serde_json::de::Deserializer<R> as serde_core::de::Deserializer>::deserialize_struct::h5d239f11fa000628
  [NEW] +5.87Ki  [NEW] +5.72Ki    _<serde_json::de::SeqAccess<R> as serde_core::de::SeqAccess>::next_element_seed::he3e2d75eb3b074cf
  [NEW] +5.52Ki  [NEW] +5.22Ki    alloc::collections::btree::node::Handle<alloc::collections::btree::node::NodeRef<alloc::collections::btree::node::marker::Mut,K,V,alloc::collections::btree::node::marker::Leaf>,alloc::collections::btree::node::marker::Edge>::insert_recursing::h1670df83829822a4
  [NEW] +4.56Ki  [NEW] +4.26Ki    alloc::collections::btree::node::Handle<alloc::collections::btree::node::NodeRef<alloc::collections::btree::node::marker::Mut,K,V,alloc::collections::btree::node::marker::Leaf>,alloc::collections::btree::node::marker::Edge>::insert_recursing::h6aebd6eb2cbb16d7
 -86.0% -4.92Ki -87.6% -4.92Ki    alloc::collections::btree::map::BTreeMap<K,V,A>::insert::ha8d583a1d0509c7d
  [DEL] -6.11Ki  [DEL] -5.90Ki    _<saluki_components::encoders::datadog::metrics::MetricsEndpointEncoder as saluki_components::common::datadog::request_builder::EndpointEncoder>::encode::hdf591e762d8c7e54
  [DEL] -6.13Ki  [DEL] -5.97Ki    _<&mut serde_json::de::Deserializer<R> as serde_core::de::Deserializer>::deserialize_struct::heb60545e81a9a584
  [DEL] -6.56Ki  [DEL] -6.41Ki    _<core::marker::PhantomData<T> as serde_core::de::DeserializeSeed>::deserialize::h59296b5c732c0ed1
  [DEL] -8.12Ki  [DEL] -7.95Ki    _<&mut serde_json::de::Deserializer<R> as serde_core::de::Deserializer>::deserialize_struct::h296a1abeac8594b2
  [DEL] -8.78Ki  [DEL] -8.58Ki    _<saluki_components::encoders::datadog::metrics::DatadogMetrics as saluki_core::components::encoders::Encoder>::run::_{{closure}}::h4044b9be0d8340aa
  [DEL] -9.42Ki  [DEL] -9.29Ki    _<core::pin::Pin<P> as core::future::future::Future>::poll::h8bf635c589f5ae5d
  [DEL] -9.90Ki  [DEL] -9.75Ki    _<hyper::proto::h2::server::Server<T,S,B,E> as core::future::future::Future>::poll::h6e574e2a45576f6a
  -0.1% -6.90Ki  -0.2% -10.5Ki    [6118 Others]
  [DEL] -10.9Ki  [DEL] -10.8Ki    saluki_components::sources::otlp::logs::transform::transform_log_record::hefcb9c2341939142
 -99.2% -16.6Ki -99.7% -16.6Ki    core::ops::function::FnOnce::call_once::hf0d23ad91433eeed
  +0.0% +3.55Ki  -0.0%    -632    TOTAL

@gh-worker-dd-mergequeue-cf854d gh-worker-dd-mergequeue-cf854d Bot merged commit d92149c into main May 13, 2026
77 checks passed
@tobz tobz deleted the tobz/dd-metrics-v1-api-series branch May 13, 2026 19:50
dd-octo-sts Bot pushed a commit that referenced this pull request May 13, 2026
## Summary

This PR adds support for sending series metrics to the legacy series V1 API for Datadog destinations.

Prior to this, we only supported the series V2 API, the newer, Protocol Buffers-based API which superseded the old V1 API. Well... we want to allow using ADP in more configurations, and some customers still use the series V1 API, so here we are. :)

This PR implements support for the series V1 API, which is kind of self-evident, but we've made the following changes:

- updated the existing Datadog Metrics encoder to support both series API versions (mutually exclusive) based on the configuration of `use_v2_api.series`
- updated the configuration registry to account for `use_v2_api.series`, and update our supportability status for it
- added a few unit tests, and a new correctness test, to assert that we're doing series V1 correctly

I also made three small changes to the correctness tooling outside of adding series V1 support:

- `make test-correctness-case` runs with `--no-tui` now so that you can actually see all of the failing assertions (if any); no need for the TUI if you're just running a single case, really
- added detection of diagnose-related requests for the two series API endpoints in `datadog-intake`: DDA will send dummy payloads when trying to hit those endpoints during diagnose/connectivity check runs... so now we directly detect them and log them as such to avoid having spurious failure messages in the `datadog-intake` logs
- added normalization of the various ways we propagate the "host" value in different metrics output formats such that it makes it into the `stele` normalized metric as a tag, such that we can ensure we're properly comparing whatever the generated host value is, whether it's a tag or specialized field

## Change Type
- [ ] Bug fix
- [x] New feature
- [ ] Non-functional (chore, refactoring, docs)
- [ ] Performance

## How did you test this PR?

- [x] Existing unit/correctness tests.
- [x] Added a new correctness test (`dsd-v1-api-series`) that runs in series V1 mode.

## References

DADP-72

Closes #1641, #1642

Co-authored-by: toby.lawrence <toby.lawrence@datadoghq.com> d92149c
thieman added a commit that referenced this pull request May 14, 2026
Add a `focus_metrics` field to the correctness test config that, when
non-empty, replaces the standard internal-telemetry filter with an
allowlist. Only metrics whose names appear in the list are kept for
comparison; everything else (including other `datadog.*` metrics and
all user DSD traffic) is discarded.

This enables correctness tests that validate specific agent-emitted
metrics such as `datadog.agent.point.sent` and
`datadog.agent.point.dropped`, which would otherwise be stripped by
the default filter.

Also fix a test reference to `MetricsEndpoint::Series` that was
renamed to `MetricsEndpoint::SeriesV1` in #1646.
thieman added a commit that referenced this pull request May 14, 2026
Add a `focus_metrics` field to the correctness test config that, when
non-empty, replaces the standard internal-telemetry filter with an
allowlist. Only metrics whose names appear in the list are kept for
comparison; everything else (including other `datadog.*` metrics and
all user DSD traffic) is discarded.

This enables correctness tests that validate specific agent-emitted
metrics such as `datadog.agent.point.sent` and
`datadog.agent.point.dropped`, which would otherwise be stripped by
the default filter.

Also fix a test reference to `MetricsEndpoint::Series` that was
renamed to `MetricsEndpoint::SeriesV1` in #1646.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/components Sources, transforms, and destinations. area/test All things testing: unit/integration, correctness, SMP regression, etc. encoder/datadog-metrics Datadog Metrics encoder. forwarder/datadog Datadog forwarder. mergequeue-status: done type/enhancement An enhancement in functionality or support.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Correctly categorize use_v2_api.* keys. DADP-72 Finding 2

2 participants