vector/common/
expansion.rs1use regex::Regex;
2use std::{collections::HashMap, sync::LazyLock};
3
4use crate::event::Value;
5
6static RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"[^0-9A-Za-z_]").unwrap());
7fn slugify_text(input: &str) -> String {
8 let result = RE.replace_all(input, "_");
9 result.to_lowercase()
10}
11
12pub(crate) fn pair_expansion(
15 key_s: &str,
16 value_s: &str,
17 static_pairs: &mut HashMap<String, String>,
18 dynamic_pairs: &mut HashMap<String, String>,
19) -> Result<HashMap<String, String>, serde_json::Error> {
20 let mut expanded_pairs = HashMap::new();
21 if let Some(opening_prefix) = key_s.strip_suffix('*') {
22 let output: serde_json::map::Map<String, serde_json::Value> =
23 serde_json::from_str(value_s)?;
24
25 for (k, v) in output {
28 let key = slugify_text(&format!("{opening_prefix}{k}"));
29 let val = Value::from(v).to_string_lossy().into_owned();
30 if val == "<null>" {
31 warn!("Encountered \"null\" value for dynamic pair. key: {}", key);
32 continue;
33 }
34 if let Some(prev) = dynamic_pairs.insert(key.clone(), val.clone()) {
35 warn!(
36 "Encountered duplicated dynamic pair. \
37 key: {}, value: {:?}, discarded value: {:?}",
38 key, val, prev
39 );
40 };
41 expanded_pairs.insert(key, val);
42 }
43 } else {
44 static_pairs.insert(key_s.to_string(), value_s.to_string());
45 expanded_pairs.insert(key_s.to_string(), value_s.to_string());
46 }
47 Ok(expanded_pairs)
48}