#![warn(missing_docs)]
use tracing::Subscriber;
use tracing_subscriber::{
fmt::format::FmtSpan,
registry::LookupSpan,
EnvFilter,
prelude::*,
};
use std::{str::FromStr, sync::Once};
use flames::{toml_path, FlameTimed};
use fmt::*;
mod flames;
mod fmt;
pub mod metrics;
mod open;
pub use open::{Config, Context, MsgWrap, OpenSpanExt};
pub use tracing;
#[derive(Debug, Clone)]
pub enum Output {
Compact,
Json,
JsonTimed,
Log,
LogTimed,
FlameTimed,
IceTimed,
OpenTel,
None,
}
pub type ParseError = String;
static INIT: Once = Once::new();
impl FromStr for Output {
type Err = ParseError;
fn from_str(day: &str) -> Result<Self, Self::Err> {
match day {
"Json" => Ok(Output::Json),
"JsonTimed" => Ok(Output::JsonTimed),
"IceTimed" => Ok(Output::IceTimed),
"Log" => Ok(Output::Log),
"LogTimed" => Ok(Output::LogTimed),
"FlameTimed" => Ok(Output::FlameTimed),
"Compact" => Ok(Output::Compact),
"OpenTel" => Ok(Output::OpenTel),
"None" => Ok(Output::None),
_ => Err("Could not parse log output type".into()),
}
}
}
pub fn test_run() -> Result<(), errors::TracingError> {
if std::env::var_os("RUST_LOG").is_none() {
return Ok(());
}
init_fmt(Output::Log)
}
pub fn test_run_open() -> Result<(), errors::TracingError> {
if std::env::var_os("RUST_LOG").is_none() {
return Ok(());
}
init_fmt(Output::OpenTel)
}
pub fn test_run_timed() -> Result<(), errors::TracingError> {
if std::env::var_os("RUST_LOG").is_none() {
return Ok(());
}
init_fmt(Output::LogTimed)
}
pub fn test_run_timed_json() -> Result<(), errors::TracingError> {
if std::env::var_os("RUST_LOG").is_none() {
return Ok(());
}
init_fmt(Output::JsonTimed)
}
pub fn test_run_timed_flame(path: Option<&str>) -> Result<Option<impl Drop>, errors::TracingError> {
if std::env::var_os("RUST_LOG").is_none() {
return Ok(None);
}
init_fmt(Output::FlameTimed)?;
Ok(path.and_then(|p| {
toml_path().map(|mut t| {
t.push(p);
FlameTimed::new(t)
})
}))
}
pub fn test_run_timed_ice(path: Option<&str>) -> Result<Option<impl Drop>, errors::TracingError> {
if std::env::var_os("RUST_LOG").is_none() {
return Ok(None);
}
init_fmt(Output::IceTimed)?;
Ok(path.and_then(|p| {
toml_path().map(|mut t| {
t.push(p);
FlameTimed::new(t)
})
}))
}
pub fn init_fmt(output: Output) -> Result<(), errors::TracingError> {
let mut filter = match std::env::var("RUST_LOG") {
Ok(_) => EnvFilter::from_default_env(),
Err(_) => EnvFilter::from_default_env().add_directive("[wasm_debug]=debug".parse()?),
};
if std::env::var("CUSTOM_FILTER").is_ok() {
EnvFilter::try_from_env("CUSTOM_FILTER")
.map_err(|e| eprintln!("Failed to parse CUSTOM_FILTER {:?}", e))
.map(|f| {
filter = f;
})
.ok();
}
match output {
Output::Json => {
let subscriber = tracing_subscriber::fmt()
.with_writer(std::io::stderr)
.with_target(true)
.json()
.with_env_filter(filter)
.finish();
finish(subscriber)
}
Output::JsonTimed => {
let subscriber = tracing_subscriber::fmt()
.with_writer(std::io::stderr)
.with_target(true)
.with_span_events(FmtSpan::CLOSE)
.json()
.with_env_filter(filter)
.finish();
finish(subscriber)
}
Output::Log => {
let subscriber = tracing_subscriber::fmt()
.with_writer(std::io::stderr)
.with_target(true)
.with_env_filter(filter)
.finish();
finish(subscriber)
}
Output::LogTimed => {
let subscriber = tracing_subscriber::fmt()
.with_writer(std::io::stderr)
.with_target(true)
.with_span_events(FmtSpan::CLOSE)
.with_env_filter(filter)
.finish();
finish(subscriber)
}
Output::FlameTimed => {
let subscriber = tracing_subscriber::fmt()
.with_writer(std::io::stderr)
.with_target(true)
.with_span_events(FmtSpan::CLOSE)
.with_env_filter(filter)
.finish();
finish(subscriber)
}
Output::IceTimed => {
let subscriber = tracing_subscriber::fmt()
.with_writer(std::io::stderr)
.with_target(true)
.with_span_events(FmtSpan::CLOSE)
.with_env_filter(filter)
.finish();
finish(subscriber)
}
Output::Compact => {
let subscriber = tracing_subscriber::fmt()
.with_writer(std::io::stderr)
.with_target(true)
.compact()
.with_env_filter(filter)
.finish();
finish(subscriber)
}
Output::OpenTel => {
let subscriber = tracing_subscriber::fmt()
.with_writer(std::io::stderr)
.with_target(true)
.with_env_filter(filter)
.finish();
finish(subscriber)
}
Output::None => Ok(()),
}
}
fn finish<S>(subscriber: S) -> Result<(), errors::TracingError>
where
S: Subscriber + Send + Sync + for<'span> LookupSpan<'span>,
{
let mut result = Ok(());
INIT.call_once(|| {
result = tracing::subscriber::set_global_default(subscriber).map_err(Into::into);
});
result
}
pub mod errors {
use thiserror::Error;
#[allow(missing_docs)] #[derive(Error, Debug)]
pub enum TracingError {
#[error(transparent)]
SetGlobal(#[from] tracing::subscriber::SetGlobalDefaultError),
#[error("Failed to setup tracing flame")]
TracingFlame,
#[error(transparent)]
BadDirective(#[from] tracing_subscriber::filter::ParseError),
}
}