mirror of
https://github.com/tokio-rs/tracing.git
synced 2025-10-02 15:24:47 +00:00
core: support Wrapping
and NonZero
types as Value
s (#538)
## Motivation For tracing there's no difference between a `NonZero*` or `Wrapping` type and their underlying type. This allows such types to directly be referenced by the tracing macros without requiring additional method calls or boilerplate. ## Solution Implemented `Value` for `Wrapping<T: Value>` and for all the `NonZero*` types from `std::num`. This required a slight refactoring of the macros generating the regular integer impls as to reduce the amount of generated code.
This commit is contained in:
parent
ed7e5a7624
commit
c5972d8447
@ -42,6 +42,7 @@ use crate::stdlib::{
|
||||
borrow::Borrow,
|
||||
fmt,
|
||||
hash::{Hash, Hasher},
|
||||
num,
|
||||
ops::Range,
|
||||
};
|
||||
|
||||
@ -276,33 +277,88 @@ macro_rules! impl_values {
|
||||
)+
|
||||
}
|
||||
}
|
||||
macro_rules! impl_value {
|
||||
( $record:ident( $( $value_ty:ty ),+ ) ) => {
|
||||
$(
|
||||
impl $crate::sealed::Sealed for $value_ty {}
|
||||
impl $crate::field::Value for $value_ty {
|
||||
fn record(
|
||||
&self,
|
||||
key: &$crate::field::Field,
|
||||
visitor: &mut dyn $crate::field::Visit,
|
||||
) {
|
||||
visitor.$record(key, *self)
|
||||
}
|
||||
|
||||
macro_rules! ty_to_nonzero {
|
||||
(u8) => {
|
||||
NonZeroU8
|
||||
};
|
||||
(u16) => {
|
||||
NonZeroU16
|
||||
};
|
||||
(u32) => {
|
||||
NonZeroU32
|
||||
};
|
||||
(u64) => {
|
||||
NonZeroU64
|
||||
};
|
||||
(u128) => {
|
||||
NonZeroU128
|
||||
};
|
||||
(usize) => {
|
||||
NonZeroUsize
|
||||
};
|
||||
(i8) => {
|
||||
NonZeroI8
|
||||
};
|
||||
(i16) => {
|
||||
NonZeroI16
|
||||
};
|
||||
(i32) => {
|
||||
NonZeroI32
|
||||
};
|
||||
(i64) => {
|
||||
NonZeroI64
|
||||
};
|
||||
(i128) => {
|
||||
NonZeroI128
|
||||
};
|
||||
(isize) => {
|
||||
NonZeroIsize
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_one_value {
|
||||
(bool, $op:expr, $record:ident) => {
|
||||
impl_one_value!(normal, bool, $op, $record);
|
||||
};
|
||||
($value_ty:tt, $op:expr, $record:ident) => {
|
||||
impl_one_value!(normal, $value_ty, $op, $record);
|
||||
impl_one_value!(nonzero, $value_ty, $op, $record);
|
||||
};
|
||||
(normal, $value_ty:tt, $op:expr, $record:ident) => {
|
||||
impl $crate::sealed::Sealed for $value_ty {}
|
||||
impl $crate::field::Value for $value_ty {
|
||||
fn record(&self, key: &$crate::field::Field, visitor: &mut dyn $crate::field::Visit) {
|
||||
visitor.$record(key, $op(*self))
|
||||
}
|
||||
}
|
||||
};
|
||||
(nonzero, $value_ty:tt, $op:expr, $record:ident) => {
|
||||
// This `use num::*;` is reported as unused because it gets emitted
|
||||
// for every single invocation of this macro, so there are multiple `use`s.
|
||||
// All but the first are useless indeed.
|
||||
// We need this import because we can't write a path where one part is
|
||||
// the `ty_to_nonzero!($value_ty)` invocation.
|
||||
#[allow(clippy::useless_attribute, unused)]
|
||||
use num::*;
|
||||
impl $crate::sealed::Sealed for ty_to_nonzero!($value_ty) {}
|
||||
impl $crate::field::Value for ty_to_nonzero!($value_ty) {
|
||||
fn record(&self, key: &$crate::field::Field, visitor: &mut dyn $crate::field::Visit) {
|
||||
visitor.$record(key, $op(self.get()))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_value {
|
||||
( $record:ident( $( $value_ty:tt ),+ ) ) => {
|
||||
$(
|
||||
impl_one_value!($value_ty, |this: $value_ty| this, $record);
|
||||
)+
|
||||
};
|
||||
( $record:ident( $( $value_ty:ty ),+ as $as_ty:ty) ) => {
|
||||
( $record:ident( $( $value_ty:tt ),+ as $as_ty:ty) ) => {
|
||||
$(
|
||||
impl $crate::sealed::Sealed for $value_ty {}
|
||||
impl Value for $value_ty {
|
||||
fn record(
|
||||
&self,
|
||||
key: &$crate::field::Field,
|
||||
visitor: &mut dyn $crate::field::Visit,
|
||||
) {
|
||||
visitor.$record(key, *self as $as_ty)
|
||||
}
|
||||
}
|
||||
impl_one_value!($value_ty, |this: $value_ty| this as $as_ty, $record);
|
||||
)+
|
||||
};
|
||||
}
|
||||
@ -317,6 +373,13 @@ impl_values! {
|
||||
record_bool(bool)
|
||||
}
|
||||
|
||||
impl<T: crate::sealed::Sealed> crate::sealed::Sealed for Wrapping<T> {}
|
||||
impl<T: crate::field::Value> crate::field::Value for Wrapping<T> {
|
||||
fn record(&self, key: &crate::field::Field, visitor: &mut dyn crate::field::Visit) {
|
||||
self.0.record(key, visitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::sealed::Sealed for str {}
|
||||
|
||||
impl Value for str {
|
||||
|
@ -27,7 +27,7 @@ keywords = ["logging", "tracing", "metrics", "async"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
tracing-core = { version = "0.1.9", default-features = false }
|
||||
tracing-core = { path = "../tracing-core", version = "0.1.9", default-features = false }
|
||||
log = { version = "0.4", optional = true }
|
||||
tracing-attributes = "0.1.6"
|
||||
cfg-if = "0.1.10"
|
||||
|
@ -33,6 +33,12 @@ fn test_always_log() {
|
||||
error!(foo = 5);
|
||||
test.assert_logged("foo=5");
|
||||
|
||||
error!(foo = std::num::NonZeroU16::new(42).unwrap());
|
||||
test.assert_logged("foo=42");
|
||||
|
||||
error!(foo = std::num::Wrapping(39));
|
||||
test.assert_logged("foo=39");
|
||||
|
||||
warn!("hello {};", "world");
|
||||
test.assert_logged("hello world;");
|
||||
|
||||
|
@ -18,33 +18,43 @@ use tracing::{
|
||||
Level,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn event_without_message() {
|
||||
let (subscriber, handle) = subscriber::mock()
|
||||
.event(
|
||||
event::mock().with_fields(
|
||||
field::mock("answer")
|
||||
.with_value(&42)
|
||||
.and(
|
||||
field::mock("to_question")
|
||||
.with_value(&"life, the universe, and everything"),
|
||||
)
|
||||
.only(),
|
||||
),
|
||||
)
|
||||
.done()
|
||||
.run_with_handle();
|
||||
macro_rules! event_without_message {
|
||||
($name:ident: $e:expr) => {
|
||||
#[test]
|
||||
fn $name() {
|
||||
let (subscriber, handle) = subscriber::mock()
|
||||
.event(
|
||||
event::mock().with_fields(
|
||||
field::mock("answer")
|
||||
.with_value(&42)
|
||||
.and(
|
||||
field::mock("to_question")
|
||||
.with_value(&"life, the universe, and everything"),
|
||||
)
|
||||
.only(),
|
||||
),
|
||||
)
|
||||
.done()
|
||||
.run_with_handle();
|
||||
|
||||
with_default(subscriber, || {
|
||||
info!(
|
||||
answer = 42,
|
||||
to_question = "life, the universe, and everything"
|
||||
);
|
||||
});
|
||||
with_default(subscriber, || {
|
||||
info!(
|
||||
answer = $e,
|
||||
to_question = "life, the universe, and everything"
|
||||
);
|
||||
});
|
||||
|
||||
handle.assert_finished();
|
||||
handle.assert_finished();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
event_without_message! {event_without_message: 42}
|
||||
event_without_message! {wrapping_event_without_message: std::num::Wrapping(42)}
|
||||
event_without_message! {nonzeroi32_event_without_message: std::num::NonZeroI32::new(42).unwrap()}
|
||||
// needs API breakage
|
||||
//event_without_message!{nonzerou128_event_without_message: std::num::NonZeroU128::new(42).unwrap()}
|
||||
|
||||
#[test]
|
||||
fn event_with_message() {
|
||||
let (subscriber, handle) = subscriber::mock()
|
||||
|
Loading…
x
Reference in New Issue
Block a user