Skip to content

enhancement(checks ipc): add new check data types and harden the protocol - #1855

Open
nathan-b wants to merge 5 commits into
mainfrom
nbaker/acr-ipc-protocol
Open

enhancement(checks ipc): add new check data types and harden the protocol#1855
nathan-b wants to merge 5 commits into
mainfrom
nbaker/acr-ipc-protocol

Conversation

@nathan-b

Copy link
Copy Markdown

Summary

Implement improvements to the IPC protocol between ADP and ACR.

Adds new types (sketches for histograms, the new openmetrics histogram bucket, extend log type). Also tries to make the protocol more robust and build failure detection into it.

How did you test this PR?

Ran ACR against both ADP and the core agent to confirm data types are correctly sent

@datadog-prod-us1-6

This comment has been minimized.

@nathan-b
nathan-b requested a review from fabbing June 11, 2026 15:00
@dd-octo-sts dd-octo-sts Bot added area/io General I/O and networking. area/components Sources, transforms, and destinations. labels Jun 11, 2026
Comment thread lib/protos/datadog/proto/checks/v1/acr_ipc.proto Outdated
Comment thread lib/protos/datadog/proto/checks/v1/acr_ipc.proto Outdated
Comment thread lib/protos/datadog/proto/checks/v1/checks.proto Outdated
Comment on lines +44 to +47
// Distinguishes the two sender upcalls. False (the default)
// routes to `Sender.OpenmetricsBucket`; true routes to
// `Sender.HistogramBucket`. Python `submit_histogram_bucket`
// always lands as false.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: opaque comment that requires implicit cross-repository knowledge.

It's also... confusing at face value. The naming implies multiple buckets, but this type is, definitionally, a value representing a single bucket.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This comment (and TBH this field) is a hot mess. It took me several passes and I'm still not sure I got it right, but my next commit should make this better.

Comment thread lib/saluki-components/src/sources/checks_ipc/mod.rs Outdated
Comment thread lib/saluki-components/src/sources/checks_ipc/mod.rs Outdated
nathan-b added 4 commits July 17, 2026 14:49
Protocol-level messages:
 - Hello
 - HelloResp
 - ConfigData
 - CheckDataMsg
 - CheckDataAck
 - CheckResultMsg

Add Histogram and EventPlatformEvent data types to the CheckData oneof.

Extend MetricType with MonotonicCount and Historate.

Remove gRPC service definition as it is no longer needed.
Restore the AcrIpc gRPC service with four RPCs:
 - Handshake (unary)
 - SendCheckData (unary with ACK)
 - SendCheckResult (unary)
 - StreamConfig (server streaming for config push).

 Re-enable server and client codegen for the checks proto compilation.
…init_config

extend Log:
 - Add fields to the Log message to support all the metadata the agent
   and ADP support
 - The fields map 1:1 onto ADP's internal Log struct

Histogram / sketch:
 - Renamed histogram.proto to sketch.proto and replaced its contents
   with the DDSketch wire format used by the agent's SketchPayload
 - CheckData oneof slot 5 is repurposed to carry pre-aggregated sketches

Note: lib/saluki-components/src/sources/checks_ipc/mod.rs is left
broken — it still imports the old Checks service.

init_config:
 - The check API has both `config` and `init_config`, and many
   integrations rely on the init_config block for shared defaults
 - The previous CheckInstance message only carried the
   per-instance config, so an ACR-scheduled check would receive an
   empty init_config

openmetrics:
 - Add support for the new openmetrics histogram bucket type
- Improve some AI-authored code comments
- Change protobuf message naming to fit request / response pattern
- Change name of AcrIpc to read a bit more naturally
- Don't hard-code server ID
@nathan-b
nathan-b force-pushed the nbaker/acr-ipc-protocol branch from 40ce8a8 to d342d92 Compare July 17, 2026 19:13
@pr-commenter

