summaryrefslogtreecommitdiffstats
path: root/vendor/tracing-tree/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /vendor/tracing-tree/src
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/tracing-tree/src')
-rw-r--r--vendor/tracing-tree/src/format.rs425
-rw-r--r--vendor/tracing-tree/src/lib.rs395
2 files changed, 820 insertions, 0 deletions
diff --git a/vendor/tracing-tree/src/format.rs b/vendor/tracing-tree/src/format.rs
new file mode 100644
index 000000000..067ea9771
--- /dev/null
+++ b/vendor/tracing-tree/src/format.rs
@@ -0,0 +1,425 @@
+use ansi_term::Color;
+use std::{
+ fmt::{self, Write as _},
+ io,
+};
+use tracing_core::{
+ field::{Field, Visit},
+ Level,
+};
+
+pub(crate) const LINE_VERT: &str = "│";
+const LINE_HORIZ: &str = "─";
+pub(crate) const LINE_BRANCH: &str = "├";
+pub(crate) const LINE_CLOSE: &str = "┘";
+pub(crate) const LINE_OPEN: &str = "┐";
+
+#[derive(Copy, Clone)]
+pub(crate) enum SpanMode {
+ PreOpen,
+ Open { verbose: bool },
+ Close { verbose: bool },
+ PostClose,
+ Event,
+}
+
+#[derive(Debug)]
+pub struct Config {
+ /// Whether to use colors.
+ pub ansi: bool,
+ /// Whether an ascii art tree is used or (if false) whether to just use whitespace indent
+ pub indent_lines: bool,
+ /// The amount of chars to indent.
+ pub indent_amount: usize,
+ /// Whether to show the module paths.
+ pub targets: bool,
+ /// Whether to show thread ids.
+ pub render_thread_ids: bool,
+ /// Whether to show thread names.
+ pub render_thread_names: bool,
+ /// Specifies after how many indentation levels we will wrap back around to zero
+ pub wraparound: usize,
+ /// Whether to print the current span before activating a new one
+ pub verbose_entry: bool,
+ /// Whether to print the current span before exiting it.
+ pub verbose_exit: bool,
+ /// Whether to print squiggly brackets (`{}`) around the list of fields in a span.
+ pub bracketed_fields: bool,
+}
+
+impl Config {
+ pub fn with_ansi(self, ansi: bool) -> Self {
+ Self { ansi, ..self }
+ }
+
+ pub fn with_indent_lines(self, indent_lines: bool) -> Self {
+ Self {
+ indent_lines,
+ ..self
+ }
+ }
+
+ pub fn with_targets(self, targets: bool) -> Self {
+ Self { targets, ..self }
+ }
+
+ pub fn with_thread_ids(self, render_thread_ids: bool) -> Self {
+ Self {
+ render_thread_ids,
+ ..self
+ }
+ }
+
+ pub fn with_thread_names(self, render_thread_names: bool) -> Self {
+ Self {
+ render_thread_names,
+ ..self
+ }
+ }
+
+ pub fn with_wraparound(self, wraparound: usize) -> Self {
+ Self { wraparound, ..self }
+ }
+
+ pub fn with_verbose_entry(self, verbose_entry: bool) -> Self {
+ Self {
+ verbose_entry,
+ ..self
+ }
+ }
+
+ pub fn with_verbose_exit(self, verbose_exit: bool) -> Self {
+ Self {
+ verbose_exit,
+ ..self
+ }
+ }
+
+ pub fn with_bracketed_fields(self, bracketed_fields: bool) -> Self {
+ Self {
+ bracketed_fields,
+ ..self
+ }
+ }
+
+ pub(crate) fn prefix(&self) -> String {
+ let mut buf = String::new();
+ if self.render_thread_ids {
+ write!(buf, "{:?}", std::thread::current().id()).unwrap();
+ if buf.ends_with(')') {
+ buf.truncate(buf.len() - 1);
+ }
+ if buf.starts_with("ThreadId(") {
+ buf.drain(0.."ThreadId(".len());
+ }
+ }
+ if self.render_thread_names {
+ if let Some(name) = std::thread::current().name() {
+ if self.render_thread_ids {
+ buf.push(':');
+ }
+ buf.push_str(name);
+ }
+ }
+ buf
+ }
+}
+
+impl Default for Config {
+ fn default() -> Self {
+ Self {
+ ansi: true,
+ indent_lines: false,
+ indent_amount: 2,
+ targets: false,
+ render_thread_ids: false,
+ render_thread_names: false,
+ wraparound: usize::max_value(),
+ verbose_entry: false,
+ verbose_exit: false,
+ bracketed_fields: false,
+ }
+ }
+}
+
+#[derive(Debug)]
+pub struct Buffers {
+ pub current_buf: String,
+ pub indent_buf: String,
+}
+
+impl Buffers {
+ pub fn new() -> Self {
+ Self {
+ current_buf: String::new(),
+ indent_buf: String::new(),
+ }
+ }
+
+ pub fn flush_current_buf(&mut self, mut writer: impl io::Write) {
+ write!(writer, "{}", &self.current_buf).unwrap();
+ self.current_buf.clear();
+ }
+
+ pub fn flush_indent_buf(&mut self) {
+ self.current_buf.push_str(&self.indent_buf);
+ self.indent_buf.clear();
+ }
+
+ pub(crate) fn indent_current(&mut self, indent: usize, config: &Config, style: SpanMode) {
+ self.current_buf.push('\n');
+ let prefix = config.prefix();
+
+ // Render something when wraparound occurs so the user is aware of it
+ if config.indent_lines {
+ match style {
+ SpanMode::Close { .. } | SpanMode::PostClose => {
+ if indent > 0 && (indent + 1) % config.wraparound == 0 {
+ self.indent_buf.push_str(&prefix);
+ for _ in 0..(indent % config.wraparound * config.indent_amount) {
+ self.indent_buf.push_str(LINE_HORIZ);
+ }
+ self.indent_buf.push_str(LINE_OPEN);
+ self.indent_buf.push('\n');
+ }
+ }
+ _ => {}
+ }
+ }
+
+ indent_block(
+ &mut self.current_buf,
+ &mut self.indent_buf,
+ indent % config.wraparound,
+ config.indent_amount,
+ config.indent_lines,
+ &prefix,
+ style,
+ );
+ self.current_buf.clear();
+ self.flush_indent_buf();
+
+ // Render something when wraparound occurs so the user is aware of it
+ if config.indent_lines {
+ match style {
+ SpanMode::PreOpen | SpanMode::Open { .. } => {
+ if indent > 0 && (indent + 1) % config.wraparound == 0 {
+ self.current_buf.push_str(&prefix);
+ for _ in 0..(indent % config.wraparound * config.indent_amount) {
+ self.current_buf.push_str(LINE_HORIZ);
+ }
+ self.current_buf.push_str(LINE_CLOSE);
+ self.current_buf.push('\n');
+ }
+ }
+ _ => {}
+ }
+ }
+ }
+}
+
+pub struct FmtEvent<'a> {
+ pub bufs: &'a mut Buffers,
+ pub comma: bool,
+}
+
+impl<'a> Visit for FmtEvent<'a> {
+ fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
+ let buf = &mut self.bufs.current_buf;
+ let comma = if self.comma { "," } else { "" };
+ match field.name() {
+ "message" => {
+ write!(buf, "{} {:?}", comma, value).unwrap();
+ self.comma = true;
+ }
+ // Skip fields that are actually log metadata that have already been handled
+ #[cfg(feature = "tracing-log")]
+ name if name.starts_with("log.") => {}
+ name => {
+ write!(buf, "{} {}={:?}", comma, name, value).unwrap();
+ self.comma = true;
+ }
+ }
+ }
+}
+
+pub struct ColorLevel<'a>(pub &'a Level);
+
+impl<'a> fmt::Display for ColorLevel<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self.0 {
+ Level::TRACE => Color::Purple.bold().paint("TRACE"),
+ Level::DEBUG => Color::Blue.bold().paint("DEBUG"),
+ Level::INFO => Color::Green.bold().paint(" INFO"),
+ Level::WARN => Color::RGB(252, 234, 160).bold().paint(" WARN"), // orange
+ Level::ERROR => Color::Red.bold().paint("ERROR"),
+ }
+ .fmt(f)
+ }
+}
+
+fn indent_block_with_lines(
+ lines: &[&str],
+ buf: &mut String,
+ indent: usize,
+ indent_amount: usize,
+ prefix: &str,
+ style: SpanMode,
+) {
+ let indent_spaces = indent * indent_amount;
+ if lines.is_empty() {
+ return;
+ } else if indent_spaces == 0 {
+ for line in lines {
+ buf.push_str(prefix);
+ // The first indent is special, we only need to print open/close and nothing else
+ if indent == 0 {
+ match style {
+ SpanMode::Open { .. } => buf.push_str(LINE_OPEN),
+ SpanMode::Close { .. } => buf.push_str(LINE_CLOSE),
+ SpanMode::PreOpen | SpanMode::PostClose => {}
+ SpanMode::Event => {}
+ }
+ }
+ buf.push_str(line);
+ buf.push('\n');
+ }
+ return;
+ }
+ let mut s = String::with_capacity(indent_spaces + prefix.len());
+ s.push_str(prefix);
+
+ // instead of using all spaces to indent, draw a vertical line at every indent level
+ // up until the last indent
+ for i in 0..(indent_spaces - indent_amount) {
+ if i % indent_amount == 0 {
+ s.push_str(LINE_VERT);
+ } else {
+ s.push(' ');
+ }
+ }
+
+ // draw branch
+ buf.push_str(&s);
+
+ match style {
+ SpanMode::PreOpen => {
+ buf.push_str(LINE_BRANCH);
+ for _ in 1..(indent_amount / 2) {
+ buf.push_str(LINE_HORIZ);
+ }
+ buf.push_str(LINE_OPEN);
+ }
+ SpanMode::Open { verbose: false } => {
+ buf.push_str(LINE_BRANCH);
+ for _ in 1..indent_amount {
+ buf.push_str(LINE_HORIZ);
+ }
+ buf.push_str(LINE_OPEN);
+ }
+ SpanMode::Open { verbose: true } => {
+ buf.push_str(LINE_VERT);
+ for _ in 1..(indent_amount / 2) {
+ buf.push(' ');
+ }
+ // We don't have the space for fancy rendering at single space indent.
+ if indent_amount > 1 {
+ buf.push('└');
+ }
+ for _ in (indent_amount / 2)..(indent_amount - 1) {
+ buf.push_str(LINE_HORIZ);
+ }
+ // We don't have the space for fancy rendering at single space indent.
+ if indent_amount > 1 {
+ buf.push_str(LINE_OPEN);
+ } else {
+ buf.push_str(LINE_VERT);
+ }
+ }
+ SpanMode::Close { verbose: false } => {
+ buf.push_str(LINE_BRANCH);
+ for _ in 1..indent_amount {
+ buf.push_str(LINE_HORIZ);
+ }
+ buf.push_str(LINE_CLOSE);
+ }
+ SpanMode::Close { verbose: true } => {
+ buf.push_str(LINE_VERT);
+ for _ in 1..(indent_amount / 2) {
+ buf.push(' ');
+ }
+ // We don't have the space for fancy rendering at single space indent.
+ if indent_amount > 1 {
+ buf.push('┌');
+ }
+ for _ in (indent_amount / 2)..(indent_amount - 1) {
+ buf.push_str(LINE_HORIZ);
+ }
+ // We don't have the space for fancy rendering at single space indent.
+ if indent_amount > 1 {
+ buf.push_str(LINE_CLOSE);
+ } else {
+ buf.push_str(LINE_VERT);
+ }
+ }
+ SpanMode::PostClose => {
+ buf.push_str(LINE_BRANCH);
+ for _ in 1..(indent_amount / 2) {
+ buf.push_str(LINE_HORIZ);
+ }
+ buf.push_str(LINE_CLOSE);
+ }
+ SpanMode::Event => {
+ buf.push_str(LINE_BRANCH);
+
+ // add `indent_amount - 1` horizontal lines before the span/event
+ for _ in 0..(indent_amount - 1) {
+ buf.push_str(LINE_HORIZ);
+ }
+ }
+ }
+ buf.push_str(lines[0]);
+ buf.push('\n');
+
+ // add the rest of the indentation, since we don't want to draw horizontal lines
+ // for subsequent lines
+ for i in 0..indent_amount {
+ if i % indent_amount == 0 {
+ s.push_str(LINE_VERT);
+ } else {
+ s.push(' ');
+ }
+ }
+
+ // add all of the actual content, with each line preceded by the indent string
+ for line in &lines[1..] {
+ buf.push_str(&s);
+ buf.push_str(line);
+ buf.push('\n');
+ }
+}
+
+fn indent_block(
+ block: &mut String,
+ buf: &mut String,
+ indent: usize,
+ indent_amount: usize,
+ indent_lines: bool,
+ prefix: &str,
+ style: SpanMode,
+) {
+ let lines: Vec<&str> = block.lines().collect();
+ let indent_spaces = indent * indent_amount;
+ buf.reserve(block.len() + (lines.len() * indent_spaces));
+ if indent_lines {
+ indent_block_with_lines(&lines, buf, indent, indent_amount, prefix, style);
+ } else {
+ let indent_str = String::from(" ").repeat(indent_spaces);
+ for line in lines {
+ buf.push_str(prefix);
+ buf.push_str(&indent_str);
+ buf.push_str(line);
+ buf.push('\n');
+ }
+ }
+}
diff --git a/vendor/tracing-tree/src/lib.rs b/vendor/tracing-tree/src/lib.rs
new file mode 100644
index 000000000..dbacaa57e
--- /dev/null
+++ b/vendor/tracing-tree/src/lib.rs
@@ -0,0 +1,395 @@
+pub(crate) mod format;
+
+use ansi_term::{Color, Style};
+use format::{Buffers, ColorLevel, Config, FmtEvent, SpanMode};
+use std::{
+ fmt::{self, Write as _},
+ io,
+ sync::Mutex,
+ time::Instant,
+};
+use tracing_core::{
+ field::{Field, Visit},
+ span::{Attributes, Id},
+ Event, Subscriber,
+};
+#[cfg(feature = "tracing-log")]
+use tracing_log::NormalizeEvent;
+use tracing_subscriber::{
+ fmt::MakeWriter,
+ layer::{Context, Layer},
+ registry::{self, LookupSpan},
+};
+
+pub(crate) struct Data {
+ start: Instant,
+ kvs: Vec<(&'static str, String)>,
+}
+
+impl Data {
+ pub fn new(attrs: &Attributes<'_>) -> Self {
+ let mut span = Self {
+ start: Instant::now(),
+ kvs: Vec::new(),
+ };
+ attrs.record(&mut span);
+ span
+ }
+}
+
+impl Visit for Data {
+ fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
+ self.kvs.push((field.name(), format!("{:?}", value)))
+ }
+}
+#[derive(Debug)]
+pub struct HierarchicalLayer<W = fn() -> io::Stderr>
+where
+ W: for<'writer> MakeWriter<'writer> + 'static,
+{
+ make_writer: W,
+ bufs: Mutex<Buffers>,
+ config: Config,
+}
+
+impl Default for HierarchicalLayer {
+ fn default() -> Self {
+ Self::new(2)
+ }
+}
+
+impl HierarchicalLayer<fn() -> io::Stderr> {
+ pub fn new(indent_amount: usize) -> Self {
+ let ansi = atty::is(atty::Stream::Stderr);
+ let config = Config {
+ ansi,
+ indent_amount,
+ ..Default::default()
+ };
+ Self {
+ make_writer: io::stderr,
+ bufs: Mutex::new(Buffers::new()),
+ config,
+ }
+ }
+}
+
+impl<W> HierarchicalLayer<W>
+where
+ W: for<'writer> MakeWriter<'writer> + 'static,
+{
+ /// Enables terminal colors, boldness and italics.
+ pub fn with_ansi(self, ansi: bool) -> Self {
+ Self {
+ config: self.config.with_ansi(ansi),
+ ..self
+ }
+ }
+
+ pub fn with_writer<W2>(self, make_writer: W2) -> HierarchicalLayer<W2>
+ where
+ W2: for<'writer> MakeWriter<'writer>,
+ {
+ HierarchicalLayer {
+ make_writer,
+ config: self.config,
+ bufs: self.bufs,
+ }
+ }
+
+ pub fn with_indent_amount(self, indent_amount: usize) -> Self {
+ let config = Config {
+ indent_amount,
+ ..self.config
+ };
+ Self { config, ..self }
+ }
+
+ /// Renders an ascii art tree instead of just using whitespace indentation.
+ pub fn with_indent_lines(self, indent_lines: bool) -> Self {
+ Self {
+ config: self.config.with_indent_lines(indent_lines),
+ ..self
+ }
+ }
+
+ /// Whether to render the event and span targets. Usually targets are the module path to the
+ /// event/span macro invocation.
+ pub fn with_targets(self, targets: bool) -> Self {
+ Self {
+ config: self.config.with_targets(targets),
+ ..self
+ }
+ }
+
+ /// Whether to render the thread id in the beginning of every line. This is helpful to
+ /// untangle the tracing statements emitted by each thread.
+ pub fn with_thread_ids(self, thread_ids: bool) -> Self {
+ Self {
+ config: self.config.with_thread_ids(thread_ids),
+ ..self
+ }
+ }
+
+ /// Whether to render the thread name in the beginning of every line. Not all threads have
+ /// names, but if they do, this may be more helpful than the generic thread ids.
+ pub fn with_thread_names(self, thread_names: bool) -> Self {
+ Self {
+ config: self.config.with_thread_names(thread_names),
+ ..self
+ }
+ }
+
+ /// Resets the indentation to zero after `wraparound` indentation levels.
+ /// This is helpful if you expect very deeply nested spans as otherwise the indentation
+ /// just runs out of your screen.
+ pub fn with_wraparound(self, wraparound: usize) -> Self {
+ Self {
+ config: self.config.with_wraparound(wraparound),
+ ..self
+ }
+ }
+
+ /// Whether to print the currently active span's message again before entering a new span.
+ /// This helps if the entry to the current span was quite a while back (and with scrolling
+ /// upwards in logs).
+ pub fn with_verbose_entry(self, verbose_entry: bool) -> Self {
+ Self {
+ config: self.config.with_verbose_entry(verbose_entry),
+ ..self
+ }
+ }
+
+ /// Whether to print the currently active span's message again before dropping it.
+ /// This helps if the entry to the current span was quite a while back (and with scrolling
+ /// upwards in logs).
+ pub fn with_verbose_exit(self, verbose_exit: bool) -> Self {
+ Self {
+ config: self.config.with_verbose_exit(verbose_exit),
+ ..self
+ }
+ }
+
+ /// Whether to print `{}` around the fields when printing a span.
+ /// This can help visually distinguish fields from the rest of the message.
+ pub fn with_bracketed_fields(self, bracketed_fields: bool) -> Self {
+ Self {
+ config: self.config.with_bracketed_fields(bracketed_fields),
+ ..self
+ }
+ }
+
+ fn styled(&self, style: Style, text: impl AsRef<str>) -> String {
+ if self.config.ansi {
+ style.paint(text.as_ref()).to_string()
+ } else {
+ text.as_ref().to_string()
+ }
+ }
+
+ fn print_kvs<'a, I, V>(&self, buf: &mut impl fmt::Write, kvs: I) -> fmt::Result
+ where
+ I: IntoIterator<Item = (&'a str, V)>,
+ V: fmt::Display + 'a,
+ {
+ let mut kvs = kvs.into_iter();
+ if let Some((k, v)) = kvs.next() {
+ if k == "message" {
+ write!(buf, "{}", v)?;
+ } else {
+ write!(buf, "{}={}", k, v)?;
+ }
+ }
+ for (k, v) in kvs {
+ write!(buf, ", {}={}", k, v)?;
+ }
+ Ok(())
+ }
+
+ fn write_span_info<S>(&self, id: &Id, ctx: &Context<S>, style: SpanMode)
+ where
+ S: Subscriber + for<'span> LookupSpan<'span>,
+ {
+ let span = ctx
+ .span(id)
+ .expect("in on_enter/on_exit but span does not exist");
+ let ext = span.extensions();
+ let data = ext.get::<Data>().expect("span does not have data");
+
+ let mut guard = self.bufs.lock().unwrap();
+ let bufs = &mut *guard;
+ let mut current_buf = &mut bufs.current_buf;
+
+ let indent = ctx
+ .lookup_current()
+ .as_ref()
+ .map(registry::SpanRef::scope)
+ .map(registry::Scope::from_root)
+ .into_iter()
+ .flatten()
+ .count();
+
+ if self.config.verbose_entry || matches!(style, SpanMode::Open { .. } | SpanMode::Event) {
+ if self.config.targets {
+ let target = span.metadata().target();
+ write!(
+ &mut current_buf,
+ "{}::",
+ self.styled(Style::new().dimmed(), target,),
+ )
+ .expect("Unable to write to buffer");
+ }
+
+ write!(
+ current_buf,
+ "{name}",
+ name = self.styled(Style::new().fg(Color::Green).bold(), span.metadata().name())
+ )
+ .unwrap();
+ if self.config.bracketed_fields {
+ write!(
+ current_buf,
+ "{}",
+ self.styled(Style::new().fg(Color::Green).bold(), "{") // Style::new().fg(Color::Green).dimmed().paint("{")
+ )
+ .unwrap();
+ } else {
+ write!(current_buf, " ").unwrap();
+ }
+ self.print_kvs(&mut current_buf, data.kvs.iter().map(|(k, v)| (*k, v)))
+ .unwrap();
+ if self.config.bracketed_fields {
+ write!(
+ current_buf,
+ "{}",
+ self.styled(Style::new().fg(Color::Green).bold(), "}") // Style::new().dimmed().paint("}")
+ )
+ .unwrap();
+ }
+ }
+
+ bufs.indent_current(indent, &self.config, style);
+ let writer = self.make_writer.make_writer();
+ bufs.flush_current_buf(writer)
+ }
+}
+
+impl<S, W> Layer<S> for HierarchicalLayer<W>
+where
+ S: Subscriber + for<'span> LookupSpan<'span>,
+ W: for<'writer> MakeWriter<'writer> + 'static,
+{
+ fn on_new_span(&self, attrs: &Attributes, id: &Id, ctx: Context<S>) {
+ let span = ctx.span(id).expect("in new_span but span does not exist");
+ if span.extensions().get::<Data>().is_none() {
+ let data = Data::new(attrs);
+ span.extensions_mut().insert(data);
+ }
+
+ if self.config.verbose_exit {
+ if let Some(span) = span.parent() {
+ self.write_span_info(&span.id(), &ctx, SpanMode::PreOpen);
+ }
+ }
+
+ self.write_span_info(
+ id,
+ &ctx,
+ SpanMode::Open {
+ verbose: self.config.verbose_entry,
+ },
+ );
+ }
+
+ fn on_event(&self, event: &Event<'_>, ctx: Context<S>) {
+ let mut guard = self.bufs.lock().unwrap();
+ let bufs = &mut *guard;
+ let mut event_buf = &mut bufs.current_buf;
+
+ // printing the indentation
+ let indent = if ctx.current_span().id().is_some() {
+ // size hint isn't implemented on Scope.
+ ctx.event_scope(event)
+ .expect("Unable to get span scope; this is a bug")
+ .count()
+ } else {
+ 0
+ };
+
+ // check if this event occurred in the context of a span.
+ // if it has, get the start time of this span.
+ let start = match ctx.current_span().id() {
+ Some(id) => match ctx.span(id) {
+ // if the event is in a span, get the span's starting point.
+ Some(ctx) => {
+ let ext = ctx.extensions();
+ let data = ext
+ .get::<Data>()
+ .expect("Data cannot be found in extensions");
+ Some(data.start)
+ }
+ None => None,
+ },
+ None => None,
+ };
+ if let Some(start) = start {
+ let elapsed = start.elapsed();
+ write!(
+ &mut event_buf,
+ "{timestamp}{unit} ",
+ timestamp = self.styled(Style::new().dimmed(), elapsed.as_millis().to_string()),
+ unit = self.styled(Style::new().dimmed(), "ms"),
+ )
+ .expect("Unable to write to buffer");
+ }
+
+ #[cfg(feature = "tracing-log")]
+ let normalized_meta = event.normalized_metadata();
+ #[cfg(feature = "tracing-log")]
+ let metadata = normalized_meta.as_ref().unwrap_or_else(|| event.metadata());
+ #[cfg(not(feature = "tracing-log"))]
+ let metadata = event.metadata();
+
+ let level = metadata.level();
+ let level = if self.config.ansi {
+ ColorLevel(level).to_string()
+ } else {
+ level.to_string()
+ };
+ write!(&mut event_buf, "{level}", level = level).expect("Unable to write to buffer");
+
+ if self.config.targets {
+ let target = metadata.target();
+ write!(
+ &mut event_buf,
+ " {}",
+ self.styled(Style::new().dimmed(), target,),
+ )
+ .expect("Unable to write to buffer");
+ }
+
+ let mut visitor = FmtEvent { comma: false, bufs };
+ event.record(&mut visitor);
+ visitor
+ .bufs
+ .indent_current(indent, &self.config, SpanMode::Event);
+ let writer = self.make_writer.make_writer();
+ bufs.flush_current_buf(writer)
+ }
+
+ fn on_close(&self, id: Id, ctx: Context<S>) {
+ self.write_span_info(
+ &id,
+ &ctx,
+ SpanMode::Close {
+ verbose: self.config.verbose_exit,
+ },
+ );
+
+ if self.config.verbose_exit {
+ if let Some(span) = ctx.span(&id).and_then(|span| span.parent()) {
+ self.write_span_info(&span.id(), &ctx, SpanMode::PostClose);
+ }
+ }
+ }
+}