saluki_config/dynamic/
event.rs1use serde_json::Value as JsonValue;
4
5use crate::upsert;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct ConfigChangeEvent {
10 pub key: String,
12 pub old_value: Option<JsonValue>,
14 pub new_value: Option<JsonValue>,
16}
17
18#[derive(Clone, Copy, Debug, Eq, PartialEq)]
25pub enum Provenance {
26 Explicit,
29 Default,
31}
32
33#[derive(Clone, Debug, PartialEq)]
38pub struct ConfigSetting {
39 pub key: String,
41 pub value: JsonValue,
43 pub provenance: Provenance,
45}
46
47impl ConfigSetting {
48 pub fn new(key: impl Into<String>, value: JsonValue, provenance: Provenance) -> Self {
50 Self {
51 key: key.into(),
52 value,
53 provenance,
54 }
55 }
56
57 pub fn explicit(key: impl Into<String>, value: JsonValue) -> Self {
59 Self::new(key, value, Provenance::Explicit)
60 }
61}
62
63#[derive(Clone, Debug)]
65pub enum ConfigUpdate {
66 Snapshot(Vec<ConfigSetting>),
70 Partial(ConfigSetting),
74}
75
76impl ConfigUpdate {
77 pub fn snapshot(settings: impl IntoIterator<Item = ConfigSetting>) -> Self {
79 Self::Snapshot(settings.into_iter().collect())
80 }
81}
82
83pub fn settings_to_state(settings: &[ConfigSetting]) -> JsonValue {
88 let mut state = JsonValue::Object(serde_json::Map::new());
89 for setting in settings {
90 upsert(&mut state, &setting.key, setting.value.clone());
91 }
92
93 state
94}
95
96#[cfg(test)]
97mod tests {
98 use serde_json::json;
99
100 use super::{settings_to_state, ConfigSetting, Provenance};
101
102 #[test]
103 fn settings_expand_dotted_keys_into_nested_objects() {
104 let settings = [
105 ConfigSetting::explicit("dogstatsd_port", json!(8125)),
106 ConfigSetting::explicit("otlp_config.traces.enabled", json!(true)),
107 ];
108
109 assert_eq!(
110 settings_to_state(&settings),
111 json!({ "dogstatsd_port": 8125, "otlp_config": { "traces": { "enabled": true } } })
112 );
113 }
114
115 #[test]
116 fn object_valued_settings_keep_dotted_entry_keys_intact() {
117 let settings = [ConfigSetting::explicit(
118 "additional_endpoints",
119 json!({ "https://app.datadoghq.eu": ["deadbeef"] }),
120 )];
121
122 assert_eq!(
123 settings_to_state(&settings),
124 json!({ "additional_endpoints": { "https://app.datadoghq.eu": ["deadbeef"] } })
125 );
126 }
127
128 #[test]
129 fn later_settings_win_over_earlier_ones() {
130 let settings = [
131 ConfigSetting::new("dd_url", json!("https://app.datadoghq.com"), Provenance::Default),
132 ConfigSetting::explicit("dd_url", json!("https://app.datadoghq.eu")),
133 ];
134
135 assert_eq!(
136 settings_to_state(&settings),
137 json!({ "dd_url": "https://app.datadoghq.eu" })
138 );
139 }
140}