@@ -117,10 +117,54 @@ impl DogStatsdConfig {
117117/// unset. The current value caps the preallocation at 512 MiB.
118118const MAX_STRING_INTERNER_ENTRIES : u64 = 1_048_576 ;
119119
120+ /// Compressor both targets serialize metric payloads with.
121+ #[ derive( Debug , Clone , Copy , Serialize ) ]
122+ #[ serde( rename_all = "lowercase" ) ]
123+ pub ( crate ) enum CompressorKind {
124+ /// Deflate. Disables the v3 series intake on both targets.
125+ Zlib ,
126+ /// Zstandard.
127+ Zstd ,
128+ /// Gzip.
129+ Gzip ,
130+ /// No compression, the Agent's `NoneKind`.
131+ None ,
132+ /// A codec neither target implements, so each falls back its own way and the two lanes disagree
133+ /// on the wire from one config value.
134+ Snappy ,
135+ }
136+
137+ impl Distribution < CompressorKind > for StandardUniform {
138+ fn sample < R : Rng + ?Sized > ( & self , rng : & mut R ) -> CompressorKind {
139+ match rng. random_range ( 0 ..5u8 ) {
140+ 0 => CompressorKind :: Zlib ,
141+ 1 => CompressorKind :: Zstd ,
142+ 2 => CompressorKind :: Gzip ,
143+ 3 => CompressorKind :: None ,
144+ _ => CompressorKind :: Snappy ,
145+ }
146+ }
147+ }
148+
149+ /// The Agent's nested `use_v3_api.series` switch between the v2 and v3 series
150+ /// intake.
151+ #[ derive( Debug , Serialize ) ]
152+ pub ( crate ) struct UseV3ApiConfig {
153+ /// The series sub-tree.
154+ series : V3SeriesConfig ,
155+ }
156+
157+ /// The `enabled` leaf under a v3 series key.
158+ #[ derive( Debug , Serialize ) ]
159+ pub ( crate ) struct V3SeriesConfig {
160+ /// Whether the series intake is v3 rather than v2.
161+ enabled : bool ,
162+ }
163+
120164/// Agent-facing config. `hostname`, `api_key`, `dd_url`, and the socket are
121- /// supplied by the environment; `log_level` and the `DogStatsD` options are
122- /// sampled per branch. The static flags are appended by [`Self::to_yaml`], not
123- /// fields here.
165+ /// supplied by the environment; `log_level`, the series intake API, and the
166+ /// `DogStatsD` options are sampled per branch. The static flags are appended by
167+ /// [`Self::to_yaml`], not fields here.
124168#[ derive( Debug , Serialize ) ]
125169pub struct DatadogConfig {
126170 /// Agent hostname. Supplied by the environment. ADP requires it
@@ -132,6 +176,13 @@ pub struct DatadogConfig {
132176 dd_url : String ,
133177 /// Agent log verbosity. Pinned to `error` (see [`LogLevel`]).
134178 log_level : LogLevel ,
179+ /// Series intake API for this timeline.
180+ use_v3_api : UseV3ApiConfig ,
181+ /// Compressor for metric payloads. Sampled independently of the series API.
182+ serializer_compressor_kind : CompressorKind ,
183+ /// ADP's safety gate for authoritative v3 series, which the Agent has no counterpart for.
184+ /// Sampled with [`Self::use_v3_api`] so ADP and the Agent never split encodings in a timeline.
185+ data_plane_metrics_v3_series_enabled : bool ,
135186 /// `DogStatsD` options, flattened to top-level `dogstatsd_*` keys.
136187 #[ serde( flatten) ]
137188 dogstatsd : DogStatsdConfig ,
@@ -145,11 +196,17 @@ impl DatadogConfig {
145196 pub fn sample < R : Rng + ?Sized > (
146197 rng : & mut R , hostname : & str , api_key : & str , dd_url : & str , dogstatsd_socket : & Path ,
147198 ) -> Self {
199+ let series_v3 = rng. random ( ) ;
148200 Self {
149201 hostname : hostname. to_owned ( ) ,
150202 api_key : api_key. to_owned ( ) ,
151203 dd_url : dd_url. to_owned ( ) ,
152204 log_level : LogLevel :: Error ,
205+ use_v3_api : UseV3ApiConfig {
206+ series : V3SeriesConfig { enabled : series_v3 } ,
207+ } ,
208+ serializer_compressor_kind : rng. random ( ) ,
209+ data_plane_metrics_v3_series_enabled : series_v3,
153210 dogstatsd : DogStatsdConfig :: sample ( rng, dogstatsd_socket) ,
154211 }
155212 }
@@ -177,7 +234,6 @@ impl DatadogConfig {
177234
178235/// Yaml flags the Agent reads at boot that never vary.
179236const STATIC_YAML_TAIL : & str = "use_dogstatsd: true
180- use_v2_api_series: true
181237inventories_enabled: false
182238enable_metadata_collection: false
183239cloud_provider_metadata: []
@@ -239,6 +295,7 @@ impl DriverConfig {
239295
240296#[ cfg( test) ]
241297mod tests {
298+ use std:: collections:: BTreeSet ;
242299 use std:: convert:: Infallible ;
243300
244301 use rand:: rand_core:: TryRng ;
@@ -303,4 +360,53 @@ mod tests {
303360 assert ! ( has_key( & render( 0 ) , "log_level" ) ) ;
304361 assert ! ( render( 0 ) . contains( "log_level: error" ) ) ;
305362 }
363+
364+ /// The Agent's nested switch and ADP's safety gate, as a timeline renders them.
365+ fn series_api ( seed : u64 ) -> ( bool , bool ) {
366+ let yaml = render ( seed) ;
367+ let parsed: serde_yaml:: Value = serde_yaml:: from_str ( & yaml) . expect ( "parse rendered yaml" ) ;
368+ let agent = parsed[ "use_v3_api" ] [ "series" ] [ "enabled" ]
369+ . as_bool ( )
370+ . expect ( "use_v3_api.series.enabled" ) ;
371+ let adp = parsed[ "data_plane_metrics_v3_series_enabled" ]
372+ . as_bool ( )
373+ . expect ( "data_plane_metrics_v3_series_enabled" ) ;
374+ ( agent, adp)
375+ }
376+
377+ #[ test]
378+ fn both_lanes_share_one_series_api ( ) {
379+ for seed in 0 ..16 {
380+ let ( agent, adp) = series_api ( seed) ;
381+ assert_eq ! ( agent, adp, "seed {seed}" ) ;
382+ }
383+ }
384+
385+ #[ test]
386+ fn series_api_samples_both_intakes ( ) {
387+ let mut seen = [ false , false ] ;
388+ for seed in 0 ..16 {
389+ seen[ usize:: from ( series_api ( seed) . 0 ) ] = true ;
390+ }
391+ assert_eq ! ( seen, [ true , true ] ) ;
392+ }
393+
394+ #[ test]
395+ fn compressor_samples_every_kind ( ) {
396+ let mut seen = BTreeSet :: new ( ) ;
397+ for seed in 0 ..64 {
398+ let yaml = render ( seed) ;
399+ let kind = yaml
400+ . lines ( )
401+ . find_map ( |line| line. strip_prefix ( "serializer_compressor_kind: " ) )
402+ . expect ( "serializer_compressor_kind" )
403+ . to_owned ( ) ;
404+ seen. insert ( kind) ;
405+ }
406+ let want = [ "gzip" , "none" , "snappy" , "zlib" , "zstd" ]
407+ . into_iter ( )
408+ . map ( str:: to_owned)
409+ . collect :: < BTreeSet < _ > > ( ) ;
410+ assert_eq ! ( seen, want) ;
411+ }
306412}
0 commit comments