1use serde::Deserialize;
9
10#[derive(Debug, Clone, Deserialize)]
12pub struct LoggingConfig {
13 #[serde(default = "LoggingConfig::default_level")]
15 pub level: String,
16
17 #[serde(default)]
19 pub format: LogFormat,
20
21 pub service_name: Option<String>,
23
24 #[serde(default)]
26 pub output: LogOutput,
27
28 #[serde(default)]
30 pub with_caller: bool,
31}
32
33impl Default for LoggingConfig {
34 fn default() -> Self {
35 Self {
36 level: Self::default_level(),
37 format: LogFormat::default(),
38 service_name: None,
39 output: LogOutput::default(),
40 with_caller: false,
41 }
42 }
43}
44
45impl LoggingConfig {
46 fn default_level() -> String {
47 "info".to_string()
48 }
49}
50
51#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Default)]
53#[non_exhaustive]
54#[serde(rename_all = "lowercase")]
55pub enum LogFormat {
56 Json,
58 #[default]
60 Console,
61}
62
63#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Default)]
65#[non_exhaustive]
66#[serde(tag = "type", rename_all = "lowercase")]
67pub enum LogOutput {
68 #[default]
70 Stdout,
71 Stderr,
73 File {
75 path: String,
77 },
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn logging_config_default_level() {
86 let cfg = LoggingConfig::default();
87 assert_eq!(cfg.level, "info");
88 }
89
90 #[test]
91 fn logging_config_default_format() {
92 let cfg = LoggingConfig::default();
93 assert_eq!(cfg.format, LogFormat::Console);
94 }
95
96 #[test]
97 fn logging_config_default_output() {
98 let cfg = LoggingConfig::default();
99 assert_eq!(cfg.output, LogOutput::Stdout);
100 }
101
102 #[test]
103 fn logging_config_default_service_name_is_none() {
104 let cfg = LoggingConfig::default();
105 assert!(cfg.service_name.is_none());
106 }
107
108 #[test]
109 fn logging_config_default_with_caller_false() {
110 let cfg = LoggingConfig::default();
111 assert!(!cfg.with_caller);
112 }
113
114 #[test]
115 fn log_format_default_is_console() {
116 assert_eq!(LogFormat::default(), LogFormat::Console);
117 }
118
119 #[test]
120 fn log_format_json_variant() {
121 let fmt = LogFormat::Json;
122 assert_ne!(fmt, LogFormat::Console);
123 }
124
125 #[test]
126 fn log_format_deserialize_json() {
127 let fmt: LogFormat = serde_json::from_str(r#""json""#).unwrap();
128 assert_eq!(fmt, LogFormat::Json);
129 }
130
131 #[test]
132 fn log_format_deserialize_console() {
133 let fmt: LogFormat = serde_json::from_str(r#""console""#).unwrap();
134 assert_eq!(fmt, LogFormat::Console);
135 }
136
137 #[test]
138 fn log_output_default_is_stdout() {
139 assert_eq!(LogOutput::default(), LogOutput::Stdout);
140 }
141
142 #[test]
143 fn log_output_stderr_variant() {
144 let out = LogOutput::Stderr;
145 assert_ne!(out, LogOutput::Stdout);
146 }
147
148 #[test]
149 fn log_output_file_variant() {
150 let out = LogOutput::File {
151 path: "/var/log/app.log".to_string(),
152 };
153 assert_eq!(
154 out,
155 LogOutput::File {
156 path: "/var/log/app.log".to_string()
157 }
158 );
159 }
160
161 #[test]
162 fn log_output_deserialize_stdout() {
163 let out: LogOutput = serde_json::from_str(r#"{"type":"stdout"}"#).unwrap();
164 assert_eq!(out, LogOutput::Stdout);
165 }
166
167 #[test]
168 fn log_output_deserialize_stderr() {
169 let out: LogOutput = serde_json::from_str(r#"{"type":"stderr"}"#).unwrap();
170 assert_eq!(out, LogOutput::Stderr);
171 }
172
173 #[test]
174 fn log_output_deserialize_file() {
175 let out: LogOutput =
176 serde_json::from_str(r#"{"type":"file","path":"/logs/app.log"}"#).unwrap();
177 assert_eq!(
178 out,
179 LogOutput::File {
180 path: "/logs/app.log".to_string()
181 }
182 );
183 }
184}