use clap::ValueEnum;
use console::Color::{Green, Magenta, White, Yellow};
use console::Style;
use std::fmt::Debug;
use tracing::field::{Field, Visit};
use tracing::span::Attributes;
use tracing::{Event, Subscriber};
use tracing::{Id, Level};
use tracing_subscriber::fmt::format::Writer;
use tracing_subscriber::fmt::{FmtContext, FormatEvent, FormatFields};
use tracing_subscriber::layer::Context;
use tracing_subscriber::registry::LookupSpan;
use tracing_subscriber::Layer;
pub struct OrandaFormatter;
pub struct CaptureFieldsLayer;
#[derive(Default, Clone)]
struct SpanVisitor {
pub prefix: Option<String>,
}
#[derive(Default)]
struct EventVisitor {
pub message: String,
pub success: bool,
}
struct SpanFieldStorage(SpanVisitor);
impl<S> Layer<S> for CaptureFieldsLayer
where
S: Subscriber,
S: for<'lookup> LookupSpan<'lookup>,
{
fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
let mut visitor = SpanVisitor::default();
attrs.record(&mut visitor);
let storage = SpanFieldStorage(visitor);
let span = ctx.span(id).unwrap();
if span.name() == "workspace_page" {
let mut extensions = span.extensions_mut();
extensions.insert::<SpanFieldStorage>(storage);
}
}
}
impl<S, N> FormatEvent<S, N> for OrandaFormatter
where
S: Subscriber + for<'a> LookupSpan<'a>,
N: for<'a> FormatFields<'a> + 'static,
{
fn format_event(
&self,
ctx: &FmtContext<'_, S, N>,
mut writer: Writer<'_>,
event: &Event<'_>,
) -> std::fmt::Result {
let warn_icon = Style::new().bold().fg(Yellow).apply_to("⚠");
let check_icon = Style::new().bold().fg(Green).apply_to("✓");
let arrow_icon = Style::new().bold().fg(White).apply_to("↪");
let mut message = EventVisitor::default();
let metadata = event.metadata();
event.record(&mut message);
if metadata.fields().field("message").is_some() {
let output_str = if message.success {
let style = Style::new().bold().fg(Green);
format!(
"{} >o_o< SUCCESS: {}",
check_icon,
style.apply_to(message.message)
)
} else if matches!(metadata.level(), &Level::INFO) {
let style = Style::new().bold().fg(White);
format!(
"{} >o_o< INFO: {}",
arrow_icon,
style.apply_to(message.message)
)
} else if matches!(metadata.level(), &Level::WARN) {
let style = Style::new().bold().fg(Yellow);
format!(
"{} >o_o< WARNING: {}",
warn_icon,
style.apply_to(message.message)
)
} else if matches!(metadata.level(), &Level::DEBUG) {
let style = Style::new().bold().fg(Magenta);
format!(
"{} >o_o< DEBUG: {}",
arrow_icon,
style.apply_to(message.message)
)
} else {
format!("TRACE: {}", message.message)
};
let fields = if let Some(span) = ctx.lookup_current() {
let extensions = span.extensions();
if let Some(storage) = extensions.get::<SpanFieldStorage>() {
let field_data = storage.0.clone();
Some(field_data)
} else {
None
}
} else {
None
};
if let Some(fields) = fields {
if let Some(prefix) = fields.prefix {
write!(
&mut writer,
"{:>15} {}",
console::style(prefix).magenta(),
output_str
)?;
} else {
write!(&mut writer, "{}", output_str)?;
}
} else {
write!(&mut writer, "{}", output_str)?;
}
}
writeln!(writer)
}
}
impl Visit for EventVisitor {
fn record_debug(&mut self, field: &Field, value: &dyn Debug) {
if field.name() == "message" {
self.message = format!("{:?}", value);
}
if field.name() == "success" {
self.success = true;
}
}
}
impl Visit for SpanVisitor {
fn record_str(&mut self, field: &Field, value: &str) {
if field.name() == "prefix" {
self.prefix = Some(value.to_string());
}
}
fn record_debug(&mut self, _field: &Field, _value: &dyn Debug) {}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
pub enum OutputFormat {
Human,
Json,
}