pub mod layer;
pub mod prelude;
pub use tracing;
pub use tracing_subscriber;
use std::fs;
use std::path::{Path, PathBuf};
use tracing_subscriber::layer::Layered;
use tracing_subscriber::layer::SubscriberExt as _;
use tracing_subscriber::{
fmt::{
self,
format::{DefaultFields, Format, Full},
},
registry::LookupSpan,
};
#[deprecated(
since = "0.1.2",
note = "This function is deprecated. Use `ts_init::builder()` instead."
)]
pub fn init_logging<S: AsRef<str>>(outputs: Vec<Option<String>>, env: S) {
use tracing::subscriber::set_global_default;
use tracing_subscriber::{layer::SubscriberExt, *};
let default_env = env.as_ref();
fn file_appender(path: impl AsRef<str>) -> std::fs::File {
std::fs::File::options()
.append(true)
.create(true)
.open(path.as_ref())
.unwrap_or_else(|e| panic!("{:?}: {}", path.as_ref(), e))
}
let t = tracing_subscriber::fmt()
.with_env_filter(
EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::builder().parse(default_env).unwrap()),
)
.with_writer(std::io::stderr);
match outputs.len() {
0 => set_global_default(t.finish()),
1 => match outputs[0].as_ref() {
None => set_global_default(t.finish()),
Some(p) => match p.as_str() {
"journald" => {
set_global_default(Registry::default().with(tracing_journald::layer().unwrap()))
}
_ => set_global_default(t.with_writer(file_appender(p)).with_ansi(false).finish()),
},
},
2 => match (outputs[0].as_ref(), outputs[1].as_ref()) {
(None, Some(p)) => match p.as_str() {
"journald" => {
set_global_default(t.finish().with(tracing_journald::layer().unwrap()))
}
_ => set_global_default(
t.finish().with(
fmt::Layer::default()
.with_writer(file_appender(p))
.with_ansi(false),
),
),
},
_ => panic!("Invalid output"),
},
_ => panic!("Too many outputs"),
}
.unwrap();
}
pub fn builder() -> tracing_subscriber::fmt::SubscriberBuilder<
DefaultFields,
Format<Full>,
tracing_subscriber::filter::LevelFilter,
fn() -> std::io::Stderr,
> {
tracing_subscriber::fmt().with_writer(std::io::stderr)
}
pub fn subscriber() -> tracing_subscriber::fmt::Subscriber<
DefaultFields,
Format<Full>,
tracing_subscriber::filter::LevelFilter,
fn() -> std::io::Stderr,
> {
builder().finish()
}
pub fn try_init<S: AsRef<str>>(
default_env: S,
) -> Result<(), tracing_subscriber::util::TryInitError> {
use tracing_subscriber::util::SubscriberInitExt;
builder()
.finish()
.with_env_filter_or(default_env.as_ref())
.try_init()
}
pub fn init<S: AsRef<str>>(default_env: S) {
try_init(default_env).expect("Failed to initialize logging")
}
#[derive(Clone)]
pub struct FileMakeWriter {
path: PathBuf,
}
impl FileMakeWriter {
fn new<P: AsRef<Path>>(path: P) -> Self {
Self {
path: path.as_ref().into(),
}
}
}
impl<'a> tracing_subscriber::fmt::MakeWriter<'a> for FileMakeWriter {
type Writer = fs::File;
fn make_writer(&'a self) -> Self::Writer {
fs::OpenOptions::new()
.create(true)
.append(true)
.open(&self.path)
.expect("unable to open log file")
}
}
pub trait TiSubscriberExt: tracing_core::subscriber::Subscriber {
fn with_env_filter_or<S: AsRef<str>>(
self,
default_env: S,
) -> Layered<tracing_subscriber::EnvFilter, Self>
where
Self: Sized,
{
self.with(layer::env_filter_with_default(default_env))
}
fn with_file<P>(
self,
path: P,
) -> Layered<fmt::Layer<Self, DefaultFields, Format<Full>, FileMakeWriter>, Self>
where
Self: Sized,
for<'span> Self: LookupSpan<'span>,
P: AsRef<Path>,
{
let path_buf = path.as_ref().to_owned();
self.with(
fmt::layer()
.with_ansi(false)
.with_writer(FileMakeWriter::new(path_buf)),
)
}
fn with_journald(self) -> Layered<tracing_journald::Layer, Self>
where
Self: Sized,
for<'span> Self: tracing_subscriber::registry::LookupSpan<'span>,
{
self.with(tracing_journald::layer().unwrap())
}
}
impl<S: tracing_core::subscriber::Subscriber> TiSubscriberExt for S {}
pub use ts_init_macros::env_filter_directive;
#[deprecated(
since = "0.2.0",
note = "The `crate_env!` macro has been renamed to `env_filter_directive!`. Please update your usage."
)]
#[macro_export]
macro_rules! crate_env {
($env:expr) => {
$crate::generate_log_env!($env)
};
}