#[cfg(feature = "logging")]
use tracing::Level;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum LogFormat {
#[default]
Json,
Pretty,
Compact,
}
#[cfg(feature = "logging")]
#[derive(Debug, Clone)]
pub struct LoggingBuilder {
level: Level,
format: LogFormat,
target: Option<&'static str>,
with_file: bool,
with_line_number: bool,
with_thread_ids: bool,
with_thread_names: bool,
}
#[cfg(feature = "logging")]
impl Default for LoggingBuilder {
fn default() -> Self {
Self {
level: Level::DEBUG,
format: LogFormat::Json,
target: None,
with_file: false,
with_line_number: false,
with_thread_ids: false,
with_thread_names: false,
}
}
}
#[cfg(feature = "logging")]
impl LoggingBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn with_level(mut self, level: Level) -> Self {
self.level = level;
self
}
pub fn trace(mut self) -> Self {
self.level = Level::TRACE;
self
}
pub fn debug(mut self) -> Self {
self.level = Level::DEBUG;
self
}
pub fn info(mut self) -> Self {
self.level = Level::INFO;
self
}
pub fn warn(mut self) -> Self {
self.level = Level::WARN;
self
}
pub fn error(mut self) -> Self {
self.level = Level::ERROR;
self
}
pub fn with_target_filter(mut self, target: &'static str) -> Self {
self.target = Some(target);
self
}
pub fn di_only(self) -> Self {
self.with_target_filter("dependency_injector")
}
pub fn with_file(mut self) -> Self {
self.with_file = true;
self
}
pub fn with_line_number(mut self) -> Self {
self.with_line_number = true;
self
}
pub fn with_thread_ids(mut self) -> Self {
self.with_thread_ids = true;
self
}
pub fn with_thread_names(mut self) -> Self {
self.with_thread_names = true;
self
}
pub fn json(mut self) -> Self {
self.format = LogFormat::Json;
self
}
pub fn pretty(mut self) -> Self {
self.format = LogFormat::Pretty;
self
}
pub fn compact(mut self) -> Self {
self.format = LogFormat::Compact;
self
}
#[cfg(any(feature = "logging-json", feature = "logging-pretty"))]
pub fn init(self) {
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
let filter = if let Some(target) = self.target {
EnvFilter::new(format!("{}={}", target, self.level))
} else {
EnvFilter::new(self.level.to_string())
};
match self.format {
LogFormat::Json => {
#[cfg(feature = "logging-json")]
{
let subscriber = fmt::layer()
.json()
.with_file(self.with_file)
.with_line_number(self.with_line_number)
.with_thread_ids(self.with_thread_ids)
.with_thread_names(self.with_thread_names)
.with_target(true);
tracing_subscriber::registry()
.with(filter)
.with(subscriber)
.init();
}
#[cfg(not(feature = "logging-json"))]
{
let subscriber = fmt::layer()
.with_file(self.with_file)
.with_line_number(self.with_line_number)
.with_thread_ids(self.with_thread_ids)
.with_thread_names(self.with_thread_names)
.with_target(true);
tracing_subscriber::registry()
.with(filter)
.with(subscriber)
.init();
}
}
LogFormat::Pretty => {
let subscriber = fmt::layer()
.pretty()
.with_file(self.with_file)
.with_line_number(self.with_line_number)
.with_thread_ids(self.with_thread_ids)
.with_thread_names(self.with_thread_names)
.with_target(true);
tracing_subscriber::registry()
.with(filter)
.with(subscriber)
.init();
}
LogFormat::Compact => {
let subscriber = fmt::layer()
.compact()
.with_file(self.with_file)
.with_line_number(self.with_line_number)
.with_thread_ids(self.with_thread_ids)
.with_thread_names(self.with_thread_names)
.with_target(true);
tracing_subscriber::registry()
.with(filter)
.with(subscriber)
.init();
}
}
}
#[cfg(not(any(feature = "logging-json", feature = "logging-pretty")))]
pub fn init(self) {
}
}
#[cfg(feature = "logging")]
pub fn builder() -> LoggingBuilder {
LoggingBuilder::new()
}
#[cfg(any(feature = "logging-json", feature = "logging-pretty"))]
pub fn init() {
#[cfg(feature = "logging-json")]
{
init_json();
}
#[cfg(all(feature = "logging-pretty", not(feature = "logging-json")))]
{
init_pretty();
}
}
#[cfg(not(any(feature = "logging-json", feature = "logging-pretty")))]
pub fn init() {
}
#[cfg(any(feature = "logging-json", feature = "logging-pretty"))]
pub fn init_json() {
builder().json().debug().init();
}
#[cfg(not(any(feature = "logging-json", feature = "logging-pretty")))]
pub fn init_json() {
}
#[cfg(any(feature = "logging-json", feature = "logging-pretty"))]
pub fn init_pretty() {
builder().pretty().debug().init();
}
#[cfg(not(any(feature = "logging-json", feature = "logging-pretty")))]
pub fn init_pretty() {
}
#[cfg(any(feature = "logging-json", feature = "logging-pretty"))]
pub fn init_di_only() {
builder().di_only().debug().init();
}
#[cfg(not(any(feature = "logging-json", feature = "logging-pretty")))]
pub fn init_di_only() {
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_builder_defaults() {
let builder = LoggingBuilder::default();
assert_eq!(builder.level, Level::DEBUG);
assert_eq!(builder.format, LogFormat::Json);
assert!(builder.target.is_none());
}
#[test]
fn test_builder_chain() {
let builder = LoggingBuilder::new()
.trace()
.pretty()
.with_file()
.with_line_number()
.di_only();
assert_eq!(builder.level, Level::TRACE);
assert_eq!(builder.format, LogFormat::Pretty);
assert!(builder.with_file);
assert!(builder.with_line_number);
assert_eq!(builder.target, Some("dependency_injector"));
}
}