Skip to content

Commit 8d48c4e

Browse files
authored
chore(config): migrate DatadogEventsConfiguration to typed config (#1981)
## AI Summary Build `DatadogEventsConfiguration` from the typed shared configuration model instead of deserializing the generic configuration map. Remove component-local source defaults and retire the configuration smoke test. ## Change Type - [x] Non-functional (chore, refactoring, docs) ## How did you test this PR? - `make build-schema-overlay && make fmt` - `make check-fmt check-docs` - `make test` - `make check-deny check-unused-deps check-licenses check-features generate-api-docs` - `cargo check -p saluki-components -p agent-data-plane` ## References No issue.
1 parent d6bcd0a commit 8d48c4e

4 files changed

Lines changed: 69 additions & 80 deletions

File tree

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ async fn create_topology(
412412
}
413413

414414
if dp_config.events_pipeline_required() {
415-
add_baseline_events_pipeline_to_blueprint(&mut blueprint, config).await?;
415+
add_baseline_events_pipeline_to_blueprint(&mut blueprint, config_system).await?;
416416
}
417417

418418
if dp_config.service_checks_pipeline_required() {
@@ -599,11 +599,15 @@ async fn add_baseline_logs_pipeline_to_blueprint(
599599
}
600600

601601
async fn add_baseline_events_pipeline_to_blueprint(
602-
blueprint: &mut TopologyBlueprint, config: &GenericConfiguration,
602+
blueprint: &mut TopologyBlueprint, config_system: &ConfigurationSystem,
603603
) -> Result<(), GenericError> {
604-
let dd_events_config = DatadogEventsConfiguration::from_configuration(config)
605-
.map(BufferedIncrementalConfiguration::from_encoder_builder)
606-
.error_context("Failed to configure Datadog Events encoder.")?;
604+
let saluki = config_system.config();
605+
let dd_events_config = DatadogEventsConfiguration::from_configuration(
606+
&saluki.shared.metrics_encoding,
607+
&saluki.shared.endpoints.compression,
608+
)
609+
.map(BufferedIncrementalConfiguration::from_encoder_builder)
610+
.error_context("Failed to configure Datadog Events encoder.")?;
607611

608612
blueprint
609613
.add_encoder("dd_events_encode", dd_events_config)?

lib/agent-data-plane-config-system/src/translators/datadog_translator.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use agent_data_plane_config::control::ListenAddress;
2222
use agent_data_plane_config::domains::dogstatsd::{
2323
FilterAction, MapperProfile, MetricMapping, MetricTagFilterEntry, OriginTagCardinality,
2424
};
25-
use agent_data_plane_config::shared::ForwarderHttpProtocol;
25+
use agent_data_plane_config::shared::{ForwarderHttpProtocol, ZSTD_DEFAULT_OVERRIDE};
2626
use agent_data_plane_config::SalukiConfiguration;
2727
use bytesize::ByteSize;
2828
use datadog_agent_config::{drive, DatadogConfigWitness, DatadogConfiguration, TranslateError, TranslateErrors};
@@ -952,7 +952,19 @@ impl DatadogConfigWitness for DatadogTranslator<'_> {
952952
}
953953

954954
fn consume_serializer_zstd_compressor_level(&mut self, value: i64) {
955-
self.config.shared.endpoints.compression.zstd_compressor_level = value as i32;
955+
// TODO: The core Agent streams a fully resolved config, so its schema default for
956+
// `serializer_zstd_compressor_level` arrives here as a concrete value rather than being
957+
// absent. When the incoming level matches that Agent default we swap in ADP's intended
958+
// level; without this the Agent default would silently override it. We compare against the
959+
// schema-generated default, so an operator who deliberately sets exactly the Agent default is
960+
// indistinguishable from the default itself and also gets overridden. Removing that ambiguity
961+
// needs per-value source tracking (user-set vs Agent default), which is follow-up work.
962+
let agent_default = DatadogConfiguration::default().serializer_zstd_compressor_level;
963+
self.config.shared.endpoints.compression.zstd_compressor_level = if value == agent_default {
964+
ZSTD_DEFAULT_OVERRIDE
965+
} else {
966+
value as i32
967+
};
956968
}
957969

958970
fn consume_site(&mut self, value: String) {

lib/agent-data-plane-config/src/shared.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,14 @@ pub struct Tls {
118118
pub sslkeylogfile: String,
119119
}
120120

121+
/// zstd compression level ADP substitutes when the core Agent supplies its own schema default. ADP
122+
/// compresses harder than the Agent, whose schema default for `serializer_zstd_compressor_level` is
123+
/// lower. Because the Agent streams a fully resolved config, that default arrives as a concrete
124+
/// value; when the incoming level is exactly the Agent default, the translator swaps in this level
125+
/// so the Agent default does not quietly lower ADP's compression. Any other value is treated as an
126+
/// explicit choice and left untouched.
127+
pub const ZSTD_DEFAULT_OVERRIDE: i32 = 3;
128+
121129
/// Payload compression settings applied before transmission.
122130
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
123131
pub struct Compression {

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

Lines changed: 38 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1+
use agent_data_plane_config::shared::{Compression, MetricsEncoding};
12
use async_trait::async_trait;
23
use datadog_protos::events as proto;
34
use facet::Facet;
45
use http::{uri::PathAndQuery, HeaderValue, Method, Uri};
56
use protobuf::{rt::WireType, CodedOutputStream};
67
use resource_accounting::{MemoryBounds, MemoryBoundsBuilder};
78
use saluki_common::iter::ReusableDeduplicator;
8-
use saluki_config::GenericConfiguration;
99
use saluki_context::tags::Tag;
1010
use saluki_core::{
1111
components::{encoders::*, ComponentContext},
@@ -19,7 +19,6 @@ use saluki_core::{
1919
use saluki_error::{ErrorContext as _, GenericError};
2020
use saluki_io::compression::CompressionScheme;
2121
use saluki_metrics::MetricsBuilder;
22-
use serde::Deserialize;
2322
use tracing::{debug, error, warn};
2423

2524
use crate::common::datadog::{
@@ -28,95 +27,56 @@ use crate::common::datadog::{
2827
request_builder::{EndpointEncoder, RequestBuilder},
2928
telemetry::ComponentTelemetry,
3029
DEFAULT_INTAKE_COMPRESSED_SIZE_LIMIT, DEFAULT_INTAKE_UNCOMPRESSED_SIZE_LIMIT,
31-
DEFAULT_SERIALIZER_COMPRESSED_SIZE_LIMIT, DEFAULT_SERIALIZER_UNCOMPRESSED_SIZE_LIMIT,
3230
};
3331

34-
const DEFAULT_SERIALIZER_COMPRESSOR_KIND: &str = "zstd";
3532
const MAX_EVENTS_PER_PAYLOAD: usize = 100;
3633
const EVENTS_FIELD_NUMBER: u32 = 1;
3734

3835
static CONTENT_TYPE_PROTOBUF: HeaderValue = HeaderValue::from_static("application/x-protobuf");
3936

40-
fn default_serializer_compressor_kind() -> String {
41-
DEFAULT_SERIALIZER_COMPRESSOR_KIND.to_owned()
42-
}
43-
44-
const fn default_zstd_compressor_level() -> i32 {
45-
3
46-
}
47-
48-
const fn default_max_payload_size() -> usize {
49-
DEFAULT_SERIALIZER_COMPRESSED_SIZE_LIMIT
50-
}
51-
52-
const fn default_max_uncompressed_payload_size() -> usize {
53-
DEFAULT_SERIALIZER_UNCOMPRESSED_SIZE_LIMIT
54-
}
55-
56-
const fn default_log_payloads() -> bool {
57-
false
58-
}
59-
6037
/// Datadog Events incremental encoder.
6138
///
6239
/// Generates Datadog Events payloads for the Datadog platform.
63-
#[derive(Deserialize, Facet)]
64-
#[cfg_attr(test, derive(Debug, PartialEq, serde::Serialize))]
40+
#[derive(Facet)]
6541
pub struct DatadogEventsConfiguration {
6642
/// Maximum compressed size, in bytes, of an events payload.
6743
///
6844
/// This uses the same generic event payload setting as the Datadog Agent. ADP sends events to
6945
/// `/api/v1/events_batch`, so the effective value is clamped to that endpoint's global intake limit of 3,200,000
7046
/// bytes. If set to `0`, every non-empty compressed payload exceeds the limit and is dropped during flush.
71-
///
72-
/// Defaults to 2,621,440 bytes.
73-
#[serde(rename = "serializer_max_payload_size", default = "default_max_payload_size")]
7447
max_payload_size: usize,
7548

7649
/// Maximum uncompressed size, in bytes, of an events payload.
7750
///
7851
/// This uses the same generic event payload setting as the Datadog Agent. ADP sends events to
7952
/// `/api/v1/events_batch`, so the effective value is clamped to that endpoint's global intake limit of 62,914,560
8053
/// bytes. Values smaller than the minimum endpoint framing size prevent the request builder from starting.
81-
///
82-
/// Defaults to 4,194,304 bytes.
83-
#[serde(
84-
rename = "serializer_max_uncompressed_payload_size",
85-
default = "default_max_uncompressed_payload_size"
86-
)]
8754
max_uncompressed_payload_size: usize,
8855

8956
/// Compression kind to use for the request payloads.
90-
///
91-
/// Defaults to `zstd`.
92-
#[serde(
93-
rename = "serializer_compressor_kind",
94-
default = "default_serializer_compressor_kind"
95-
)]
9657
compressor_kind: String,
9758

9859
/// Compressor level to use when the compressor kind is `zstd`.
99-
///
100-
/// Defaults to 3.
101-
#[serde(
102-
rename = "serializer_zstd_compressor_level",
103-
default = "default_zstd_compressor_level"
104-
)]
10560
zstd_compressor_level: i32,
10661

10762
/// Whether to log event payload contents before encoding.
10863
///
10964
/// This logs decoded event objects, not the encoded HTTP body.
110-
///
111-
/// Defaults to `false`.
112-
#[serde(default = "default_log_payloads")]
11365
log_payloads: bool,
11466
}
11567

11668
impl DatadogEventsConfiguration {
117-
/// Creates a new `DatadogEventsConfiguration` from the given configuration.
118-
pub fn from_configuration(config: &GenericConfiguration) -> Result<Self, GenericError> {
119-
Ok(config.as_typed()?)
69+
/// Creates a new `DatadogEventsConfiguration` from the shared typed configuration.
70+
pub fn from_configuration(
71+
metrics_encoding: &MetricsEncoding, compression: &Compression,
72+
) -> Result<Self, GenericError> {
73+
Ok(Self {
74+
max_payload_size: metrics_encoding.max_payload_size,
75+
max_uncompressed_payload_size: metrics_encoding.max_uncompressed_payload_size,
76+
compressor_kind: compression.compressor_kind.clone(),
77+
zstd_compressor_level: compression.zstd_compressor_level,
78+
log_payloads: metrics_encoding.log_payloads,
79+
})
12080
}
12181
}
12282

@@ -328,27 +288,32 @@ fn encode_eventd(eventd: &EventD, tags_deduplicator: &mut ReusableDeduplicator<T
328288
}
329289

330290
#[cfg(test)]
331-
mod config_smoke {
332-
use datadog_agent_config_testing::config_registry::structs;
333-
use datadog_agent_config_testing::run_config_smoke_tests;
334-
use serde_json::json;
291+
mod tests {
292+
use agent_data_plane_config::shared::{Compression, MetricsEncoding};
335293

336294
use super::DatadogEventsConfiguration;
337-
use crate::config::{DatadogRemapper, KEY_ALIASES};
338-
339-
#[tokio::test]
340-
async fn smoke_test() {
341-
run_config_smoke_tests(
342-
structs::DATADOG_EVENTS_CONFIGURATION,
343-
&[],
344-
json!({}),
345-
|cfg| {
346-
cfg.as_typed::<DatadogEventsConfiguration>()
347-
.expect("DatadogEventsConfiguration should deserialize")
348-
},
349-
KEY_ALIASES,
350-
DatadogRemapper::new,
351-
)
352-
.await
295+
296+
#[test]
297+
fn from_configuration_reads_typed_shared_values() {
298+
let metrics_encoding = MetricsEncoding {
299+
max_payload_size: 123,
300+
max_uncompressed_payload_size: 456,
301+
log_payloads: true,
302+
..Default::default()
303+
};
304+
305+
let compression = Compression {
306+
compressor_kind: "gzip".to_owned(),
307+
zstd_compressor_level: 7,
308+
};
309+
310+
let config = DatadogEventsConfiguration::from_configuration(&metrics_encoding, &compression)
311+
.expect("typed configuration should be accepted");
312+
313+
assert_eq!(config.max_payload_size, 123);
314+
assert_eq!(config.max_uncompressed_payload_size, 456);
315+
assert_eq!(config.compressor_kind, "gzip");
316+
assert_eq!(config.zstd_compressor_level, 7);
317+
assert!(config.log_payloads);
353318
}
354319
}

0 commit comments

Comments
 (0)