#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[non_exhaustive]
pub enum Format {
#[default]
Auto,
Compact,
Pretty,
Json,
}
impl Format {
#[must_use]
pub fn from_env_value(value: &str) -> Self {
match value.trim().to_ascii_lowercase().as_str() {
"compact" => Self::Compact,
"pretty" => Self::Pretty,
"json" => Self::Json,
_ => Self::Auto,
}
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[non_exhaustive]
pub enum Sink {
#[default]
Auto,
Stdout,
Stderr,
Journald,
}
impl Sink {
#[must_use]
pub fn from_env_value(value: &str) -> Self {
match value.trim().to_ascii_lowercase().as_str() {
"stdout" => Self::Stdout,
"stderr" => Self::Stderr,
"journald" => Self::Journald,
_ => Self::Auto,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct InitOptions {
pub(crate) service_name: Option<String>,
pub(crate) default_filter: Option<String>,
pub(crate) env_var: Option<String>,
pub(crate) format: Format,
pub(crate) sink: Sink,
pub(crate) idempotent: bool,
#[cfg(feature = "with-otlp")]
pub(crate) otlp: Option<crate::otlp::OtlpConfig>,
}
impl InitOptions {
#[must_use]
pub fn with_service_name(mut self, name: impl Into<String>) -> Self {
self.service_name = Some(name.into());
self
}
#[must_use]
pub fn with_default_filter(mut self, filter: impl Into<String>) -> Self {
self.default_filter = Some(filter.into());
self
}
#[must_use]
pub fn with_env_var(mut self, var: impl Into<String>) -> Self {
self.env_var = Some(var.into());
self
}
#[must_use]
pub fn with_format(mut self, format: Format) -> Self {
self.format = format;
self
}
#[must_use]
pub fn with_sink(mut self, sink: Sink) -> Self {
self.sink = sink;
self
}
#[must_use]
pub fn idempotent(mut self, enabled: bool) -> Self {
self.idempotent = enabled;
self
}
#[cfg(feature = "with-otlp")]
#[must_use]
pub fn with_otlp(mut self, config: crate::otlp::OtlpConfig) -> Self {
self.otlp = Some(config);
self
}
#[cfg(feature = "systemd")]
pub(crate) fn resolved_env_var(&self) -> &str {
self.env_var.as_deref().unwrap_or("RUST_LOG")
}
#[cfg(feature = "systemd")]
pub(crate) fn resolved_default_filter(&self) -> &str {
if let Some(filter) = self.default_filter.as_deref() {
return filter;
}
if cfg!(debug_assertions) { "debug" } else { "info" }
}
#[cfg(feature = "wasm32")]
pub(crate) fn resolved_default_filter(&self) -> &str {
if let Some(filter) = self.default_filter.as_deref() {
return filter;
}
if cfg!(debug_assertions) { "debug" } else { "info" }
}
#[cfg(feature = "wasm32")]
pub(crate) fn resolved_wasm_format(&self) -> Format {
match self.format {
Format::Auto => Format::Json,
format => format,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builder_sets_every_field() {
let opts = InitOptions::default()
.with_service_name("svc")
.with_default_filter("warn")
.with_env_var("KKP_LOG")
.with_format(Format::Json)
.with_sink(Sink::Stdout)
.idempotent(true);
assert_eq!(opts.service_name.as_deref(), Some("svc"));
assert_eq!(opts.default_filter.as_deref(), Some("warn"));
assert_eq!(opts.env_var.as_deref(), Some("KKP_LOG"));
assert_eq!(opts.format, Format::Json);
assert_eq!(opts.sink, Sink::Stdout);
assert!(opts.idempotent);
}
#[cfg(feature = "systemd")]
#[test]
fn resolved_helpers_apply_defaults_then_overrides() {
let default = InitOptions::default();
assert_eq!(default.resolved_env_var(), "RUST_LOG");
let expected = if cfg!(debug_assertions) { "debug" } else { "info" };
assert_eq!(default.resolved_default_filter(), expected);
let custom = InitOptions::default().with_env_var("KKP_LOG").with_default_filter("trace");
assert_eq!(custom.resolved_env_var(), "KKP_LOG");
assert_eq!(custom.resolved_default_filter(), "trace");
}
}