pr-commenter Bot commented Jul 17, 2026

Copy link
Copy Markdown

Binary Size Analysis (Agent Data Plane)

Baseline: e448977 · Comparison: c319fb0 · diff
Analysis Configuration: stripped binaries · Pass/Fail Threshold: +5%
Sizes: 39.52 MiB (baseline) vs 39.76 MiB (comparison)
Size Change: +255.52 KiB (+0.63%)

✅ Binary size difference within threshold

Changes by Module
Module File Size Symbols
figment +99.87 KiB 167
serde -41.52 KiB 52
saluki_components::common::datadog +34.01 KiB 74
datadog_protos::checks_include::datadog +33.63 KiB 23
tonic +22.49 KiB 74
core +20.59 KiB 1170
[sections] +18.36 KiB 9
saluki_components::sources::checks_ipc +17.71 KiB 45
otlp_protos::otlp_include::opentelemetry +14.94 KiB 59
tokio_rustls +14.84 KiB 10
saluki_components::sources::dogstatsd +14.77 KiB 26
hyper_util -14.37 KiB 16
hyper +13.03 KiB 68
axum +11.44 KiB 46
saluki_components::sources::otlp -10.99 KiB 26
alloc -9.91 KiB 216
crossbeam_channel +9.25 KiB 20
&mut rmp_serde -9.01 KiB 8
std -8.97 KiB 49
rmp +8.88 KiB 25
Detailed Symbol Changes
    FILE SIZE        VM SIZE    
 --------------  -------------- 
  +4.1%  +246Ki  +4.9%  +215Ki    [6857 Others]
  [NEW] +36.2Ki  [NEW] +35.9Ki    _<saluki_components::common::datadog::obfuscation::_::<impl serde_core::de::Deserialize for saluki_components::common::datadog::obfuscation::ObfuscationConfig>::deserialize::__Visitor as serde_core::de::Visitor>::visit_map::h34d26aec78b9b6fd
  [NEW] +16.5Ki  [NEW] +16.2Ki    _<saluki_components::sources::checks_ipc::CheckRunnerService as datadog_protos::checks_include::datadog::checks::v1::check_runner_server::CheckRunner>::send_check_data::_{{closure}}::he4232522b64e2ad8
   +70% +15.0Ki   +70% +15.0Ki    _<saluki_components::transforms::apm_stats::ApmStats as saluki_core::components::transforms::Transform>::run::_{{closure}}::h4aa97cab3ce4643f
  +1.2% +13.3Ki  +1.2% +13.3Ki    [section .gcc_except_table]
 +24e2% +12.6Ki +40e2% +12.6Ki    _<saluki_components::transforms::trace_obfuscation::TraceObfuscation as saluki_core::components::transforms::SynchronousTransform>::transform_buffer::h13d00a1ed5d1a949
  [NEW] +11.8Ki  [NEW] +11.7Ki    _<figment::value::magic::RelativePathBuf as figment::value::magic::Magic>::deserialize_from::hd1e34203984dab46
  [NEW] +11.3Ki  [NEW] +11.2Ki    saluki_components::sources::dogstatsd::replay::writer::run_capture_loop::h1fbbf0bd793493d3
  [NEW] +11.3Ki  [NEW] +11.1Ki    _<figment::value::magic::Tagged<T> as figment::value::magic::Magic>::deserialize_from::h871bb666a5dedd8e
  [NEW] +11.0Ki  [NEW] +10.9Ki    saluki_components::sources::otlp::logs::transform::transform_log_record::hda456ebc43b370f0
  [NEW] +10.8Ki  [NEW] +10.7Ki    _<hyper::proto::h2::server::Server<T,S,B,E> as core::future::future::Future>::poll::h12af4a6377fc587e
 -92.6% -10.8Ki -93.6% -10.8Ki    saluki_components::sources::otlp::metrics::cache::PointsCache::from_config::h8fc8317d63dee92f
 -87.9% -10.9Ki -89.1% -10.9Ki    _<saluki_components::sources::otlp::logs::translator::OtlpLogsTranslator as core::iter::traits::iterator::Iterator>::next::h616b5cfbb0a673cf
 -98.0% -11.0Ki -98.8% -11.0Ki    std::sys::backtrace::__rust_begin_short_backtrace::h2bda0a5a24ebfdd4
 -75.6% -11.5Ki -76.0% -11.5Ki    prost::message::Message::encode_to_vec::h057eddd56dae0828
  [DEL] -12.2Ki  [DEL] -11.9Ki    _<saluki_components::sources::checks_ipc::ChecksService as datadog_protos::checks_include::datadog::checks::v1::checks_server::Checks>::send_check_payload::_{{closure}}::h85f1cca804b25d6b
  [DEL] -12.8Ki  [DEL] -12.6Ki    saluki_components::common::datadog::apm::_::_<impl serde_core::de::Deserialize for saluki_components::common::datadog::apm::ApmConfiguration>::deserialize::h83fd55e646efe09f
  [DEL] -15.0Ki  [DEL] -14.9Ki    saluki_components::transforms::apm_stats::span_concentrator::SpanConcentrator::flush::h781147baa3bb80c6
 -74.4% -16.6Ki -74.6% -16.6Ki    prost::message::Message::encode::h9a0c9dab3671d2d1
 -74.4% -17.5Ki -74.7% -17.5Ki    h2::proto::connection::DynConnection<B>::recv_frame::hb003113333df1b8c
  [DEL] -22.3Ki  [DEL] -22.2Ki    saluki_components::transforms::trace_obfuscation::TraceObfuscation::obfuscate_span::h9bdc045d41ac5ae1
  +0.6%  +255Ki  +0.7%  +224Ki    TOTAL

