From 018c4950b9406055dec02ef0fb52f132e2bb1e2c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 19 Jun 2024 11:25:56 +0200 Subject: Merging upstream version 1.76.0+dfsg1. Signed-off-by: Daniel Baumann --- vendor/tracing-tree/src/format.rs | 427 ------------------------------------- vendor/tracing-tree/src/lib.rs | 436 -------------------------------------- vendor/tracing-tree/src/time.rs | 119 ----------- 3 files changed, 982 deletions(-) delete mode 100644 vendor/tracing-tree/src/format.rs delete mode 100644 vendor/tracing-tree/src/lib.rs delete mode 100644 vendor/tracing-tree/src/time.rs (limited to 'vendor/tracing-tree/src') diff --git a/vendor/tracing-tree/src/format.rs b/vendor/tracing-tree/src/format.rs deleted file mode 100644 index aa56178be..000000000 --- a/vendor/tracing-tree/src/format.rs +++ /dev/null @@ -1,427 +0,0 @@ -use nu_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) { - let prefix = config.prefix(); - - // Render something when wraparound occurs so the user is aware of it - if config.indent_lines { - self.current_buf.push('\n'); - - 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(' '); - 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 deleted file mode 100644 index d171c7608..000000000 --- a/vendor/tracing-tree/src/lib.rs +++ /dev/null @@ -1,436 +0,0 @@ -pub(crate) mod format; -pub mod time; - -use crate::time::FormatTime; -use format::{Buffers, ColorLevel, Config, FmtEvent, SpanMode}; - -use is_terminal::IsTerminal; -use nu_ansi_term::{Color, Style}; -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 io::Stderr, FT = ()> -where - W: for<'writer> MakeWriter<'writer> + 'static, - FT: FormatTime, -{ - make_writer: W, - bufs: Mutex, - config: Config, - timer: FT, -} - -impl Default for HierarchicalLayer { - fn default() -> Self { - Self::new(2) - } -} - -impl HierarchicalLayer io::Stderr> { - pub fn new(indent_amount: usize) -> Self { - let ansi = io::stderr().is_terminal(); - let config = Config { - ansi, - indent_amount, - ..Default::default() - }; - Self { - make_writer: io::stderr, - bufs: Mutex::new(Buffers::new()), - config, - timer: (), - } - } -} - -impl HierarchicalLayer -where - W: for<'writer> MakeWriter<'writer> + 'static, - FT: FormatTime, -{ - /// 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(self, make_writer: W2) -> HierarchicalLayer - where - W2: for<'writer> MakeWriter<'writer>, - { - HierarchicalLayer { - make_writer, - config: self.config, - bufs: self.bufs, - timer: self.timer, - } - } - - 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 - } - } - - /// Specifies how to measure and format time at which event has occurred. - pub fn with_timer(self, timer: FT2) -> HierarchicalLayer { - HierarchicalLayer { - make_writer: self.make_writer, - config: self.config, - bufs: self.bufs, - timer, - } - } - - /// 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) -> 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, - 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(&self, id: &Id, ctx: &Context, 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::().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 Layer for HierarchicalLayer -where - S: Subscriber + for<'span> LookupSpan<'span>, - W: for<'writer> MakeWriter<'writer> + 'static, - FT: FormatTime + 'static, -{ - fn on_new_span(&self, attrs: &Attributes, id: &Id, ctx: Context) { - let span = ctx.span(id).expect("in new_span but span does not exist"); - if span.extensions().get::().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) { - let mut guard = self.bufs.lock().unwrap(); - let bufs = &mut *guard; - let mut event_buf = &mut bufs.current_buf; - - // Time. - - { - let prev_buffer_len = event_buf.len(); - - self.timer - .format_time(&mut event_buf) - .expect("Unable to write time to buffer"); - - // Something was written to the buffer, pad it with a space. - if prev_buffer_len < event_buf.len() { - write!(event_buf, " ").expect("Unable to write to buffer"); - } - } - - // printing the indentation - let indent = ctx - .event_scope(event) - .map(|scope| scope.count()) - .unwrap_or(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::() - .expect("Data cannot be found in extensions"); - Some(data.start) - } - None => None, - }, - None => None, - }; - if let Some(start) = start { - let elapsed = start.elapsed(); - let millis = elapsed.as_millis(); - let secs = elapsed.as_secs(); - let (n, unit) = if millis < 1000 { - (millis as _, "ms") - } else if secs < 60 { - (secs, "s ") - } else { - (secs / 60, "m ") - }; - let n = format!("{n:>3}"); - write!( - &mut event_buf, - "{timestamp}{unit} ", - timestamp = self.styled(Style::new().dimmed(), n), - unit = self.styled(Style::new().dimmed(), unit), - ) - .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) { - 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); - } - } - } -} diff --git a/vendor/tracing-tree/src/time.rs b/vendor/tracing-tree/src/time.rs deleted file mode 100644 index e0f81d47d..000000000 --- a/vendor/tracing-tree/src/time.rs +++ /dev/null @@ -1,119 +0,0 @@ -/// A type that can measure and format the current time. -/// -/// This trait is used by [HierarchicalLayer] to include a timestamp with each -/// [Event] when it is logged. -/// -/// Notable default implementations of this trait are [LocalDateTime] and `()`. -/// The former prints the current time as reported by [time's OffsetDateTime] -/// (note that it requires a `time` feature to be enabled and may panic! -/// make sure to check out the docs for the [LocalDateTime]), -/// and the latter does not print the current time at all. -/// -/// Inspired by the [FormatTime] trait from [tracing-subscriber]. -/// -/// [HierarchicalLayer]: crate::HierarchicalLayer -/// [Event]: tracing_core::Event -/// [time's OffsetDateTime]: time::OffsetDateTime -/// [FormatTime]: tracing_subscriber::fmt::time::FormatTime -/// [tracing-subscriber]: tracing_subscriber -// NB: -// We can't use `tracing_subscriber::fmt::format::Writer` -// since it doesn't have a public constructor. -pub trait FormatTime { - fn format_time(&self, w: &mut impl std::fmt::Write) -> std::fmt::Result; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/// Default do-nothing time formatter. -impl FormatTime for () { - fn format_time(&self, _w: &mut impl std::fmt::Write) -> std::fmt::Result { - Ok(()) - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/// Retrieve and print the current wall-clock time in UTC timezone. -#[cfg(feature = "time")] -#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] -pub struct UtcDateTime; - -#[cfg(feature = "time")] -impl FormatTime for UtcDateTime { - fn format_time(&self, w: &mut impl std::fmt::Write) -> std::fmt::Result { - let time = time::OffsetDateTime::now_utc(); - write!(w, "{} {}", time.date(), time.time()) - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/// Retrieve and print the current wall-clock time. -/// -/// # Panics -/// -/// Panics if [time crate] cannot determine the local UTC offset. -/// -/// [time crate]: time -// NB: -// Can't use `tracing_subscriber::fmt::time::SystemTime` since it uses -// private `datetime` module to format the actual time. -#[cfg(feature = "time")] -#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] -pub struct LocalDateTime; - -#[cfg(feature = "time")] -impl FormatTime for LocalDateTime { - fn format_time(&self, w: &mut impl std::fmt::Write) -> std::fmt::Result { - let time = time::OffsetDateTime::now_local().expect("time offset cannot be determined"); - write!(w, "{}", time) - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/// Retrieve and print the relative elapsed wall-clock time since an epoch. -/// -/// The `Default` implementation for `Uptime` makes the epoch the current time. -// NB: Copy-pasted from `tracing-subscriber::fmt::time::Uptime`. -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub struct Uptime { - epoch: std::time::Instant, -} - -impl Default for Uptime { - fn default() -> Self { - Uptime { - epoch: std::time::Instant::now(), - } - } -} - -impl From for Uptime { - fn from(epoch: std::time::Instant) -> Self { - Uptime { epoch } - } -} - -impl FormatTime for Uptime { - fn format_time(&self, w: &mut impl std::fmt::Write) -> std::fmt::Result { - let e = self.epoch.elapsed(); - write!(w, "{:4}.{:06}s", e.as_secs(), e.subsec_micros()) - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -impl<'a, F> FormatTime for &'a F -where - F: FormatTime, -{ - fn format_time(&self, w: &mut impl std::fmt::Write) -> std::fmt::Result { - (*self).format_time(w) - } -} - -// NB: -// Can't impl for `fn(&mut impl std::fmt::Write)` since impl trait is not allowed -// outside of function and inherent method return types for now. -- cgit v1.2.3