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 #[serde(default)]
27 pub pretty_backtrace: bool,
28
29 #[serde(default)]
33 pub level: LogLevel,
34
35 #[serde(default)]
39 pub format: Format,
40
41 #[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 pub override_filter: Option<String>,
56
57 #[serde(rename = "file")]
59 pub file_appender: Option<LoggerFileAppender>,
60}
61
62#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]
63pub(crate) enum LogLevel {
64 #[serde(rename = "off")]
66 Off,
67 #[serde(rename = "trace")]
69 Trace,
70 #[serde(rename = "debug")]
72 Debug,
73 #[serde(rename = "info")]
75 #[default]
76 Info,
77 #[serde(rename = "warn")]
79 Warn,
80 #[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#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]
115pub(crate) enum TimeStyle {
116 #[serde(rename = "system")]
118 SystemTime,
119 #[serde(rename = "uptime")]
121 Uptime,
122 #[default]
124 #[serde(rename = "local")]
125 ChronoLocal,
126 #[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}