@@ -191,6 +191,24 @@ impl<T: ConfigurationValueProvider> ConfigurationValueProvider for ConfigItemRef
191
191
}
192
192
}
193
193
194
+ /// A trait for providing configuration data for telemetry reporting.
195
+ ///
196
+ /// This trait standardizes how configuration items expose their current state
197
+ /// as `ddtelemetry::data::Configuration` payloads for telemetry collection.
198
+ /// It enables the configuration system to report configuration values, their
199
+ /// origins, and associated metadata to Datadog.
200
+ pub trait ConfigurationProvider {
201
+ /// Returns a telemetry configuration object representing the current state of this configuration item.
202
+ ///
203
+ /// # Parameters
204
+ ///
205
+ /// - `config_id`: Optional identifier for remote configuration scenarios.
206
+ /// When provided, this ID is included in the returned `Configuration` to
207
+ /// track which remote configuration is responsible for the current value.
208
+ ///
209
+ fn get_configuration ( & self , config_id : Option < String > ) -> Configuration ;
210
+ }
211
+
194
212
/// A trait for converting configuration values to their string representation for telemetry.
195
213
///
196
214
/// This trait is used to serialize configuration values into strings that can be sent
@@ -288,14 +306,16 @@ impl<T: Clone + ConfigurationValueProvider> ConfigItem<T> {
288
306
ConfigSourceOrigin :: Default
289
307
}
290
308
}
309
+ }
291
310
311
+ impl < T : Clone + ConfigurationValueProvider > ConfigurationProvider for ConfigItem < T > {
292
312
/// Gets a Configuration object used as telemetry payload
293
- fn get_configuration ( & self ) -> Configuration {
313
+ fn get_configuration ( & self , config_id : Option < String > ) -> Configuration {
294
314
Configuration {
295
315
name : self . name . to_string ( ) ,
296
316
value : self . value ( ) . get_configuration_value ( ) ,
297
317
origin : self . source ( ) . into ( ) ,
298
- config_id : None ,
318
+ config_id,
299
319
}
300
320
}
301
321
}
@@ -387,14 +407,18 @@ impl<T: ConfigurationValueProvider + Clone + Deref> ConfigItemWithOverride<T> {
387
407
ConfigItemRef :: Ref ( self . config_item . value ( ) )
388
408
}
389
409
}
410
+ }
390
411
412
+ impl < T : Clone + ConfigurationValueProvider + Deref > ConfigurationProvider
413
+ for ConfigItemWithOverride < T >
414
+ {
391
415
/// Gets a Configuration object used as telemetry payload
392
- fn get_configuration ( & self ) -> Configuration {
416
+ fn get_configuration ( & self , config_id : Option < String > ) -> Configuration {
393
417
Configuration {
394
418
name : self . config_item . name . to_string ( ) ,
395
419
value : self . value ( ) . get_configuration_value ( ) ,
396
420
origin : self . source ( ) . into ( ) ,
397
- config_id : None ,
421
+ config_id,
398
422
}
399
423
}
400
424
}
@@ -970,33 +994,33 @@ impl Config {
970
994
Self :: builder_with_sources ( & CompositeSource :: default_sources ( ) )
971
995
}
972
996
973
- pub fn get_telemetry_configuration ( & self ) -> Vec < Configuration > {
997
+ pub fn get_telemetry_configuration ( & self ) -> Vec < & dyn ConfigurationProvider > {
974
998
vec ! [
975
- self . service. get_configuration ( ) ,
976
- self . env. get_configuration ( ) ,
977
- self . version. get_configuration ( ) ,
978
- self . global_tags. get_configuration ( ) ,
979
- self . agent_host. get_configuration ( ) ,
980
- self . trace_agent_port. get_configuration ( ) ,
981
- self . trace_agent_url. get_configuration ( ) ,
982
- self . dogstatsd_agent_host. get_configuration ( ) ,
983
- self . dogstatsd_agent_port. get_configuration ( ) ,
984
- self . dogstatsd_agent_url. get_configuration ( ) ,
985
- self . trace_sampling_rules. get_configuration ( ) ,
986
- self . trace_rate_limit. get_configuration ( ) ,
987
- self . enabled. get_configuration ( ) ,
988
- self . log_level_filter. get_configuration ( ) ,
989
- self . trace_stats_computation_enabled. get_configuration ( ) ,
990
- self . telemetry_enabled. get_configuration ( ) ,
991
- self . telemetry_log_collection_enabled. get_configuration ( ) ,
992
- self . telemetry_heartbeat_interval. get_configuration ( ) ,
993
- self . trace_propagation_style. get_configuration ( ) ,
994
- self . trace_propagation_style_extract. get_configuration ( ) ,
995
- self . trace_propagation_style_inject. get_configuration ( ) ,
996
- self . trace_propagation_extract_first. get_configuration ( ) ,
997
- self . remote_config_enabled. get_configuration ( ) ,
998
- self . remote_config_poll_interval. get_configuration ( ) ,
999
- self . datadog_tags_max_length. get_configuration ( ) ,
999
+ & self . service,
1000
+ & self . env,
1001
+ & self . version,
1002
+ & self . global_tags,
1003
+ & self . agent_host,
1004
+ & self . trace_agent_port,
1005
+ & self . trace_agent_url,
1006
+ & self . dogstatsd_agent_host,
1007
+ & self . dogstatsd_agent_port,
1008
+ & self . dogstatsd_agent_url,
1009
+ & self . trace_sampling_rules,
1010
+ & self . trace_rate_limit,
1011
+ & self . enabled,
1012
+ & self . log_level_filter,
1013
+ & self . trace_stats_computation_enabled,
1014
+ & self . telemetry_enabled,
1015
+ & self . telemetry_log_collection_enabled,
1016
+ & self . telemetry_heartbeat_interval,
1017
+ & self . trace_propagation_style,
1018
+ & self . trace_propagation_style_extract,
1019
+ & self . trace_propagation_style_inject,
1020
+ & self . trace_propagation_extract_first,
1021
+ & self . remote_config_enabled,
1022
+ & self . remote_config_poll_interval,
1023
+ & self . datadog_tags_max_length,
1000
1024
]
1001
1025
}
1002
1026
@@ -1118,14 +1142,18 @@ impl Config {
1118
1142
* self . trace_propagation_extract_first . value ( )
1119
1143
}
1120
1144
1121
- pub fn update_sampling_rules_from_remote ( & self , rules_json : & str ) -> Result < ( ) , String > {
1145
+ pub fn update_sampling_rules_from_remote (
1146
+ & self ,
1147
+ rules_json : & str ,
1148
+ config_id : Option < String > ,
1149
+ ) -> Result < ( ) , String > {
1122
1150
// Parse the JSON into SamplingRuleConfig objects
1123
1151
let rules: Vec < SamplingRuleConfig > = serde_json:: from_str ( rules_json)
1124
1152
. map_err ( |e| format ! ( "Failed to parse sampling rules JSON: {e}" ) ) ?;
1125
1153
1126
1154
// If remote config sends empty rules, clear remote config to fall back to local rules
1127
1155
if rules. is_empty ( ) {
1128
- self . clear_remote_sampling_rules ( ) ;
1156
+ self . clear_remote_sampling_rules ( config_id ) ;
1129
1157
} else {
1130
1158
self . trace_sampling_rules . set_override_value (
1131
1159
ParsedSamplingRules { rules } ,
@@ -1137,7 +1165,7 @@ impl Config {
1137
1165
& RemoteConfigUpdate :: SamplingRules ( self . trace_sampling_rules ( ) . to_vec ( ) ) ,
1138
1166
) ;
1139
1167
1140
- telemetry:: notify_update_configuration ( self . trace_sampling_rules . get_configuration ( ) ) ;
1168
+ telemetry:: notify_configuration_update ( & self . trace_sampling_rules , config_id ) ;
1141
1169
}
1142
1170
1143
1171
Ok ( ( ) )
@@ -1152,14 +1180,14 @@ impl Config {
1152
1180
}
1153
1181
}
1154
1182
1155
- pub fn clear_remote_sampling_rules ( & self ) {
1183
+ pub fn clear_remote_sampling_rules ( & self , config_id : Option < String > ) {
1156
1184
self . trace_sampling_rules . unset_override_value ( ) ;
1157
1185
1158
1186
self . remote_config_callbacks . lock ( ) . unwrap ( ) . notify_update (
1159
1187
& RemoteConfigUpdate :: SamplingRules ( self . trace_sampling_rules ( ) . to_vec ( ) ) ,
1160
1188
) ;
1161
1189
1162
- telemetry:: notify_update_configuration ( self . trace_sampling_rules . get_configuration ( ) ) ;
1190
+ telemetry:: notify_configuration_update ( & self . trace_sampling_rules , config_id ) ;
1163
1191
}
1164
1192
1165
1193
/// Add a callback to be called when sampling rules are updated via remote configuration
@@ -1984,7 +2012,7 @@ mod tests {
1984
2012
1985
2013
let rules_json = serde_json:: to_string ( & new_rules) . unwrap ( ) ;
1986
2014
config
1987
- . update_sampling_rules_from_remote ( & rules_json)
2015
+ . update_sampling_rules_from_remote ( & rules_json, None )
1988
2016
. unwrap ( ) ;
1989
2017
1990
2018
// Callback should be called with the new rules
@@ -1995,7 +2023,7 @@ mod tests {
1995
2023
* callback_called. lock ( ) . unwrap ( ) = false ;
1996
2024
callback_rules. lock ( ) . unwrap ( ) . clear ( ) ;
1997
2025
1998
- config. clear_remote_sampling_rules ( ) ;
2026
+ config. clear_remote_sampling_rules ( None ) ;
1999
2027
2000
2028
// Callback should be called with fallback rules (empty in this case since no env/code rules
2001
2029
// set)
@@ -2118,7 +2146,7 @@ mod tests {
2118
2146
let remote_rules_json =
2119
2147
r#"[{"sample_rate": 0.8, "service": "remote-service", "provenance": "remote"}]"# ;
2120
2148
config
2121
- . update_sampling_rules_from_remote ( remote_rules_json)
2149
+ . update_sampling_rules_from_remote ( remote_rules_json, None )
2122
2150
. unwrap ( ) ;
2123
2151
2124
2152
// Verify remote rules override local rules
@@ -2132,7 +2160,7 @@ mod tests {
2132
2160
// 3. Remote config sends empty array []
2133
2161
let empty_remote_rules_json = "[]" ;
2134
2162
config
2135
- . update_sampling_rules_from_remote ( empty_remote_rules_json)
2163
+ . update_sampling_rules_from_remote ( empty_remote_rules_json, None )
2136
2164
. unwrap ( ) ;
2137
2165
2138
2166
// Empty remote rules automatically fall back to local rules
@@ -2145,7 +2173,7 @@ mod tests {
2145
2173
2146
2174
// 4. Verify explicit clearing still works (for completeness)
2147
2175
// Since we're already on local rules, clear should keep us on local rules
2148
- config. clear_remote_sampling_rules ( ) ;
2176
+ config. clear_remote_sampling_rules ( None ) ;
2149
2177
2150
2178
// Should remain on local rules
2151
2179
assert_eq ! ( config. trace_sampling_rules( ) . len( ) , 1 ) ;
@@ -2398,7 +2426,7 @@ mod tests {
2398
2426
r#"[{"sample_rate":0.5,"service":"web-api","name":null,"resource":null,"tags":{},"provenance":"customer"}]"#
2399
2427
) . unwrap ( ) ;
2400
2428
2401
- let configuration = & config. trace_sampling_rules . get_configuration ( ) ;
2429
+ let configuration = & config. trace_sampling_rules . get_configuration ( None ) ;
2402
2430
assert_eq ! ( configuration. origin, ConfigurationOrigin :: EnvVar ) ;
2403
2431
2404
2432
// Converting configuration value to json helps with comparison as serialized properties may
@@ -2414,7 +2442,7 @@ mod tests {
2414
2442
. trace_sampling_rules
2415
2443
. set_override_value ( expected_rc. clone ( ) , ConfigSourceOrigin :: RemoteConfig ) ;
2416
2444
2417
- let configuration_after_rc = & config. trace_sampling_rules . get_configuration ( ) ;
2445
+ let configuration_after_rc = & config. trace_sampling_rules . get_configuration ( None ) ;
2418
2446
assert_eq ! (
2419
2447
configuration_after_rc. origin,
2420
2448
ConfigurationOrigin :: RemoteConfig
@@ -2427,7 +2455,7 @@ mod tests {
2427
2455
// Reset ConfigItemRc RC previous value
2428
2456
config. trace_sampling_rules . unset_override_value ( ) ;
2429
2457
2430
- let configuration = & config. trace_sampling_rules . get_configuration ( ) ;
2458
+ let configuration = & config. trace_sampling_rules . get_configuration ( None ) ;
2431
2459
assert_eq ! ( configuration. origin, ConfigurationOrigin :: EnvVar ) ;
2432
2460
assert_eq ! (
2433
2461
ParsedSamplingRules :: from_str( & configuration. value) . unwrap( ) ,
0 commit comments