mirror of
https://github.com/tokio-rs/tracing.git
synced 2025-10-02 23:34:40 +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,
|
borrow::Borrow,
|
||||||
fmt,
|
fmt,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
|
num,
|
||||||
ops::Range,
|
ops::Range,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -276,33 +277,88 @@ macro_rules! impl_values {
|
|||||||
)+
|
)+
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
macro_rules! impl_value {
|
|
||||||
( $record:ident( $( $value_ty:ty ),+ ) ) => {
|
macro_rules! ty_to_nonzero {
|
||||||
$(
|
(u8) => {
|
||||||
impl $crate::sealed::Sealed for $value_ty {}
|
NonZeroU8
|
||||||
impl $crate::field::Value for $value_ty {
|
};
|
||||||
fn record(
|
(u16) => {
|
||||||
&self,
|
NonZeroU16
|
||||||
key: &$crate::field::Field,
|
};
|
||||||
visitor: &mut dyn $crate::field::Visit,
|
(u32) => {
|
||||||
) {
|
NonZeroU32
|
||||||
visitor.$record(key, *self)
|
};
|
||||||
}
|
(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_one_value!($value_ty, |this: $value_ty| this as $as_ty, $record);
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)+
|
)+
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -317,6 +373,13 @@ impl_values! {
|
|||||||
record_bool(bool)
|
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 crate::sealed::Sealed for str {}
|
||||||
|
|
||||||
impl Value for str {
|
impl Value for str {
|
||||||
|
@ -27,7 +27,7 @@ keywords = ["logging", "tracing", "metrics", "async"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[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 }
|
log = { version = "0.4", optional = true }
|
||||||
tracing-attributes = "0.1.6"
|
tracing-attributes = "0.1.6"
|
||||||
cfg-if = "0.1.10"
|
cfg-if = "0.1.10"
|
||||||
|
@ -33,6 +33,12 @@ fn test_always_log() {
|
|||||||
error!(foo = 5);
|
error!(foo = 5);
|
||||||
test.assert_logged("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");
|
warn!("hello {};", "world");
|
||||||
test.assert_logged("hello world;");
|
test.assert_logged("hello world;");
|
||||||
|
|
||||||
|
@ -18,33 +18,43 @@ use tracing::{
|
|||||||
Level,
|
Level,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
macro_rules! event_without_message {
|
||||||
fn event_without_message() {
|
($name:ident: $e:expr) => {
|
||||||
let (subscriber, handle) = subscriber::mock()
|
#[test]
|
||||||
.event(
|
fn $name() {
|
||||||
event::mock().with_fields(
|
let (subscriber, handle) = subscriber::mock()
|
||||||
field::mock("answer")
|
.event(
|
||||||
.with_value(&42)
|
event::mock().with_fields(
|
||||||
.and(
|
field::mock("answer")
|
||||||
field::mock("to_question")
|
.with_value(&42)
|
||||||
.with_value(&"life, the universe, and everything"),
|
.and(
|
||||||
)
|
field::mock("to_question")
|
||||||
.only(),
|
.with_value(&"life, the universe, and everything"),
|
||||||
),
|
)
|
||||||
)
|
.only(),
|
||||||
.done()
|
),
|
||||||
.run_with_handle();
|
)
|
||||||
|
.done()
|
||||||
|
.run_with_handle();
|
||||||
|
|
||||||
with_default(subscriber, || {
|
with_default(subscriber, || {
|
||||||
info!(
|
info!(
|
||||||
answer = 42,
|
answer = $e,
|
||||||
to_question = "life, the universe, and everything"
|
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]
|
#[test]
|
||||||
fn event_with_message() {
|
fn event_with_message() {
|
||||||
let (subscriber, handle) = subscriber::mock()
|
let (subscriber, handle) = subscriber::mock()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user