1#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
12#[non_exhaustive]
13pub enum Format {
14 #[default]
16 Auto,
17 Compact,
19 Pretty,
21 Json,
24}
25
26impl Format {
27 #[must_use]
29 pub fn from_env_value(value: &str) -> Self {
30 match value.trim().to_ascii_lowercase().as_str() {
31 "compact" => Self::Compact,
32 "pretty" => Self::Pretty,
33 "json" => Self::Json,
34 _ => Self::Auto,
35 }
36 }
37}
38
39#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
47#[non_exhaustive]
48pub enum Sink {
49 #[default]
51 Auto,
52 Stdout,
54 Stderr,
56 Journald,
58}
59
60impl Sink {
61 #[must_use]
63 pub fn from_env_value(value: &str) -> Self {
64 match value.trim().to_ascii_lowercase().as_str() {
65 "stdout" => Self::Stdout,
66 "stderr" => Self::Stderr,
67 "journald" => Self::Journald,
68 _ => Self::Auto,
69 }
70 }
71}
72
73#[derive(Debug, Clone, Default)]
90pub struct InitOptions {
91 pub(crate) service_name: Option<String>,
92 pub(crate) default_filter: Option<String>,
93 pub(crate) env_var: Option<String>,
94 pub(crate) format: Format,
95 pub(crate) sink: Sink,
96 pub(crate) idempotent: bool,
97 #[cfg(feature = "with-otlp")]
98 pub(crate) otlp: Option<crate::otlp::OtlpConfig>,
99}
100
101impl InitOptions {
102 #[must_use]
105 pub fn with_service_name(mut self, name: impl Into<String>) -> Self {
106 self.service_name = Some(name.into());
107 self
108 }
109
110 #[must_use]
113 pub fn with_default_filter(mut self, filter: impl Into<String>) -> Self {
114 self.default_filter = Some(filter.into());
115 self
116 }
117
118 #[must_use]
122 pub fn with_env_var(mut self, var: impl Into<String>) -> Self {
123 self.env_var = Some(var.into());
124 self
125 }
126
127 #[must_use]
129 pub fn with_format(mut self, format: Format) -> Self {
130 self.format = format;
131 self
132 }
133
134 #[must_use]
136 pub fn with_sink(mut self, sink: Sink) -> Self {
137 self.sink = sink;
138 self
139 }
140
141 #[must_use]
148 pub fn idempotent(mut self, enabled: bool) -> Self {
149 self.idempotent = enabled;
150 self
151 }
152
153 #[cfg(feature = "with-otlp")]
156 #[must_use]
157 pub fn with_otlp(mut self, config: crate::otlp::OtlpConfig) -> Self {
158 self.otlp = Some(config);
159 self
160 }
161
162 #[cfg(feature = "systemd")]
163 pub(crate) fn resolved_env_var(&self) -> &str {
164 self.env_var.as_deref().unwrap_or("RUST_LOG")
165 }
166
167 #[cfg(feature = "systemd")]
168 pub(crate) fn resolved_default_filter(&self) -> &str {
169 if let Some(filter) = self.default_filter.as_deref() {
170 return filter;
171 }
172 if cfg!(debug_assertions) { "debug" } else { "info" }
173 }
174
175 #[cfg(feature = "wasm32")]
176 pub(crate) fn resolved_default_filter(&self) -> &str {
177 if let Some(filter) = self.default_filter.as_deref() {
178 return filter;
179 }
180 if cfg!(debug_assertions) { "debug" } else { "info" }
181 }
182
183 #[cfg(feature = "wasm32")]
184 pub(crate) fn resolved_wasm_format(&self) -> Format {
185 match self.format {
186 Format::Auto => Format::Json,
187 format => format,
188 }
189 }
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195
196 #[test]
197 fn builder_sets_every_field() {
198 let opts = InitOptions::default()
199 .with_service_name("svc")
200 .with_default_filter("warn")
201 .with_env_var("KKP_LOG")
202 .with_format(Format::Json)
203 .with_sink(Sink::Stdout)
204 .idempotent(true);
205 assert_eq!(opts.service_name.as_deref(), Some("svc"));
206 assert_eq!(opts.default_filter.as_deref(), Some("warn"));
207 assert_eq!(opts.env_var.as_deref(), Some("KKP_LOG"));
208 assert_eq!(opts.format, Format::Json);
209 assert_eq!(opts.sink, Sink::Stdout);
210 assert!(opts.idempotent);
211 }
212
213 #[cfg(feature = "systemd")]
214 #[test]
215 fn resolved_helpers_apply_defaults_then_overrides() {
216 let default = InitOptions::default();
217 assert_eq!(default.resolved_env_var(), "RUST_LOG");
218 let expected = if cfg!(debug_assertions) { "debug" } else { "info" };
219 assert_eq!(default.resolved_default_filter(), expected);
220
221 let custom = InitOptions::default().with_env_var("KKP_LOG").with_default_filter("trace");
222 assert_eq!(custom.resolved_env_var(), "KKP_LOG");
223 assert_eq!(custom.resolved_default_filter(), "trace");
224 }
225}