spring/log/
config.rs

1use crate::config::Configurable;
2use schemars::JsonSchema;
3use serde::Deserialize;
4use std::fmt::Display;
5
6impl Configurable for LoggerConfig {
7    fn config_prefix() -> &'static str {
8        "logger"
9    }
10}
11
12crate::config::submit! {
13    crate::config::ConfigSchema {
14        prefix: "logger",
15        schema: || crate::config::schema_for!(LoggerConfig),
16    }
17}
18
19#[derive(Debug, Clone, JsonSchema, Deserialize)]
20pub(crate) struct LoggerConfig {
21    #[serde(default = "default_true")]
22    pub enable: bool,
23
24    /// Enable nice display of backtraces, in development this should be on.
25    /// Turn it off in performance sensitive production deployments.
26    #[serde(default)]
27    pub pretty_backtrace: bool,
28
29    /// Set the logger level.
30    ///
31    /// * options: `trace` | `debug` | `info` | `warn` | `error`
32    #[serde(default)]
33    pub level: LogLevel,
34
35    /// Set the logger format.
36    ///
37    /// * options: `compact` | `pretty` | `json`
38    #[serde(default)]
39    pub format: Format,
40
41    /// Formatters for event timestamps.
42    #[serde(default)]
43    pub time_style: TimeStyle,
44
45    #[serde(default)]
46    pub time_pattern: ChronoTimePattern,
47
48    #[serde(default)]
49    pub with_fields: Vec<WithFields>,
50
51    /// Override our custom tracing filter.
52    ///
53    /// Set this to your own filter if you want to see traces from internal
54    /// libraries. See more [here](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives)
55    pub override_filter: Option<String>,
56
57    /// Set this if you want to write log to file
58    #[serde(rename = "file")]
59    pub file_appender: Option<LoggerFileAppender>,
60}
61
62#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]
63pub(crate) enum LogLevel {
64    /// The "off" level.
65    #[serde(rename = "off")]
66    Off,
67    /// The "trace" level.
68    #[serde(rename = "trace")]
69    Trace,
70    /// The "debug" level.
71    #[serde(rename = "debug")]
72    Debug,
73    /// The "info" level.
74    #[serde(rename = "info")]
75    #[default]
76    Info,
77    /// The "warn" level.
78    #[serde(rename = "warn")]
79    Warn,
80    /// The "error" level.
81    #[serde(rename = "error")]
82    Error,
83}
84
85impl Display for LogLevel {
86    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87        write!(
88            f,
89            "{}",
90            match self {
91                Self::Off => "off",
92                Self::Trace => "trace",
93                Self::Debug => "debug",
94                Self::Info => "info",
95                Self::Warn => "warn",
96                Self::Error => "error",
97            }
98        )
99    }
100}
101
102#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]
103pub(crate) enum Format {
104    #[serde(rename = "compact")]
105    #[default]
106    Compact,
107    #[serde(rename = "pretty")]
108    Pretty,
109    #[serde(rename = "json")]
110    Json,
111}
112
113/// https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/time/index.html
114#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]
115pub(crate) enum TimeStyle {
116    /// Retrieve and print the current wall-clock time.
117    #[serde(rename = "system")]
118    SystemTime,
119    /// Retrieve and print the relative elapsed wall-clock time since an epoch.
120    #[serde(rename = "uptime")]
121    Uptime,
122    /// Formats local times and UTC times with FormatTime implementations that use the chrono crate.
123    #[default]
124    #[serde(rename = "local")]
125    ChronoLocal,
126    /// Formats the current UTC time using a formatter from the chrono crate.
127    #[serde(rename = "utc")]
128    ChronoUtc,
129    #[serde(rename = "none")]
130    None,
131}
132
133#[derive(Debug, Clone, JsonSchema, Deserialize)]
134#[serde(transparent)]
135pub(crate) struct ChronoTimePattern(String);
136
137impl Default for ChronoTimePattern {
138    fn default() -> Self {
139        Self("%Y-%m-%dT%H:%M:%S".to_string())
140    }
141}
142
143#[allow(clippy::to_string_trait_impl)]
144impl ToString for ChronoTimePattern {
145    fn to_string(&self) -> String {
146        self.0.to_string()
147    }
148}
149
150#[derive(Debug, Clone, JsonSchema, Deserialize)]
151#[serde(rename_all = "snake_case")]
152pub(crate) enum WithFields {
153    File,
154    LineNumber,
155    ThreadId,
156    ThreadName,
157    InternalErrors,
158}
159
160#[derive(Debug, Clone, JsonSchema, Deserialize)]
161pub(crate) struct LoggerFileAppender {
162    pub enable: bool,
163    #[serde(default = "default_true")]
164    pub non_blocking: bool,
165    #[serde(default)]
166    pub format: Format,
167    #[serde(default)]
168    pub rotation: Rotation,
169    #[serde(default = "default_dir")]
170    pub dir: String,
171    #[serde(default = "default_prefix")]
172    pub filename_prefix: String,
173    #[serde(default = "default_suffix")]
174    pub filename_suffix: String,
175    #[serde(default = "default_max_log_files")]
176    pub max_log_files: usize,
177}
178
179#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]
180pub(crate) enum Rotation {
181    #[serde(rename = "minutely")]
182    Minutely,
183    #[serde(rename = "hourly")]
184    Hourly,
185    #[serde(rename = "daily")]
186    #[default]
187    Daily,
188    #[serde(rename = "never")]
189    Never,
190}
191
192fn default_dir() -> String {
193    "./logs".to_string()
194}
195
196fn default_prefix() -> String {
197    "app".to_string()
198}
199
200fn default_suffix() -> String {
201    "log".to_string()
202}
203
204fn default_max_log_files() -> usize {
205    365
206}
207
208fn default_true() -> bool {
209    true
210}
211
212#[allow(clippy::from_over_into)]
213impl Into<tracing_appender::rolling::Rotation> for Rotation {
214    fn into(self) -> tracing_appender::rolling::Rotation {
215        match self {
216            Self::Minutely => tracing_appender::rolling::Rotation::MINUTELY,
217            Self::Hourly => tracing_appender::rolling::Rotation::HOURLY,
218            Self::Daily => tracing_appender::rolling::Rotation::DAILY,
219            Self::Never => tracing_appender::rolling::Rotation::NEVER,
220        }
221    }
222}