@pr-commenter

pr-commenter Bot commented Jul 17, 2026

Copy link
Copy Markdown

Regression Detector (Agent Data Plane)

Run ID: ebb09ad9-88a3-4d15-8e46-66e3db913d09
Baseline: e4489779 · Comparison: c319fb09 · diff

Optimization Goals: ✅ No significant changes detected

Fine details of change detection per experiment (5)

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
quality_gates_rss_idle memory ⚪ +0.71 metrics profiles logs
quality_gates_rss_dsd_heavy memory ⚪ +0.25 metrics profiles logs
quality_gates_rss_dsd_low memory ⚪ -0.02 metrics profiles logs
quality_gates_rss_dsd_ultraheavy memory ⚪ -0.03 metrics profiles logs
quality_gates_rss_dsd_medium memory ⚪ -0.05 metrics profiles logs
Bounds Checks: ✅ Passed (5)
experiment check replicates observed links
quality_gates_rss_dsd_heavy memory_usage 10/10 ✅ 139 MiB ≤ 140 MiB metrics profiles logs
quality_gates_rss_dsd_low memory_usage 10/10 ✅ 44.3 MiB ≤ 50 MiB metrics profiles logs
quality_gates_rss_dsd_medium memory_usage 10/10 ✅ 66.7 MiB ≤ 75 MiB metrics profiles logs
quality_gates_rss_dsd_ultraheavy memory_usage 10/10 ✅ 193 MiB ≤ 200 MiB metrics profiles logs
quality_gates_rss_idle memory_usage 10/10 ✅ 30.4 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.

@nathan-b nathan-b changed the title Improvements to the ACR IPC protocol enhancement(checks ipc): add new check data types and harden the protocol Jul 17, 2026
@nathan-b
nathan-b marked this pull request as ready for review July 17, 2026 20:04
@nathan-b
nathan-b requested a review from a team as a code owner July 17, 2026 20:04

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

Copy link
Copy Markdown

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: c319fb098b

ℹ️ 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".

