objectstore_log/
config.rs

1use std::fmt;
2
3use serde::{Deserialize, Serialize};
4use tracing::level_filters::LevelFilter;
5
6/// Log output format.
7///
8/// Controls how log messages are formatted. The format can be explicitly specified or
9/// auto-detected based on whether output is to a TTY.
10#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Deserialize, Serialize)]
11#[serde(rename_all = "lowercase")]
12pub enum LogFormat {
13    /// Auto detect the best format.
14    ///
15    /// This chooses [`LogFormat::Pretty`] for TTY, otherwise [`LogFormat::Simplified`].
16    Auto,
17
18    /// Pretty printing with colors.
19    ///
20    /// ```text
21    ///  INFO  objectstore::http > objectstore starting
22    /// ```
23    Pretty,
24
25    /// Simplified plain text output.
26    ///
27    /// ```text
28    /// 2020-12-04T12:10:32Z [objectstore::http] INFO: objectstore starting
29    /// ```
30    Simplified,
31
32    /// Dump out JSON lines.
33    ///
34    /// ```text
35    /// {"timestamp":"2020-12-04T12:11:08.729716Z","level":"INFO","logger":"objectstore::http","message":"objectstore starting","module_path":"objectstore::http","filename":"objectstore_service/src/http.rs","lineno":31}
36    /// ```
37    Json,
38}
39
40/// The logging format parse error.
41#[derive(Clone, Debug)]
42pub struct FormatParseError(String);
43
44impl fmt::Display for FormatParseError {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        write!(
47            f,
48            r#"error parsing "{}" as format: expected one of "auto", "pretty", "simplified", "json""#,
49            self.0
50        )
51    }
52}
53
54impl std::str::FromStr for LogFormat {
55    type Err = FormatParseError;
56
57    fn from_str(s: &str) -> Result<Self, Self::Err> {
58        let result = match s {
59            "" => LogFormat::Auto,
60            s if s.eq_ignore_ascii_case("auto") => LogFormat::Auto,
61            s if s.eq_ignore_ascii_case("pretty") => LogFormat::Pretty,
62            s if s.eq_ignore_ascii_case("simplified") => LogFormat::Simplified,
63            s if s.eq_ignore_ascii_case("json") => LogFormat::Json,
64            s => return Err(FormatParseError(s.into())),
65        };
66
67        Ok(result)
68    }
69}
70
71impl std::error::Error for FormatParseError {}
72
73mod display_fromstr {
74    pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
75    where
76        S: serde::Serializer,
77        T: std::fmt::Display,
78    {
79        serializer.collect_str(&value)
80    }
81
82    pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
83    where
84        D: serde::Deserializer<'de>,
85        T: std::str::FromStr,
86        <T as std::str::FromStr>::Err: std::fmt::Display,
87    {
88        use serde::Deserialize;
89        let s = <std::borrow::Cow<'de, str>>::deserialize(deserializer)?;
90        s.parse().map_err(serde::de::Error::custom)
91    }
92}
93
94/// Logging configuration.
95///
96/// Controls the verbosity and format of log output. Logs are always written to stderr.
97#[derive(Debug, Deserialize, Serialize)]
98pub struct LoggingConfig {
99    /// Minimum log level to output.
100    ///
101    /// Controls which log messages are emitted based on their severity. Messages at or above this
102    /// level will be output. Valid levels in increasing severity: TRACE, DEBUG, INFO, WARN, ERROR,
103    /// OFF.
104    ///
105    /// The `RUST_LOG` environment variable provides more granular control per module if needed.
106    ///
107    /// **Important**: Levels `DEBUG` and `TRACE` are very verbose and can impact performance; use
108    /// only for debugging.
109    ///
110    /// # Default
111    ///
112    /// `INFO`
113    ///
114    /// # Environment Variable
115    ///
116    /// `OS__LOGGING__LEVEL`
117    ///
118    /// # Considerations
119    ///
120    /// - `TRACE` and `DEBUG` can be very verbose and impact performance; use only for debugging
121    /// - `INFO` is appropriate for production
122    /// - `WARN` or `ERROR` can be used to reduce log volume in high-traffic systems
123    #[serde(with = "display_fromstr")]
124    pub level: LevelFilter,
125
126    /// Log output format.
127    ///
128    /// Determines how log messages are formatted. See [`LogFormat`] for available options and
129    /// examples.
130    ///
131    /// # Default
132    ///
133    /// `Auto` (pretty for TTY, simplified otherwise)
134    ///
135    /// # Environment Variable
136    ///
137    /// `OS__LOGGING__FORMAT`
138    pub format: LogFormat,
139}
140
141impl Default for LoggingConfig {
142    fn default() -> Self {
143        Self {
144            level: LevelFilter::INFO,
145            format: LogFormat::Auto,
146        }
147    }
148}