diff --git a/tracing-core/src/metadata.rs b/tracing-core/src/metadata.rs index 61da6f659b..21840aa7a4 100644 --- a/tracing-core/src/metadata.rs +++ b/tracing-core/src/metadata.rs @@ -1,5 +1,7 @@ //! Metadata describing trace data. use super::{callsite, field}; +#[cfg(feature = "alloc")] +use alloc::borrow::Cow; use core::{ cmp, fmt, str::FromStr, @@ -60,10 +62,16 @@ use core::{ /// [callsite identifier]: super::callsite::Identifier pub struct Metadata<'a> { /// The name of the span described by this metadata. - name: &'static str, + #[cfg(feature = "alloc")] + name: Cow<'a, str>, + #[cfg(not(feature = "alloc"))] + name: &'a str, /// The part of the system that the span that this metadata describes /// occurred in. + #[cfg(feature = "alloc")] + target: Cow<'a, str>, + #[cfg(not(feature = "alloc"))] target: &'a str, /// The level of verbosity of the described span. @@ -71,10 +79,16 @@ pub struct Metadata<'a> { /// The name of the Rust module where the span occurred, or `None` if this /// could not be determined. + #[cfg(feature = "alloc")] + module_path: Option>, + #[cfg(not(feature = "alloc"))] module_path: Option<&'a str>, /// The name of the source code file where the span occurred, or `None` if /// this could not be determined. + #[cfg(feature = "alloc")] + file: Option>, + #[cfg(not(feature = "alloc"))] file: Option<&'a str>, /// The line number in the source code file where the span occurred, or @@ -122,7 +136,7 @@ impl<'a> Metadata<'a> { /// Construct new metadata for a span or event, with a name, target, level, field /// names, and optional source code location. pub const fn new( - name: &'static str, + name: &'a str, target: &'a str, level: Level, file: Option<&'a str>, @@ -131,8 +145,31 @@ impl<'a> Metadata<'a> { fields: field::FieldSet, kind: Kind, ) -> Self { + #[cfg(feature = "alloc")] + let file = { + if let Some(file) = file { + Some(Cow::Borrowed(file)) + } else { + None + } + }; + #[cfg(feature = "alloc")] + let module_path = { + if let Some(module_path) = module_path { + Some(Cow::Borrowed(module_path)) + } else { + None + } + }; + Metadata { + #[cfg(feature = "alloc")] + name: Cow::Borrowed(name), + #[cfg(not(feature = "alloc"))] name, + #[cfg(feature = "alloc")] + target: Cow::Borrowed(target), + #[cfg(not(feature = "alloc"))] target, level, module_path, @@ -143,6 +180,32 @@ impl<'a> Metadata<'a> { } } + /// Construct new metadata for a span or event, with a name, target, level, field + /// names, and optional source code location using dynamically allocated data. + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + pub fn from_cow( + name: impl Into>, + target: impl Into>, + level: Level, + file: Option>>, + line: Option, + module_path: Option>>, + fields: field::FieldSet, + kind: Kind, + ) -> Self { + Metadata { + name: name.into(), + target: target.into(), + level, + module_path: module_path.map(Into::into), + file: file.map(Into::into), + line, + fields, + kind, + } + } + /// Returns the names of the fields on the described span or event. pub fn fields(&self) -> &field::FieldSet { &self.fields @@ -154,8 +217,8 @@ impl<'a> Metadata<'a> { } /// Returns the name of the span. - pub fn name(&self) -> &'static str { - self.name + pub fn name(&self) -> &str { + &self.name } /// Returns a string describing the part of the system where the span or @@ -163,20 +226,20 @@ impl<'a> Metadata<'a> { /// /// Typically, this is the module path, but alternate targets may be set /// when spans or events are constructed. - pub fn target(&self) -> &'a str { - self.target + pub fn target(&self) -> &str { + &self.target } /// Returns the path to the Rust module where the span occurred, or /// `None` if the module path is unknown. - pub fn module_path(&self) -> Option<&'a str> { - self.module_path + pub fn module_path(&'a self) -> Option<&'a str> { + self.module_path.as_ref().map(|p| p.as_ref()) } /// Returns the name of the source code file where the span /// occurred, or `None` if the file is unknown - pub fn file(&self) -> Option<&'a str> { - self.file + pub fn file(&'a self) -> Option<&'a str> { + self.file.as_ref().map(|f| f.as_ref()) } /// Returns the line number in the source code file where the span @@ -799,6 +862,12 @@ impl PartialOrd for LevelFilter { #[cfg(test)] mod tests { use super::*; + #[cfg(feature = "alloc")] + use crate::{ + callsite::{Callsite, Identifier}, + field::FieldSet, + Interest, + }; use core::mem; #[test] @@ -863,4 +932,31 @@ mod tests { assert_eq!(expected, repr, "repr changed for {:?}", filter) } } + + #[cfg(feature = "alloc")] + #[test] + fn create_metadata_from_dynamic_data() { + struct TestCallsite; + static CS1: TestCallsite = TestCallsite; + + impl Callsite for TestCallsite { + fn set_interest(&self, _interest: Interest) {} + fn metadata(&self) -> &Metadata<'_> { + unimplemented!("not needed for this test") + } + } + let callsite_id = Identifier(&CS1); + let field_set = FieldSet::new(&["one", "fine", "day"], callsite_id); + + let _metadata = Metadata::from_cow( + "a name".to_string(), + "a target", + Level::TRACE, + Some("a file".to_string()), + None, + None::>, + field_set, + Kind::EVENT, + ); + } } diff --git a/tracing-log/src/lib.rs b/tracing-log/src/lib.rs index 8795da2dbb..044e241a05 100644 --- a/tracing-log/src/lib.rs +++ b/tracing-log/src/lib.rs @@ -186,11 +186,11 @@ pub fn format_trace(record: &log::Record<'_>) -> io::Result<()> { /// Trait implemented for `tracing` types that can be converted to a `log` /// equivalent. -pub trait AsLog: crate::sealed::Sealed { +pub trait AsLog<'a>: crate::sealed::Sealed { /// The `log` type that this type can be converted into. type Log; /// Returns the `log` equivalent of `self`. - fn as_log(&self) -> Self::Log; + fn as_log(&'a self) -> Self::Log; } /// Trait implemented for `log` types that can be converted to a `tracing` @@ -204,12 +204,12 @@ pub trait AsTrace: crate::sealed::Sealed { impl<'a> crate::sealed::Sealed for Metadata<'a> {} -impl<'a> AsLog for Metadata<'a> { +impl<'a> AsLog<'a> for Metadata<'a> { type Log = log::Metadata<'a>; - fn as_log(&self) -> Self::Log { + fn as_log(&'a self) -> Self::Log { log::Metadata::builder() .level(self.level().as_log()) - .target(self.target()) + .target(&self.target()) .build() } } @@ -329,7 +329,7 @@ impl<'a> AsTrace for log::Record<'a> { impl crate::sealed::Sealed for tracing_core::Level {} -impl AsLog for tracing_core::Level { +impl<'a> AsLog<'a> for tracing_core::Level { type Log = log::Level; fn as_log(&self) -> log::Level { match *self { diff --git a/tracing-log/src/trace_logger.rs b/tracing-log/src/trace_logger.rs new file mode 100644 index 0000000000..6ac9a51304 --- /dev/null +++ b/tracing-log/src/trace_logger.rs @@ -0,0 +1,468 @@ +//! A `tracing` [`Subscriber`] that uses the [`log`] crate as a backend for +//! formatting `tracing` spans and events. +//! +//! When a [`TraceLogger`] is set as the current subscriber, it will record +//! traces by emitting [`log::Record`]s that can be collected by a logger. +//! +//! **Note**: This API has been deprecated since version 0.1.1. In order to emit +//! `tracing` events as `log` records, the ["log" and "log-always" feature +//! flags][flags] on the `tracing` crate should be used instead. +//! +//! [`log`]: https://docs.rs/log/0.4.8/log/index.html +//! [`Subscriber`]: https://docs.rs/tracing/0.1.7/tracing/subscriber/trait.Subscriber.html +//! [`TraceLogger`]: struct.TraceLogger.html +//! [`log::Record`]: https://docs.rs/log/0.4.8/log/struct.Record.html +//! [flags]: https://docs.rs/tracing/latest/tracing/#crate-feature-flags +#![deprecated( + since = "0.1.1", + note = "use the `tracing` crate's \"log\" feature flag instead" +)] +use crate::AsLog; +use std::{ + borrow::Cow, + cell::RefCell, + collections::HashMap, + fmt::{self, Write}, + sync::{ + atomic::{AtomicUsize, Ordering}, + Mutex, + }, +}; +use tracing_core::{ + field, + span::{self, Id}, + Event, Metadata, Subscriber, +}; + +/// A `tracing` [`Subscriber`] implementation that logs all recorded +/// trace events. +/// +/// **Note**: This API has been deprecated since version 0.1.1. In order to emit +/// `tracing` events as `log` records, the ["log" and "log-always" feature +/// flags][flags] on the `tracing` crate should be used instead. +/// +/// [`Subscriber`]: https://docs.rs/tracing/0.1.7/tracing/subscriber/trait.Subscriber.html +/// [flags]: https://docs.rs/tracing/latest/tracing/#crate-feature-flags +pub struct TraceLogger<'a> { + settings: Builder, + spans: Mutex>>, + next_id: AtomicUsize, +} + +thread_local! { + static CURRENT: RefCell> = RefCell::new(Vec::new()); +} +/// Configures and constructs a [`TraceLogger`]. +/// +/// [`TraceLogger`]: struct.TraceLogger.html +#[derive(Debug)] +pub struct Builder { + log_span_closes: bool, + log_enters: bool, + log_exits: bool, + log_ids: bool, + parent_fields: bool, + log_parent: bool, +} + +// ===== impl TraceLogger ===== + +impl TraceLogger<'static> { + /// Returns a new `TraceLogger` with the default configuration. + pub fn new() -> Self { + Self::builder().finish() + } + + /// Returns a `Builder` for configuring a `TraceLogger`. + pub fn builder() -> Builder { + Default::default() + } + + fn from_builder(settings: Builder) -> Self { + Self { + settings, + ..Default::default() + } + } + + fn next_id(&self) -> Id { + Id::from_u64(self.next_id.fetch_add(1, Ordering::SeqCst) as u64) + } +} + +// ===== impl Builder ===== + +impl Builder { + /// Configures whether or not the [`TraceLogger`] being constructed will log + /// when a span closes. + /// + /// [`TraceLogger`]: struct.TraceLogger.html + pub fn with_span_closes(self, log_span_closes: bool) -> Self { + Self { + log_span_closes, + ..self + } + } + + /// Configures whether or not the [`TraceLogger`] being constructed will + /// include the fields of parent spans when formatting events. + /// + /// [`TraceLogger`]: struct.TraceLogger.html + pub fn with_parent_fields(self, parent_fields: bool) -> Self { + Self { + parent_fields, + ..self + } + } + + /// Configures whether or not the [`TraceLogger`] being constructed will log + /// when a span is entered. + /// + /// If this is set to false, fields from the current span will still be + /// recorded as context, but the actual entry will not create a log record. + /// + /// [`TraceLogger`]: struct.TraceLogger.html + pub fn with_span_entry(self, log_enters: bool) -> Self { + Self { log_enters, ..self } + } + + /// Configures whether or not the [`TraceLogger`] being constructed will log + /// when a span is exited. + /// + /// [`TraceLogger`]: struct.TraceLogger.html + pub fn with_span_exits(self, log_exits: bool) -> Self { + Self { log_exits, ..self } + } + + /// Configures whether or not the [`TraceLogger`] being constructed will + /// include span IDs when formatting log output. + /// + /// [`TraceLogger`]: struct.TraceLogger.html + pub fn with_ids(self, log_ids: bool) -> Self { + Self { log_ids, ..self } + } + + /// Configures whether or not the [`TraceLogger`] being constructed will + /// include the names of parent spans as context when formatting events. + /// + /// [`TraceLogger`]: struct.TraceLogger.html + pub fn with_parent_names(self, log_parent: bool) -> Self { + Self { log_parent, ..self } + } + + /// Complete the builder, returning a configured [`TraceLogger`]. + /// + /// [`TraceLogger`]: struct.TraceLogger.html + pub fn finish(self) -> TraceLogger<'static> { + TraceLogger::from_builder(self) + } +} + +impl Default for Builder { + fn default() -> Self { + Builder { + log_span_closes: false, + parent_fields: true, + log_exits: false, + log_ids: false, + log_parent: true, + log_enters: false, + } + } +} + +impl Default for TraceLogger<'_> { + fn default() -> Self { + TraceLogger { + settings: Default::default(), + spans: Default::default(), + next_id: AtomicUsize::new(1), + } + } +} + +#[derive(Debug)] +struct SpanLineBuilder<'a> { + parent: Option, + ref_count: usize, + fields: String, + file: Option, + line: Option, + module_path: Option, + target: String, + level: log::Level, + name: Cow<'a, str>, +} + +impl<'a> SpanLineBuilder<'a> { + fn new(parent: Option, meta: &'a Metadata<'_>, fields: String) -> Self { + Self { + parent, + ref_count: 1, + fields, + file: meta.file().map(String::from), + line: meta.line(), + module_path: meta.module_path().map(String::from), + target: String::from(meta.target()), + level: meta.level().as_log(), + name: meta.name().into(), + } + } + + fn log_meta(&self) -> log::Metadata<'_> { + log::MetadataBuilder::new() + .level(self.level) + .target(self.target.as_ref()) + .build() + } + + fn finish(self) { + let log_meta = self.log_meta(); + let logger = log::logger(); + if logger.enabled(&log_meta) { + logger.log( + &log::Record::builder() + .metadata(log_meta) + .target(self.target.as_ref()) + .module_path(self.module_path.as_ref().map(String::as_ref)) + .file(self.file.as_ref().map(String::as_ref)) + .line(self.line) + .args(format_args!("close {}; {}", self.name, self.fields)) + .build(), + ); + } + } +} + +impl field::Visit for SpanLineBuilder<'_> { + fn record_debug(&mut self, field: &field::Field, value: &dyn fmt::Debug) { + write!(self.fields, " {}={:?};", field.name(), value) + .expect("write to string should never fail") + } +} + +impl Subscriber for TraceLogger<'static> { + fn enabled(&self, metadata: &Metadata<'_>) -> bool { + log::logger().enabled(&metadata.as_log()) + } + + fn new_span(&self, attrs: &span::Attributes<'_>) -> Id { + let id = self.next_id(); + let mut spans = self.spans.lock().unwrap(); + let mut fields = String::new(); + let parent = self.current_id(); + if self.settings.parent_fields { + let mut next_parent = parent.as_ref(); + while let Some(ref parent) = next_parent.and_then(|p| spans.get(&p)) { + write!(&mut fields, "{}", parent.fields).expect("write to string cannot fail"); + next_parent = parent.parent.as_ref(); + } + } + let mut span = SpanLineBuilder::new(parent, attrs.metadata(), fields); + attrs.record(&mut span); + spans.insert(id.clone(), span); + id + } + + fn record(&self, span: &Id, values: &span::Record<'_>) { + let mut spans = self.spans.lock().unwrap(); + if let Some(span) = spans.get_mut(span) { + values.record(span); + } + } + + fn record_follows_from(&self, span: &Id, follows: &Id) { + // TODO: this should eventually track the relationship? + log::logger().log( + &log::Record::builder() + .level(log::Level::Trace) + .args(format_args!("span {:?} follows_from={:?};", span, follows)) + .build(), + ); + } + + fn enter(&self, id: &Id) { + let _ = CURRENT.try_with(|current| { + let mut current = current.borrow_mut(); + if current.contains(id) { + // Ignore duplicate enters. + return; + } + current.push(id.clone()); + }); + let spans = self.spans.lock().unwrap(); + if self.settings.log_enters { + if let Some(span) = spans.get(id) { + let log_meta = span.log_meta(); + let logger = log::logger(); + if logger.enabled(&log_meta) { + let current_id = self.current_id(); + let current_fields = current_id + .as_ref() + .and_then(|id| spans.get(&id)) + .map(|span| span.fields.as_ref()) + .unwrap_or(""); + if self.settings.log_ids { + logger.log( + &log::Record::builder() + .metadata(log_meta) + .target(span.target.as_ref()) + .module_path(span.module_path.as_ref().map(String::as_ref)) + .file(span.file.as_ref().map(String::as_ref)) + .line(span.line) + .args(format_args!( + "enter {}; in={:?}; {}", + span.name, current_id, current_fields + )) + .build(), + ); + } else { + logger.log( + &log::Record::builder() + .metadata(log_meta) + .target(span.target.as_ref()) + .module_path(span.module_path.as_ref().map(String::as_ref)) + .file(span.file.as_ref().map(String::as_ref)) + .line(span.line) + .args(format_args!("enter {}; {}", span.name, current_fields)) + .build(), + ); + } + } + } + } + } + + fn exit(&self, id: &Id) { + let _ = CURRENT.try_with(|current| { + let mut current = current.borrow_mut(); + if current.last() == Some(id) { + current.pop() + } else { + None + } + }); + if self.settings.log_exits { + let spans = self.spans.lock().unwrap(); + if let Some(span) = spans.get(id) { + let log_meta = span.log_meta(); + let logger = log::logger(); + if logger.enabled(&log_meta) { + logger.log( + &log::Record::builder() + .metadata(log_meta) + .target(span.target.as_ref()) + .module_path(span.module_path.as_ref().map(String::as_ref)) + .file(span.file.as_ref().map(String::as_ref)) + .line(span.line) + .args(format_args!("exit {}", span.name)) + .build(), + ); + } + } + } + } + + fn event(&self, event: &Event<'_>) { + let meta = event.metadata(); + let log_meta = meta.as_log(); + let logger = log::logger(); + if logger.enabled(&log_meta) { + let spans = self.spans.lock().unwrap(); + let current = self.current_id().and_then(|id| spans.get(&id)); + let (current_fields, parent) = current + .map(|span| { + let fields = span.fields.as_ref(); + let parent = if self.settings.log_parent { + Some(span.name.as_ref()) + } else { + None + }; + (fields, parent) + }) + .unwrap_or(("", None)); + logger.log( + &log::Record::builder() + .metadata(log_meta) + .target(&meta.target()) + .module_path(meta.module_path().as_ref().cloned()) + .file(meta.file().as_ref().cloned()) + .line(meta.line()) + .args(format_args!( + "{}{}{}{}", + parent.unwrap_or(""), + if parent.is_some() { ": " } else { "" }, + LogEvent(event), + current_fields, + )) + .build(), + ); + } + } + + fn clone_span(&self, id: &Id) -> Id { + let mut spans = self.spans.lock().unwrap(); + if let Some(span) = spans.get_mut(id) { + span.ref_count += 1; + } + id.clone() + } + + fn try_close(&self, id: Id) -> bool { + let mut spans = self.spans.lock().unwrap(); + if spans.contains_key(&id) { + if spans.get(&id).unwrap().ref_count == 1 { + let span = spans.remove(&id).unwrap(); + if self.settings.log_span_closes { + span.finish(); + } + return true; + } else { + spans.get_mut(&id).unwrap().ref_count -= 1; + } + } + false + } +} + +impl TraceLogger<'static> { + #[inline] + fn current_id(&self) -> Option { + CURRENT + .try_with(|current| current.borrow().last().map(|span| self.clone_span(span))) + .ok()? + } +} + +struct LogEvent<'a>(&'a Event<'a>); + +impl<'a> fmt::Display for LogEvent<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut has_logged = false; + let mut format_fields = |field: &field::Field, value: &dyn fmt::Debug| { + let name = field.name(); + let leading = if has_logged { " " } else { "" }; + // TODO: handle fmt error? + let _ = if name == "message" { + write!(f, "{}{:?};", leading, value) + } else { + write!(f, "{}{}={:?};", leading, name, value) + }; + has_logged = true; + }; + + self.0.record(&mut format_fields); + Ok(()) + } +} + +impl fmt::Debug for TraceLogger<'static> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("TraceLogger") + .field("settings", &self.settings) + .field("spans", &self.spans) + .field("current", &self.current_id()) + .field("next_id", &self.next_id) + .finish() + } +} diff --git a/tracing-serde/src/lib.rs b/tracing-serde/src/lib.rs index 5d43974c84..3f293b85bf 100644 --- a/tracing-serde/src/lib.rs +++ b/tracing-serde/src/lib.rs @@ -263,8 +263,8 @@ impl<'a> Serialize for SerializeMetadata<'a> { S: Serializer, { let mut state = serializer.serialize_struct("Metadata", 9)?; - state.serialize_field("name", self.0.name())?; - state.serialize_field("target", self.0.target())?; + state.serialize_field("name", &self.0.name())?; + state.serialize_field("target", &self.0.target())?; state.serialize_field("level", &SerializeLevel(self.0.level()))?; state.serialize_field("module_path", &self.0.module_path())?; state.serialize_field("file", &self.0.file())?; diff --git a/tracing-subscriber/src/fmt/format/json.rs b/tracing-subscriber/src/fmt/format/json.rs index 51748264e3..4224d31b42 100644 --- a/tracing-subscriber/src/fmt/format/json.rs +++ b/tracing-subscriber/src/fmt/format/json.rs @@ -167,7 +167,7 @@ where // that the fields are not supposed to be missing. Err(e) => serializer.serialize_entry("field_error", &format!("{}", e))?, }; - serializer.serialize_entry("name", self.0.metadata().name())?; + serializer.serialize_entry("name", &self.0.metadata().name())?; serializer.end() } } diff --git a/tracing-subscriber/src/registry/mod.rs b/tracing-subscriber/src/registry/mod.rs index 7cacc78fe7..e17e899bdf 100644 --- a/tracing-subscriber/src/registry/mod.rs +++ b/tracing-subscriber/src/registry/mod.rs @@ -203,8 +203,8 @@ where } /// Returns the span's name, - pub fn name(&self) -> &'static str { - self.data.metadata().name() + pub fn name(&self) -> &str { + self.metadata().name() } /// Returns a list of [fields] defined by the span. diff --git a/tracing-subscriber/src/registry/sharded.rs b/tracing-subscriber/src/registry/sharded.rs index 090cb2731a..d58ac079dc 100644 --- a/tracing-subscriber/src/registry/sharded.rs +++ b/tracing-subscriber/src/registry/sharded.rs @@ -488,8 +488,8 @@ mod tests { #[derive(Default)] struct CloseState { - open: HashMap<&'static str, Weak<()>>, - closed: Vec<(&'static str, Weak<()>)>, + open: HashMap>, + closed: Vec<(String, Weak<()>)>, } struct SetRemoved(Arc<()>); @@ -504,7 +504,7 @@ mod tests { let is_removed = Arc::new(()); assert!( lock.open - .insert(span.name(), Arc::downgrade(&is_removed)) + .insert(span.name().to_string(), Arc::downgrade(&is_removed)) .is_none(), "test layer saw multiple spans with the same name, the test is probably messed up" ); @@ -527,7 +527,7 @@ mod tests { if let Ok(mut lock) = self.inner.lock() { if let Some(is_removed) = lock.open.remove(name) { assert!(is_removed.upgrade().is_some()); - lock.closed.push((name, is_removed)); + lock.closed.push((name.to_string(), is_removed)); } } } @@ -620,14 +620,14 @@ mod tests { } #[allow(unused)] // may want this for future tests - fn assert_last_closed(&self, span: Option<&str>) { + fn assert_last_closed(&self, span: Option) { let lock = self.state.lock().unwrap(); let last = lock.closed.last().map(|(span, _)| span); assert_eq!( last, span.as_ref(), "expected {:?} to have closed last", - span + span.as_ref() ); } @@ -636,8 +636,8 @@ mod tests { let order = order.as_ref(); for (i, name) in order.iter().enumerate() { assert_eq!( - lock.closed.get(i).map(|(span, _)| span), - Some(name), + lock.closed.get(i).map(|(span, _)| span.as_ref()), + Some(*name), "expected close order: {:?}, actual: {:?}", order, lock.closed.iter().map(|(name, _)| name).collect::>() diff --git a/tracing/tests/filters_are_reevaluated_for_different_call_sites.rs b/tracing/tests/filters_are_reevaluated_for_different_call_sites.rs index 2734b0b3f5..4495ef5a87 100644 --- a/tracing/tests/filters_are_reevaluated_for_different_call_sites.rs +++ b/tracing/tests/filters_are_reevaluated_for_different_call_sites.rs @@ -36,7 +36,7 @@ fn filters_are_reevaluated_for_different_call_sites() { let subscriber = collector::mock() .with_filter(move |meta| { println!("Filter: {:?}", meta.name()); - match meta.name() { + match meta.name().as_ref() { "charlie" => { charlie_count2.fetch_add(1, Ordering::Relaxed); false diff --git a/tracing/tests/support/collector.rs b/tracing/tests/support/collector.rs index 513bedfc00..0f59a4fc9a 100644 --- a/tracing/tests/support/collector.rs +++ b/tracing/tests/support/collector.rs @@ -1,4 +1,5 @@ #![allow(missing_docs)] + use super::{ event::MockEvent, field as mock_field, @@ -246,9 +247,9 @@ where } Some(Parent::Explicit(expected_parent)) => { let actual_parent = - event.parent().and_then(|id| spans.get(id)).map(|s| s.name); + event.parent().and_then(|id| spans.get(id)).map(|s| s.name.to_string()); assert_eq!( - Some(expected_parent.as_ref()), + Some(expected_parent.clone()), actual_parent, "[{}] expected {:?} to have explicit parent {:?}", self.name, @@ -279,9 +280,9 @@ where ); let stack = self.current.lock().unwrap(); let actual_parent = - stack.last().and_then(|id| spans.get(id)).map(|s| s.name); + stack.last().and_then(|id| spans.get(id)).map(|s| s.name.to_string()); assert_eq!( - Some(expected_parent.as_ref()), + Some(expected_parent.clone()), actual_parent, "[{}] expected {:?} to have contextual parent {:?}", self.name, @@ -338,9 +339,9 @@ where } Some(Parent::Explicit(expected_parent)) => { let actual_parent = - span.parent().and_then(|id| spans.get(id)).map(|s| s.name); + span.parent().and_then(|id| spans.get(id)).map(|s| s.name.to_string()); assert_eq!( - Some(expected_parent.as_ref()), + Some(expected_parent.clone()), actual_parent, "[{}] expected {:?} to have explicit parent {:?}", self.name, @@ -371,9 +372,11 @@ where ); let stack = self.current.lock().unwrap(); let actual_parent = - stack.last().and_then(|id| spans.get(id)).map(|s| s.name); + stack.last() + .and_then(|id| spans.get(id)) + .map(|s| s.name.to_string()); assert_eq!( - Some(expected_parent.as_ref()), + Some(expected_parent.clone()), actual_parent, "[{}] expected {:?} to have contextual parent {:?}", self.name, @@ -437,7 +440,7 @@ where "[{}] exited span {:?}, but the current span was {:?}", self.name, span.name, - curr.as_ref().and_then(|id| spans.get(id)).map(|s| s.name) + curr.as_ref().and_then(|id| spans.get(id)).map(|s| &s.name) ); } Some(ex) => ex.bad(&self.name, format_args!("exited span {:?}", span.name)), @@ -446,7 +449,7 @@ where fn clone_span(&self, id: &Id) -> Id { let name = self.spans.lock().unwrap().get_mut(id).map(|span| { - let name = span.name; + let name = span.name.to_string(); println!( "[{}] clone_span: {}; id={:?}; refs={:?};", self.name, name, id, span.refs @@ -461,7 +464,7 @@ where let was_expected = if let Some(Expect::CloneSpan(ref span)) = expected.front() { assert_eq!( name, - span.name(), + span.name().map(|s| s.to_string()), "[{}] expected to clone a span named {:?}", self.name, span.name() @@ -480,7 +483,7 @@ where let mut is_event = false; let name = if let Ok(mut spans) = self.spans.try_lock() { spans.get_mut(&id).map(|span| { - let name = span.name; + let name = span.name.to_string(); if name.contains("event") { is_event = true; } @@ -503,7 +506,7 @@ where // Don't assert if this function was called while panicking, // as failing the assertion can cause a double panic. if !::std::thread::panicking() { - assert_eq!(name, span.name()); + assert_eq!(name, span.name().map(|s| s.to_string() )); } true } diff --git a/tracing/tests/support/event.rs b/tracing/tests/support/event.rs index 7033d8a134..11ef3553a7 100644 --- a/tracing/tests/support/event.rs +++ b/tracing/tests/support/event.rs @@ -69,7 +69,7 @@ impl MockEvent { pub fn with_explicit_parent(self, parent: Option<&str>) -> MockEvent { let parent = match parent { - Some(name) => Parent::Explicit(name.into()), + Some(name) => Parent::Explicit(name.to_string()), None => Parent::ExplicitRoot, }; Self { diff --git a/tracing/tests/support/metadata.rs b/tracing/tests/support/metadata.rs index 2c3606b05e..144c738768 100644 --- a/tracing/tests/support/metadata.rs +++ b/tracing/tests/support/metadata.rs @@ -13,7 +13,7 @@ impl Expect { if let Some(ref expected_name) = self.name { let name = actual.name(); assert!( - expected_name == name, + *expected_name == name, "expected {} to be named `{}`, but got one named `{}`", ctx, expected_name, diff --git a/tracing/tests/support/span.rs b/tracing/tests/support/span.rs index 023e5b7079..4da0494221 100644 --- a/tracing/tests/support/span.rs +++ b/tracing/tests/support/span.rs @@ -1,5 +1,6 @@ #![allow(missing_docs)] use super::{field, metadata, Parent}; +use std::borrow::Cow; use std::fmt; /// A mock span. @@ -60,7 +61,7 @@ impl MockSpan { pub fn with_explicit_parent(self, parent: Option<&str>) -> NewSpan { let parent = match parent { - Some(name) => Parent::Explicit(name.into()), + Some(name) => Parent::Explicit(name.to_string()), None => Parent::ExplicitRoot, }; NewSpan { @@ -72,7 +73,7 @@ impl MockSpan { pub fn with_contextual_parent(self, parent: Option<&str>) -> NewSpan { let parent = match parent { - Some(name) => Parent::Contextual(name.into()), + Some(name) => Parent::Contextual(name.to_string()), None => Parent::ContextualRoot, }; NewSpan { @@ -82,8 +83,8 @@ impl MockSpan { } } - pub fn name(&self) -> Option<&str> { - self.metadata.name.as_ref().map(String::as_ref) + pub fn name(&self) -> Option> { + self.metadata.name.as_ref().map(|s| Cow::Owned(s.clone())) } pub fn with_field(self, fields: I) -> NewSpan @@ -97,7 +98,7 @@ impl MockSpan { } } - pub(in crate::support) fn check_metadata(&self, actual: &tracing::Metadata<'_>) { + pub(in crate::support) fn check_metadata(&self, actual: &'static tracing::Metadata<'_>) { self.metadata.check(actual, format_args!("span {}", self)); assert!(actual.is_span(), "expected a span but got {:?}", actual); } @@ -125,7 +126,7 @@ impl Into for MockSpan { impl NewSpan { pub fn with_explicit_parent(self, parent: Option<&str>) -> NewSpan { let parent = match parent { - Some(name) => Parent::Explicit(name.into()), + Some(name) => Parent::Explicit(name.to_string()), None => Parent::ExplicitRoot, }; NewSpan { @@ -136,7 +137,7 @@ impl NewSpan { pub fn with_contextual_parent(self, parent: Option<&str>) -> NewSpan { let parent = match parent { - Some(name) => Parent::Contextual(name.into()), + Some(name) => Parent::Contextual(name.to_string()), None => Parent::ContextualRoot, }; NewSpan {