let mut out = Log::new(log.message)
.with_status(status)
.with_source(string_to_meta_opt(log.source))
.with_hostname(string_to_meta_opt(log.hostname))

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 Apply the default host to hostless log records

When a check runner leaves Log.hostname empty, the new proto contract says the receiver should use its default hostname, but this conversion maps the empty string to None and Log::with_hostname(None) stores an empty host. In that common host-omitted case, logs sent through checks IPC lose the agent hostname instead of matching metric behavior, which can break host-scoped routing and correlation downstream.

Useful? React with 👍 / 👎.

Comment on lines +197 to +198
accepted: true,
reject_reason: String::new(),

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 Reject unsupported check-runner protocol versions

If a runner sends PROTOCOL_VERSION_UNSPECIFIED or an unknown/future protocol integer, the handshake still returns accepted: true with no reject reason. Because SendCheckData is not gated on a negotiated version later, an incompatible runner can continue after a nominally successful handshake; the new accepted/reject_reason fields should be used to reject anything other than the supported V1 version.

Useful? React with 👍 / 👎.

@datadog-prod-us1-6 datadog-prod-us1-6 Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Datadog Autotest: WARN

log_to_event maps every new Log proto field (source, hostname, service, tags, additional_properties) except timestamp — since the saluki Log struct has no timestamp field, any non-zero producer timestamp from ACR is silently discarded and the log is always stamped at receive time. Separately, send_check_data returns success: true for batches containing only unsupported types (Sketch, MonotonicCount, etc.), giving callers no signal that their data was dropped.

Open Bits AI session

🤖 Datadog Autotest · Commit c319fb0 · What is Autotest? · Any feedback? Reach out in #autotest

.with_source(string_to_meta_opt(log.source))
.with_hostname(string_to_meta_opt(log.hostname))
.with_service(string_to_meta_opt(log.service))
.with_tags(Some(proto_tags_to_tagset(log.tags)));

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 log.timestamp silently dropped — producer timestamps always overridden by receive time

Logs from ACR checks appear in Datadog at the time ADP received them, not when the check event occurred. For batched or replayed logs this causes incorrect temporal ordering in the log explorer.

Assertion details
  • Input: ACR sends a Log payload with timestamp = 1_700_000_000_000_000_000 (nanoseconds) and any non-empty message
  • Expected: The saluki Log event carries the producer-set timestamp so Datadog shows the event at the time the check detected it
  • Actual: log_to_event reads log.level, log.message, log.source, log.hostname, log.service, log.tags, and log.additional_properties — it never accesses log.timestamp. The saluki Log struct has no timestamp field. All non-zero producer timestamps are discarded; every log emitted from this path uses pipeline receive time.

Was this helpful? React 👍 or 👎
🤖 Datadog Autotest · What is Autotest? · Any feedback? Reach out in #autotest

}

Ok(Response::new(SendCheckPayloadResponse {}))
Ok(Response::new(SendCheckDataResponse {

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 send_check_data returns success=true when entire batch is silently dropped

ACR clients that start emitting DDSketch or histogram-bucket payloads (as the new proto now allows) will receive success: true indefinitely with no indication that their data is being dropped server-side, making the data gap invisible until a separate cardinality check.

Assertion details
  • Input: A SendCheckDataRequest batch whose every CheckData item is one of: Sketch, EventPlatformEvent, HistogramBucket, MonotonicCount metric, or Historate metric
  • Expected: success: false or a non-empty error field to signal that no data was forwarded, so clients can log/alert or retry with a different code path
  • Actual: data_to_event returns None for all five types (with a debug-level log). The iteration loop continues past each one, and the function falls through to Ok(SendCheckDataResponse { success: true, error: "" }). Clients receive a success ACK with zero items actually processed.

Was this helpful? React 👍 or 👎
🤖 Datadog Autotest · What is Autotest? · Any feedback? Reach out in #autotest

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/io General I/O and networking.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants