diff --git a/tracing-appender/Cargo.toml b/tracing-appender/Cargo.toml index 28870f18f3..e8f21ff3a8 100644 --- a/tracing-appender/Cargo.toml +++ b/tracing-appender/Cargo.toml @@ -33,7 +33,7 @@ default-features = false features = ["fmt", "std"] [dev-dependencies] -criterion = { version = "0.3.6", default_features = false } +criterion = { version = "0.3.6", default-features = false } tracing = { path = "../tracing", version = "0.2" } time = { version = "0.3.2", default-features = false, features = ["formatting", "parsing"] } tempfile = "3.3.0" diff --git a/tracing-core/src/field.rs b/tracing-core/src/field.rs index d9ba1707cd..fbaa50dec4 100644 --- a/tracing-core/src/field.rs +++ b/tracing-core/src/field.rs @@ -38,7 +38,7 @@ use crate::callsite; use core::{ borrow::Borrow, - fmt, + fmt::{self, Write}, hash::{Hash, Hasher}, num, ops::Range, @@ -224,6 +224,11 @@ pub trait Visit { self.record_debug(field, &value) } + /// Visit a byte slice. + fn record_bytes(&mut self, field: &Field, value: &[u8]) { + self.record_debug(field, &HexBytes(value)) + } + /// Records a type implementing `Error`. /// ///
@@ -283,6 +288,26 @@ where DebugValue(t) } +struct HexBytes<'a>(&'a [u8]); + +impl<'a> fmt::Debug for HexBytes<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_char('[')?; + + let mut bytes = self.0.iter(); + + if let Some(byte) = bytes.next() { + f.write_fmt(format_args!("{byte:02x}"))?; + } + + for byte in bytes { + f.write_fmt(format_args!(" {byte:02x}"))?; + } + + f.write_char(']') + } +} + // ===== impl Visit ===== impl<'a, 'b> Visit for fmt::DebugStruct<'a, 'b> { @@ -443,6 +468,14 @@ impl Value for str { } } +impl crate::sealed::Sealed for [u8] {} + +impl Value for [u8] { + fn record(&self, key: &Field, visitor: &mut dyn Visit) { + visitor.record_bytes(key, self) + } +} + #[cfg(feature = "std")] impl crate::sealed::Sealed for dyn std::error::Error + 'static {} @@ -713,9 +746,9 @@ impl FieldSet { /// Returns the [`Field`] named `name`, or `None` if no such field exists. /// /// [`Field`]: super::Field - pub fn field(&self, name: &Q) -> Option + pub fn field(&self, name: &Q) -> Option where - Q: Borrow, + Q: Borrow + ?Sized, { let name = &name.borrow(); self.names.iter().position(|f| f == name).map(|i| Field { @@ -1131,4 +1164,23 @@ mod test { }); assert_eq!(result, format!("{}", err)); } + + #[test] + fn record_bytes() { + let fields = TEST_META_1.fields(); + let first = &b"abc"[..]; + let second: &[u8] = &[192, 255, 238]; + let values = &[ + (&fields.field("foo").unwrap(), Some(&first as &dyn Value)), + (&fields.field("bar").unwrap(), Some(&" " as &dyn Value)), + (&fields.field("baz").unwrap(), Some(&second as &dyn Value)), + ]; + let valueset = fields.value_set(values); + let mut result = String::new(); + valueset.record(&mut |_: &Field, value: &dyn fmt::Debug| { + use core::fmt::Write; + write!(&mut result, "{:?}", value).unwrap(); + }); + assert_eq!(result, format!("{}", r#"[61 62 63]" "[c0 ff ee]"#)); + } } diff --git a/tracing-subscriber/Cargo.toml b/tracing-subscriber/Cargo.toml index 524bf4b482..92efbff841 100644 --- a/tracing-subscriber/Cargo.toml +++ b/tracing-subscriber/Cargo.toml @@ -70,7 +70,7 @@ tracing = { path = "../tracing", version = "0.2" } tracing-mock = { path = "../tracing-mock", features = ["tracing-subscriber"] } log = "0.4.17" tracing-log = { path = "../tracing-log", version = "0.2" } -criterion = { version = "0.3.6", default_features = false } +criterion = { version = "0.3.6", default-features = false } regex = { version = "1.6.0", default-features = false, features = ["std"] } tracing-futures = { path = "../tracing-futures", version = "0.3", default-features = false, features = ["std-future", "std"] } tokio = { version = "1.20.0", features = ["rt", "macros"] } diff --git a/tracing-subscriber/src/filter/env/field.rs b/tracing-subscriber/src/filter/env/field.rs index 211d2bded9..d6d97afe3b 100644 --- a/tracing-subscriber/src/filter/env/field.rs +++ b/tracing-subscriber/src/filter/env/field.rs @@ -267,7 +267,7 @@ impl fmt::Display for ValueMatch { match self { ValueMatch::Bool(ref inner) => fmt::Display::fmt(inner, f), ValueMatch::F64(ref inner) => fmt::Display::fmt(inner, f), - ValueMatch::NaN => fmt::Display::fmt(&std::f64::NAN, f), + ValueMatch::NaN => fmt::Display::fmt(&f64::NAN, f), ValueMatch::I64(ref inner) => fmt::Display::fmt(inner, f), ValueMatch::U64(ref inner) => fmt::Display::fmt(inner, f), ValueMatch::Debug(ref inner) => fmt::Display::fmt(inner, f), @@ -507,7 +507,7 @@ impl<'a> Visit for MatchVisitor<'a> { matched.store(true, Release); } Some((ValueMatch::F64(ref e), ref matched)) - if (value - *e).abs() < std::f64::EPSILON => + if (value - *e).abs() < f64::EPSILON => { matched.store(true, Release); } diff --git a/tracing-subscriber/src/fmt/format/json.rs b/tracing-subscriber/src/fmt/format/json.rs index f4e61fb123..1f045d93b5 100644 --- a/tracing-subscriber/src/fmt/format/json.rs +++ b/tracing-subscriber/src/fmt/format/json.rs @@ -488,6 +488,11 @@ impl<'a> field::Visit for JsonVisitor<'a> { .insert(field.name(), serde_json::Value::from(value)); } + fn record_bytes(&mut self, field: &Field, value: &[u8]) { + self.values + .insert(field.name(), serde_json::Value::from(value)); + } + fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { match field.name() { // Skip fields that are actually log metadata that have already been handled @@ -528,13 +533,19 @@ mod test { #[test] fn json() { let expected = - "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":42,\"name\":\"json_span\",\"number\":3},\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3}],\"target\":\"tracing_subscriber::fmt::format::json::test\",\"fields\":{\"message\":\"some json test\"}}\n"; + "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":42,\"name\":\"json_span\",\"number\":3,\"slice\":[97,98,99]},\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3,\"slice\":[97,98,99]}],\"target\":\"tracing_subscriber::fmt::format::json::test\",\"fields\":{\"message\":\"some json test\"}}\n"; let collector = collector() .flatten_event(false) .with_current_span(true) .with_span_list(true); test_json(expected, collector, || { - let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3); + let span = tracing::span!( + tracing::Level::INFO, + "json_span", + answer = 42, + number = 3, + slice = &b"abc"[..] + ); let _guard = span.enter(); tracing::info!("some json test"); }); diff --git a/tracing-subscriber/src/fmt/time/datetime.rs b/tracing-subscriber/src/fmt/time/datetime.rs index a39d2ef19c..e7f58f9890 100644 --- a/tracing-subscriber/src/fmt/time/datetime.rs +++ b/tracing-subscriber/src/fmt/time/datetime.rs @@ -247,12 +247,12 @@ impl From for DateTime { fn from(timestamp: std::time::SystemTime) -> DateTime { let (t, nanos) = match timestamp.duration_since(std::time::UNIX_EPOCH) { Ok(duration) => { - debug_assert!(duration.as_secs() <= std::i64::MAX as u64); + debug_assert!(duration.as_secs() <= i64::MAX as u64); (duration.as_secs() as i64, duration.subsec_nanos()) } Err(error) => { let duration = error.duration(); - debug_assert!(duration.as_secs() <= std::i64::MAX as u64); + debug_assert!(duration.as_secs() <= i64::MAX as u64); let (secs, nanos) = (duration.as_secs() as i64, duration.subsec_nanos()); if nanos == 0 { (-secs, 0) @@ -332,7 +332,6 @@ impl From for DateTime { #[cfg(test)] mod tests { - use std::i32; use std::time::{Duration, UNIX_EPOCH}; use super::*; @@ -382,8 +381,8 @@ mod tests { 1, ); - case("2038-01-19T03:14:07.000000Z", std::i32::MAX as i64, 0); - case("2038-01-19T03:14:08.000000Z", std::i32::MAX as i64 + 1, 0); + case("2038-01-19T03:14:07.000000Z", i32::MAX as i64, 0); + case("2038-01-19T03:14:08.000000Z", i32::MAX as i64 + 1, 0); case("1901-12-13T20:45:52.000000Z", i32::MIN as i64, 0); case("1901-12-13T20:45:51.000000Z", i32::MIN as i64 - 1, 0); @@ -392,8 +391,8 @@ mod tests { // high date value tests to panic #[cfg(not(target_os = "windows"))] { - case("+292277026596-12-04T15:30:07.000000Z", std::i64::MAX, 0); - case("+292277026596-12-04T15:30:06.000000Z", std::i64::MAX - 1, 0); + case("+292277026596-12-04T15:30:07.000000Z", i64::MAX, 0); + case("+292277026596-12-04T15:30:06.000000Z", i64::MAX - 1, 0); case("-292277022657-01-27T08:29:53.000000Z", i64::MIN + 1, 0); } diff --git a/tracing-subscriber/src/lib.rs b/tracing-subscriber/src/lib.rs index 4b1ce72d82..8f390e19e6 100644 --- a/tracing-subscriber/src/lib.rs +++ b/tracing-subscriber/src/lib.rs @@ -210,7 +210,11 @@ feature! { #![all(feature = "registry", feature = "std")] pub use registry::Registry; + /// Creates a default [`Registry`], a [`Collect`](tracing_core::Collect) + /// implementation which tracks per-span data and exposes it to + /// [`Subscribe`]s. /// + /// For more information see [`Registry`]. pub fn registry() -> Registry { Registry::default() } diff --git a/tracing-subscriber/src/registry/sharded.rs b/tracing-subscriber/src/registry/sharded.rs index c915109fe5..0ebcdf9a58 100644 --- a/tracing-subscriber/src/registry/sharded.rs +++ b/tracing-subscriber/src/registry/sharded.rs @@ -348,7 +348,7 @@ impl Collect for Registry { let refs = span.ref_count.fetch_sub(1, Ordering::Release); if !std::thread::panicking() { - assert!(refs < std::usize::MAX, "reference count overflow!"); + assert!(refs < usize::MAX, "reference count overflow!"); } if refs > 1 { return false; @@ -541,10 +541,6 @@ mod tests { Collect, }; - #[derive(Debug)] - struct DoesNothing; - impl Subscribe for DoesNothing {} - struct AssertionSubscriber; impl Subscribe for AssertionSubscriber where diff --git a/tracing/Cargo.toml b/tracing/Cargo.toml index f01783c293..a653458fab 100644 --- a/tracing/Cargo.toml +++ b/tracing/Cargo.toml @@ -37,8 +37,8 @@ tracing-attributes = { path = "../tracing-attributes", version = "0.2", optional pin-project-lite = "0.2.9" [dev-dependencies] -criterion = { version = "0.3.6", default_features = false } -futures = { version = "0.3.21", default_features = false } +criterion = { version = "0.3.6", default-features = false } +futures = { version = "0.3.21", default-features = false } log = "0.4.17" tracing-mock = { path = "../tracing-mock" } diff --git a/tracing/src/span.rs b/tracing/src/span.rs index ed58997b5a..fe69683171 100644 --- a/tracing/src/span.rs +++ b/tracing/src/span.rs @@ -1105,9 +1105,9 @@ impl Span { /// Returns a [`Field`](super::field::Field) for the field with the /// given `name`, if one exists, - pub fn field(&self, field: &Q) -> Option + pub fn field(&self, field: &Q) -> Option where - Q: field::AsField, + Q: field::AsField + ?Sized, { self.metadata().and_then(|meta| field.as_field(meta)) } @@ -1115,9 +1115,9 @@ impl Span { /// Returns true if this `Span` has a field for the given /// [`Field`](super::field::Field) or field name. #[inline] - pub fn has_field(&self, field: &Q) -> bool + pub fn has_field(&self, field: &Q) -> bool where - Q: field::AsField, + Q: field::AsField + ?Sized, { self.field(field).is_some() } @@ -1193,9 +1193,9 @@ impl Span { /// /// [`field::Empty`]: super::field::Empty /// [`Metadata`]: super::Metadata - pub fn record(&self, field: &Q, value: V) -> &Self + pub fn record(&self, field: &Q, value: V) -> &Self where - Q: field::AsField, + Q: field::AsField + ?Sized, V: field::Value, { if let Some(meta) = self.meta { @@ -1594,9 +1594,11 @@ unsafe impl Sync for PhantomNotSend {} mod test { use super::*; + #[allow(dead_code)] trait AssertSend: Send {} impl AssertSend for Span {} + #[allow(dead_code)] trait AssertSync: Sync {} impl AssertSync for Span {} impl AssertSync for Entered<'_> {}