pub mod format;
pub mod time;
pub mod writer;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use writer::Guard;
#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)]
pub struct Subscriber {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub format: Option<Format>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub writer: Option<Writer>,
}
#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum LevelFilter {
Error,
Warn,
#[default]
Info,
Debug,
Trace,
}
impl From<LevelFilter> for tracing_core::LevelFilter {
fn from(value: LevelFilter) -> Self {
match value {
LevelFilter::Error => Self::ERROR,
LevelFilter::Warn => Self::WARN,
LevelFilter::Info => Self::INFO,
LevelFilter::Debug => Self::DEBUG,
LevelFilter::Trace => Self::TRACE,
}
}
}
pub type SubscriberBuilder<
N = format::FormatFields,
E = format::FormatEvent,
F = tracing_core::LevelFilter,
W = writer::MakeWriter,
> = tracing_subscriber::fmt::SubscriberBuilder<N, E, F, W>;
pub type Layer<S, N = format::FormatFields, E = format::FormatEvent, W = writer::MakeWriter> =
tracing_subscriber::fmt::Layer<S, N, E, W>;
impl Subscriber {
fn into_components(
self,
defer: bool,
) -> Result<
(
writer::MakeWriter,
format::FormatFields,
format::FormatEvent,
Guard,
),
writer::Error,
> {
let Self { format, writer } = self;
let format = format.unwrap_or_default();
let writer = writer.unwrap_or_default();
let (writer, guard) = match defer {
true => writer::MakeWriter::try_new(writer)?,
false => writer::MakeWriter::new(writer),
};
let fields = format::FormatFields::from(format.formatter.clone().unwrap_or_default());
let event = format::FormatEvent::from(format);
Ok((writer, fields, event, guard))
}
pub fn layer<S>(self) -> (Layer<S>, Guard)
where
S: tracing_core::Subscriber + for<'s> tracing_subscriber::registry::LookupSpan<'s>,
{
let (writer, fields, event, guard) = self
.into_components(true)
.expect("errors have been deferred");
let layer = tracing_subscriber::fmt::layer()
.fmt_fields(fields)
.event_format(event)
.with_writer(writer);
(layer, guard)
}
pub fn try_layer<S>(self) -> Result<(Layer<S>, Guard), writer::Error>
where
S: tracing_core::Subscriber + for<'s> tracing_subscriber::registry::LookupSpan<'s>,
{
let (writer, fields, event, guard) = self.into_components(false)?;
let layer = tracing_subscriber::fmt::layer()
.fmt_fields(fields)
.event_format(event)
.with_writer(writer);
Ok((layer, guard))
}
pub fn builder(self) -> (SubscriberBuilder, Guard) {
let (writer, fields, event, guard) = self
.into_components(true)
.expect("errors have been deferred");
let builder = tracing_subscriber::fmt()
.fmt_fields(fields)
.event_format(event)
.with_writer(writer);
(builder, guard)
}
pub fn try_builder(self) -> Result<(SubscriberBuilder, Guard), writer::Error> {
let (writer, fields, event, guard) = self.into_components(false)?;
let builder = tracing_subscriber::fmt()
.fmt_fields(fields)
.event_format(event)
.with_writer(writer);
Ok((builder, guard))
}
}
#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)]
pub struct Format {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ansi: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub target: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub level: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub thread_ids: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub thread_names: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub file: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub line_number: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub formatter: Option<Formatter>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub timer: Option<Timer>,
}
#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Formatter {
#[default]
Full,
Compact,
Pretty,
Json(Option<Json>),
}
#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)]
pub struct Json {
#[serde(default, skip_serializing_if = "Option::is_none")]
flatten_event: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
current_span: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
span_list: Option<bool>,
}
#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Timer {
None,
Local(#[serde(default, skip_serializing_if = "Option::is_none")] Option<String>),
Utc(#[serde(default, skip_serializing_if = "Option::is_none")] Option<String>),
#[default]
System,
Uptime,
}
#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Writer {
Null,
#[default]
Stdout,
Stderr,
File {
path: PathBuf,
behaviour: FileOpenBehaviour,
#[serde(default, skip_serializing_if = "Option::is_none")]
non_blocking: Option<NonBlocking>,
},
Rolling {
directory: PathBuf,
rolling: Option<Rolling>,
#[serde(default, skip_serializing_if = "Option::is_none")]
non_blocking: Option<NonBlocking>,
},
}
#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Rotation {
Minutely,
Hourly,
Daily,
#[default]
Never,
}
#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)]
pub struct Rolling {
#[serde(default, skip_serializing_if = "Option::is_none")]
limit: Option<usize>,
#[serde(default, skip_serializing_if = "Option::is_none")]
prefix: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
suffix: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
rotation: Option<Rotation>,
}
#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum BackpressureBehaviour {
Drop,
Block,
}
#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum FileOpenBehaviour {
Truncate,
Append,
}
#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub struct NonBlocking {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub buffer_length: Option<usize>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub behaviour: Option<BackpressureBehaviour>,
}