use std::io;
use std::path::PathBuf;
use tracing_subscriber::fmt;
use tracing_subscriber::prelude::*;
use tracing_subscriber::EnvFilter;
#[non_exhaustive]
#[derive(Debug, Default)]
pub struct TracingBuilder {
env_filter: Option<String>,
json_file: Option<PathBuf>,
}
impl TracingBuilder {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn with_filter(mut self, directives: impl Into<String>) -> Self {
self.env_filter = Some(directives.into());
self
}
#[must_use]
pub fn with_json_file(mut self, path: impl Into<PathBuf>) -> Self {
self.json_file = Some(path.into());
self
}
pub fn install(self) -> Result<(), TracingError> {
let env_filter = match self.env_filter {
Some(directives) => {
EnvFilter::try_new(directives).map_err(|e| TracingError::Filter(e.to_string()))?
}
None => EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
};
let stderr_layer = fmt::layer().with_writer(io::stderr);
let registry = tracing_subscriber::registry()
.with(env_filter)
.with(stderr_layer);
if let Some(path) = self.json_file {
let file = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(&path)
.map_err(TracingError::OpenFile)?;
let json_layer = fmt::layer().json().with_writer(file);
registry
.with(json_layer)
.try_init()
.map_err(|e| TracingError::Init(e.to_string()))
} else {
registry
.try_init()
.map_err(|e| TracingError::Init(e.to_string()))
}
}
}
#[non_exhaustive]
#[derive(Debug, thiserror::Error)]
pub enum TracingError {
#[error("invalid filter directives: {0}")]
Filter(String),
#[error("could not open tracing JSON file: {0}")]
OpenFile(#[source] io::Error),
#[error("could not install tracing subscriber: {0}")]
Init(String),
}