nitro_log/
format.rs

1use std::collections::VecDeque;
2use crate::config::FormatConfig;
3use crate::format::FormatError::MissingKey;
4use crate::placeholder::PlaceholderBuilder;
5use crate::Placeholder;
6use regex::Regex;
7use serde_json::Value;
8use thiserror::Error;
9use crate::kv::Variable;
10
11#[derive(Debug, Error)]
12pub enum FormatError {
13    #[error("{0}")]
14    SettingParseError(serde_json::Error),
15    #[error("Missing Key {0}")]
16    MissingKey(String),
17}
18
19#[derive(Debug)]
20pub struct Format {
21    pub format: Vec<FormatSection>,
22}
23
24#[derive(Debug)]
25pub enum FormatSection {
26    Text(String),
27    Variable(Variable),
28    Placeholder(Box<dyn Placeholder>),
29}
30
31
32impl Format {
33    /// {{ placeholder({"format": "", "key": ""}) }}
34    /// {{ variable.name }}
35    /// Example format `Important Log Message Here  {{level({"color": true })}} {{ repository.name }}: {{message({})}}!!!`
36    pub fn new(
37        placeholders: &[Box<dyn PlaceholderBuilder>],
38        format: FormatConfig,
39        path_safe: bool,
40    ) -> Result<Format, FormatError> where {
41        let special_call_parse: Regex =
42            Regex::new("\\{\\{(?P<key>.+?)(?P<PlaceHolder>[(](?P<settings>.+?)?[)])?}}+").unwrap();
43        let mut matches = special_call_parse.captures_iter(format.format.as_str());
44        let mut variables = Vec::new();
45        for value in special_call_parse.split(format.format.as_str()) {
46            variables.push(FormatSection::Text(value.to_string()));
47            if let Some(capture) = matches.next() {
48                let key = capture
49                    .name("key")
50                    .ok_or_else(|| FormatError::MissingKey("Missing Key".to_string()))?;
51                let special_call = if capture.name("PlaceHolder").is_some() {
52                    let settings = if let Some(settings) = capture.name("settings") {
53                        let settings_string = settings.as_str();
54                        let mut placeholder_settings =
55                            if settings_string.starts_with('{') && settings_string.ends_with('}') {
56                                serde_json::from_str(settings_string)
57                                    .map_err(FormatError::SettingParseError)
58                            } else {
59                                format
60                                    .placeholders
61                                    .get(settings_string)
62                                    .ok_or_else(|| {
63                                        FormatError::MissingKey(format!(
64                                            "Missing Setting for {}",
65                                            settings_string
66                                        ))
67                                    })
68                                    .cloned()
69                            }?;
70                        let value_map = placeholder_settings.as_object_mut().unwrap();
71                        value_map.insert("path".to_string(), Value::Bool(path_safe));
72                        Some(
73                            serde_json::to_value(placeholder_settings)
74                                .map_err(FormatError::SettingParseError)?,
75                        )
76                    } else {
77                        None
78                    };
79                    let result = placeholders
80                        .iter()
81                        .find(|pb| pb.name().eq(key.as_str()))
82                        .ok_or_else(|| {
83                            MissingKey(format!("Missing Placeholder {}", key.as_str()))
84                        })?;
85                    FormatSection::Placeholder(result.build(settings).unwrap())
86                } else if key.as_str().contains('.') {
87                        let split = key.as_str().trim().split('.');
88                        let mut split: VecDeque<String> = split.map(|v| v.to_string()).collect();
89                        let key = split.pop_front().unwrap();
90
91                        FormatSection::Variable(Variable::PathVariable(key, split.into_iter().collect()))
92
93                }else {
94                    FormatSection::Variable(Variable::SinglePartVariable(key.as_str().trim().to_string()))
95                };
96
97                variables.push(special_call);
98            }
99        }
100        Ok(Format { format: variables })
101    }
102}