drive_abci/logging/config.rs
1use crate::config::FromEnv;
2use crate::logging::level::LogLevel;
3use crate::logging::{LogDestination, LogFormat};
4use regex::Regex;
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8/// Logging configuration.
9#[derive(Serialize, Deserialize, Debug, Clone, Default)]
10pub struct LogConfig {
11 /// Destination of logs.
12 pub destination: LogDestination,
13 /// Log level
14 #[serde(default)]
15 pub level: LogLevel,
16 /// Whether or not to use colorful output; defaults to autodetect
17 #[serde(default)]
18 pub color: Option<bool>,
19 /// Output format to use.
20 #[serde(default)]
21 pub format: LogFormat,
22 /// Max number of daily files to store, excluding active one; only used when storing logs in file; defaults to 0 - rotation disabled
23 #[serde(default)]
24 pub max_files: usize,
25}
26
27/// Configuration of log destinations.
28///
29/// Logs can be sent to multiple destinations. Configuration of each of them is prefixed with `ABCI_LOG_<key>_`,
30/// where `<key>` is some arbitrary alphanumeric name of log configuration.
31///
32/// Key must match pattern `[A-Za-z0-9]+`.
33///
34/// Note that parsing of LogConfigs is implemented in [PlatformConfig::from_env()] due to limitations of [envy] crate.
35///
36/// ## Example
37///
38/// ```bash
39/// # First logger, logging to stderr on verbosity level 5
40/// ABCI_LOG_STDERR_DESTINATION=stderr
41/// ABCI_LOG_STDERR_LEVEL=trace
42///
43/// # Second logger, logging to stdout on verbosity level 1
44/// ABCI_LOG_STDOUT_DESTINATION=stdout
45/// ABCI_LOG_STDOUT_LEVEL=info
46/// ```
47///
48///
49/// [PlatformConfig::from_env()]: crate::config::PlatformConfig::from_env()
50pub type LogConfigs = HashMap<String, LogConfig>;
51
52impl FromEnv for LogConfigs {
53 /// create new object using values from environment variables
54 fn from_env() -> Result<Self, crate::error::Error>
55 where
56 Self: Sized,
57 {
58 let re: Regex = Regex::new(r"^ABCI_LOG_([0-9a-zA-Z]+)_DESTINATION$").unwrap();
59 let keys = std::env::vars().filter_map(|(key, _)| {
60 re.captures(&key)
61 .and_then(|capt| capt.get(1))
62 .map(|m| m.as_str().to_string())
63 });
64
65 let mut configs: HashMap<String, LogConfig> = HashMap::new();
66 for key in keys {
67 let config: LogConfig = envy::prefixed(format! {"ABCI_LOG_{}_", key.as_str()})
68 .from_env()
69 .map_err(crate::error::Error::from)?;
70
71 configs.insert(key, config);
72 }
73
74 Ok(configs)
75 }
76}