1use figment::{
3 providers::Serialized,
4 value::{Dict, Map},
5 Error, Metadata, Profile, Provider,
6};
7
8pub const KEY_ALIASES: &[(&str, &str)] = &[
15 ("proxy.http", "proxy_http"),
19 ("proxy.https", "proxy_https"),
20 ("proxy.no_proxy", "proxy_no_proxy"),
21 ("apm_config.enable_rare_sampler", "apm_enable_rare_sampler"),
22 (
23 "apm_config.error_tracking_standalone.enabled",
24 "apm_error_tracking_standalone_enabled",
25 ),
26 (
31 "apm_config.obfuscation.credit_cards.enabled",
32 "apm_obfuscation_credit_cards_enabled",
33 ),
34 (
35 "apm_config.obfuscation.credit_cards.keep_values",
36 "apm_obfuscation_credit_cards_keep_values",
37 ),
38 (
39 "apm_config.obfuscation.credit_cards.luhn",
40 "apm_obfuscation_credit_cards_luhn",
41 ),
42 (
43 "apm_config.obfuscation.elasticsearch.enabled",
44 "apm_obfuscation_elasticsearch_enabled",
45 ),
46 (
47 "apm_config.obfuscation.elasticsearch.keep_values",
48 "apm_obfuscation_elasticsearch_keep_values",
49 ),
50 (
51 "apm_config.obfuscation.elasticsearch.obfuscate_sql_values",
52 "apm_obfuscation_elasticsearch_obfuscate_sql_values",
53 ),
54 (
55 "apm_config.obfuscation.http.remove_paths_with_digits",
56 "apm_obfuscation_http_remove_paths_with_digits",
57 ),
58 (
59 "apm_config.obfuscation.http.remove_query_string",
60 "apm_obfuscation_http_remove_query_string",
61 ),
62 (
63 "apm_config.obfuscation.memcached.enabled",
64 "apm_obfuscation_memcached_enabled",
65 ),
66 (
67 "apm_config.obfuscation.memcached.keep_command",
68 "apm_obfuscation_memcached_keep_command",
69 ),
70 (
71 "apm_config.obfuscation.mongodb.enabled",
72 "apm_obfuscation_mongodb_enabled",
73 ),
74 (
75 "apm_config.obfuscation.mongodb.keep_values",
76 "apm_obfuscation_mongodb_keep_values",
77 ),
78 (
79 "apm_config.obfuscation.mongodb.obfuscate_sql_values",
80 "apm_obfuscation_mongodb_obfuscate_sql_values",
81 ),
82 (
83 "apm_config.obfuscation.opensearch.enabled",
84 "apm_obfuscation_opensearch_enabled",
85 ),
86 (
87 "apm_config.obfuscation.opensearch.keep_values",
88 "apm_obfuscation_opensearch_keep_values",
89 ),
90 (
91 "apm_config.obfuscation.opensearch.obfuscate_sql_values",
92 "apm_obfuscation_opensearch_obfuscate_sql_values",
93 ),
94 ("apm_config.obfuscation.redis.enabled", "apm_obfuscation_redis_enabled"),
95 (
96 "apm_config.obfuscation.redis.remove_all_args",
97 "apm_obfuscation_redis_remove_all_args",
98 ),
99 (
100 "apm_config.obfuscation.valkey.enabled",
101 "apm_obfuscation_valkey_enabled",
102 ),
103 (
104 "apm_config.obfuscation.valkey.remove_all_args",
105 "apm_obfuscation_valkey_remove_all_args",
106 ),
107 ("apm_config.obfuscation.sql.dbms", "apm_obfuscation_sql_dbms"),
108 (
109 "apm_config.obfuscation.sql.dollar_quoted_func",
110 "apm_obfuscation_sql_dollar_quoted_func",
111 ),
112 (
113 "apm_config.obfuscation.sql.keep_sql_alias",
114 "apm_obfuscation_sql_keep_sql_alias",
115 ),
116 (
117 "apm_config.obfuscation.sql.replace_digits",
118 "apm_obfuscation_sql_replace_digits",
119 ),
120 (
121 "apm_config.obfuscation.sql.table_names",
122 "apm_obfuscation_sql_table_names",
123 ),
124 (
129 "otlp_config.traces.probabilistic_sampler.sampling_percentage",
130 "otlp_config_traces_probabilistic_sampler_sampling_percentage",
131 ),
132 ("agent_ipc.grpc_max_message_size", "agent_ipc_grpc_max_message_size"),
138];
139
140const ENV_REMAPPINGS: &[(&str, &str)] = &[("http_proxy", "proxy_http"), ("https_proxy", "proxy_https")];
144
145pub struct DatadogRemapper {
158 values: serde_json::Map<String, serde_json::Value>,
159}
160
161impl DatadogRemapper {
162 pub fn new() -> Self {
164 let mut values = serde_json::Map::new();
165
166 for (env_key, env_value) in std::env::vars() {
167 let lower = env_key.to_lowercase();
168 for &(from, to) in ENV_REMAPPINGS {
169 if lower == from && !values.contains_key(to) {
170 values.insert(to.to_string(), serde_json::Value::String(env_value.clone()));
171 }
172 }
173 }
174
175 Self { values }
176 }
177}
178
179impl Default for DatadogRemapper {
180 fn default() -> Self {
181 Self::new()
182 }
183}
184
185impl Provider for DatadogRemapper {
186 fn metadata(&self) -> Metadata {
187 Metadata::named("Datadog config remapper")
188 }
189
190 fn data(&self) -> Result<Map<Profile, Dict>, Error> {
191 if self.values.is_empty() {
192 return Ok(Map::new());
193 }
194 Serialized::defaults(serde_json::Value::Object(self.values.clone())).data()
195 }
196}
197
198#[cfg(test)]
199mod tests {
200 use super::*;
201
202 static ENV_MUTEX: std::sync::Mutex<()> = std::sync::Mutex::new(());
203
204 #[test]
205 fn env_var_remapped_case_insensitively() {
206 let _guard = ENV_MUTEX.lock().unwrap();
207
208 std::env::set_var("HTTP_PROXY", "http://proxy.example.com");
209 let remapper = DatadogRemapper::new();
210 std::env::remove_var("HTTP_PROXY");
211
212 assert_eq!(
213 remapper.values.get("proxy_http").and_then(|v| v.as_str()),
214 Some("http://proxy.example.com"),
215 );
216 }
217
218 #[test]
219 fn env_var_not_remapped_when_absent() {
220 let _guard = ENV_MUTEX.lock().unwrap();
221
222 std::env::remove_var("HTTP_PROXY");
223 std::env::remove_var("http_proxy");
224 std::env::remove_var("HTTPS_PROXY");
225 std::env::remove_var("https_proxy");
226
227 let remapper = DatadogRemapper::new();
228
229 assert!(remapper.values.get("proxy_http").is_none());
230 assert!(remapper.values.get("proxy_https").is_none());
231 }
232}