Skip to content

Commit 513e600

Browse files
committed
tracing::instrument args by autoref specialization
1 parent 0fa74b9 commit 513e600

File tree

5 files changed

+76
-112
lines changed

5 files changed

+76
-112
lines changed

tracing-attributes/src/lib.rs

Lines changed: 14 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -409,17 +409,12 @@ fn gen_block(
409409
let span = (|| {
410410
// Pull out the arguments-to-be-skipped first, so we can filter results
411411
// below.
412-
let param_names: Vec<(Ident, (Ident, RecordType))> = params
412+
let param_names: Vec<(Ident, Ident)> = params
413413
.clone()
414414
.into_iter()
415415
.flat_map(|param| match param {
416-
FnArg::Typed(PatType { pat, ty, .. }) => {
417-
param_names(*pat, RecordType::parse_from_ty(&*ty))
418-
}
419-
FnArg::Receiver(_) => Box::new(iter::once((
420-
Ident::new("self", param.span()),
421-
RecordType::Debug,
422-
))),
416+
FnArg::Typed(PatType { pat, .. }) => param_names(*pat),
417+
FnArg::Receiver(_) => Box::new(iter::once(Ident::new("self", param.span()))),
423418
})
424419
// Little dance with new (user-exposed) names and old (internal)
425420
// names of identifiers. That way, we could do the following
@@ -431,13 +426,13 @@ fn gen_block(
431426
// async fn foo(&self, v: usize) {}
432427
// }
433428
// ```
434-
.map(|(x, record_type)| {
429+
.map(|x| {
435430
// if we are inside a function generated by async-trait <=0.1.43, we need to
436431
// take care to rewrite "_self" as "self" for 'user convenience'
437432
if self_type.is_some() && x == "_self" {
438-
(Ident::new("self", x.span()), (x, record_type))
433+
(Ident::new("self", x.span()), (x))
439434
} else {
440-
(x.clone(), (x, record_type))
435+
(x.clone(), (x))
441436
}
442437
})
443438
.collect();
@@ -471,16 +466,13 @@ fn gen_block(
471466
true
472467
}
473468
})
474-
.map(|(user_name, (real_name, record_type))| match record_type {
475-
RecordType::Value => quote!(#user_name = #real_name),
476-
RecordType::Debug => quote!(#user_name = tracing::field::debug(&#real_name)),
477-
})
469+
.map(|(user_name, real_name)| quote!(#user_name = tracing::__tracing_capture_value!(#real_name)))
478470
.collect();
479471

480472
// replace every use of a variable with its original name
481473
if let Some(Fields(ref mut fields)) = args.fields {
482474
let mut replacer = IdentAndTypesRenamer {
483-
idents: param_names.into_iter().map(|(a, (b, _))| (a, b)).collect(),
475+
idents: param_names.into_iter().map(|(a, b)| (a, b)).collect(),
484476
types: Vec::new(),
485477
};
486478

@@ -897,95 +889,20 @@ impl Parse for Level {
897889
}
898890
}
899891

900-
/// Indicates whether a field should be recorded as `Value` or `Debug`.
901-
enum RecordType {
902-
/// The field should be recorded using its `Value` implementation.
903-
Value,
904-
/// The field should be recorded using `tracing::field::debug()`.
905-
Debug,
906-
}
907-
908-
impl RecordType {
909-
/// Array of primitive types which should be recorded as [RecordType::Value].
910-
const TYPES_FOR_VALUE: &'static [&'static str] = &[
911-
"bool",
912-
"str",
913-
"u8",
914-
"i8",
915-
"u16",
916-
"i16",
917-
"u32",
918-
"i32",
919-
"u64",
920-
"i64",
921-
"f32",
922-
"f64",
923-
"usize",
924-
"isize",
925-
"NonZeroU8",
926-
"NonZeroI8",
927-
"NonZeroU16",
928-
"NonZeroI16",
929-
"NonZeroU32",
930-
"NonZeroI32",
931-
"NonZeroU64",
932-
"NonZeroI64",
933-
"NonZeroUsize",
934-
"NonZeroIsize",
935-
"Wrapping",
936-
];
937-
938-
/// Parse `RecordType` from [syn::Type] by looking up
939-
/// the [RecordType::TYPES_FOR_VALUE] array.
940-
fn parse_from_ty(ty: &syn::Type) -> Self {
941-
match ty {
942-
syn::Type::Path(syn::TypePath { path, .. })
943-
if path
944-
.segments
945-
.iter()
946-
.last()
947-
.map(|path_segment| {
948-
let ident = path_segment.ident.to_string();
949-
Self::TYPES_FOR_VALUE.iter().any(|&t| t == ident)
950-
})
951-
.unwrap_or(false) =>
952-
{
953-
RecordType::Value
954-
}
955-
syn::Type::Reference(syn::TypeReference { elem, .. }) => {
956-
RecordType::parse_from_ty(&*elem)
957-
}
958-
_ => RecordType::Debug,
959-
}
960-
}
961-
}
962-
963-
fn param_names(pat: Pat, record_type: RecordType) -> Box<dyn Iterator<Item = (Ident, RecordType)>> {
892+
fn param_names(pat: Pat) -> Box<dyn Iterator<Item = Ident>> {
964893
match pat {
965-
Pat::Ident(PatIdent { ident, .. }) => Box::new(iter::once((ident, record_type))),
966-
Pat::Reference(PatReference { pat, .. }) => param_names(*pat, record_type),
967-
// We can't get the concrete type of fields in the struct/tuple
968-
// patterns by using `syn`. e.g. `fn foo(Foo { x, y }: Foo) {}`.
969-
// Therefore, the struct/tuple patterns in the arguments will just
970-
// always be recorded as `RecordType::Debug`.
894+
Pat::Ident(PatIdent { ident, .. }) => Box::new(iter::once(ident)),
895+
Pat::Reference(PatReference { pat, .. }) => param_names(*pat),
971896
Pat::Struct(PatStruct { fields, .. }) => Box::new(
972897
fields
973898
.into_iter()
974-
.flat_map(|FieldPat { pat, .. }| param_names(*pat, RecordType::Debug)),
975-
),
976-
Pat::Tuple(PatTuple { elems, .. }) => Box::new(
977-
elems
978-
.into_iter()
979-
.flat_map(|p| param_names(p, RecordType::Debug)),
899+
.flat_map(|FieldPat { pat, .. }| param_names(*pat)),
980900
),
901+
Pat::Tuple(PatTuple { elems, .. }) => Box::new(elems.into_iter().flat_map(param_names)),
981902
Pat::TupleStruct(PatTupleStruct {
982903
pat: PatTuple { elems, .. },
983904
..
984-
}) => Box::new(
985-
elems
986-
.into_iter()
987-
.flat_map(|p| param_names(p, RecordType::Debug)),
988-
),
905+
}) => Box::new(elems.into_iter().flat_map(param_names)),
989906

990907
// The above *should* cover all cases of irrefutable patterns,
991908
// but we purposefully don't do any funny business here

tracing-attributes/tests/destructuring.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ fn destructure_tuples() {
1515
.new_span(
1616
span.clone().with_field(
1717
field::mock("arg1")
18-
.with_value(&format_args!("1"))
19-
.and(field::mock("arg2").with_value(&format_args!("2")))
18+
.with_value(&1usize)
19+
.and(field::mock("arg2").with_value(&2usize))
2020
.only(),
2121
),
2222
)
@@ -44,10 +44,10 @@ fn destructure_nested_tuples() {
4444
.new_span(
4545
span.clone().with_field(
4646
field::mock("arg1")
47-
.with_value(&format_args!("1"))
48-
.and(field::mock("arg2").with_value(&format_args!("2")))
49-
.and(field::mock("arg3").with_value(&format_args!("3")))
50-
.and(field::mock("arg4").with_value(&format_args!("4")))
47+
.with_value(&1usize)
48+
.and(field::mock("arg2").with_value(&2usize))
49+
.and(field::mock("arg3").with_value(&3usize))
50+
.and(field::mock("arg4").with_value(&4usize))
5151
.only(),
5252
),
5353
)
@@ -102,8 +102,8 @@ fn destructure_tuple_structs() {
102102
.new_span(
103103
span.clone().with_field(
104104
field::mock("arg1")
105-
.with_value(&format_args!("1"))
106-
.and(field::mock("arg2").with_value(&format_args!("2")))
105+
.with_value(&1usize)
106+
.and(field::mock("arg2").with_value(&2usize))
107107
.only(),
108108
),
109109
)
@@ -143,8 +143,8 @@ fn destructure_structs() {
143143
.new_span(
144144
span.clone().with_field(
145145
field::mock("arg1")
146-
.with_value(&format_args!("1"))
147-
.and(field::mock("arg2").with_value(&format_args!("2")))
146+
.with_value(&1usize)
147+
.and(field::mock("arg2").with_value(&2usize))
148148
.only(),
149149
),
150150
)
@@ -188,10 +188,10 @@ fn destructure_everything() {
188188
.new_span(
189189
span.clone().with_field(
190190
field::mock("arg1")
191-
.with_value(&format_args!("1"))
192-
.and(field::mock("arg2").with_value(&format_args!("2")))
193-
.and(field::mock("arg3").with_value(&format_args!("3")))
194-
.and(field::mock("arg4").with_value(&format_args!("4")))
191+
.with_value(&1usize)
192+
.and(field::mock("arg2").with_value(&2usize))
193+
.and(field::mock("arg3").with_value(&3usize))
194+
.and(field::mock("arg4").with_value(&4usize))
195195
.only(),
196196
),
197197
)

tracing-core/src/field.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,10 +238,12 @@ pub trait Value: crate::sealed::Sealed {
238238
/// Uses `record_debug` in the `Value` implementation to
239239
/// avoid an unnecessary evaluation.
240240
#[derive(Clone)]
241+
#[repr(transparent)]
241242
pub struct DisplayValue<T: fmt::Display>(T);
242243

243244
/// A `Value` which serializes as a string using `fmt::Debug`.
244245
#[derive(Clone)]
246+
#[repr(transparent)]
245247
pub struct DebugValue<T: fmt::Debug>(T);
246248

247249
/// Wraps a type implementing `fmt::Display` as a `Value` that can be
@@ -262,6 +264,16 @@ where
262264
DebugValue(t)
263265
}
264266

267+
/// Wraps a type implementing `fmt::Debug` as a `Value` that can be
268+
/// recorded using its `Debug` implementation.
269+
pub fn debug_ref<T>(t: &T) -> &DebugValue<T>
270+
where
271+
T: fmt::Debug,
272+
{
273+
// SAFETY: DebugValue is a repr(transparent) wrapper of T
274+
unsafe { &*(t as *const T as *const DebugValue<T>) }
275+
}
276+
265277
// ===== impl Visit =====
266278

267279
impl<'a, 'b> Visit for fmt::DebugStruct<'a, 'b> {

tracing/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -961,7 +961,8 @@ pub use self::span::Span;
961961
pub use tracing_attributes::instrument;
962962

963963
#[macro_use]
964-
mod macros;
964+
#[doc(hidden)]
965+
pub mod macros;
965966

966967
pub mod collect;
967968
pub mod dispatch;

tracing/src/macros.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2134,6 +2134,40 @@ macro_rules! fieldset {
21342134

21352135
}
21362136

2137+
// autoref specialization level 0
2138+
#[doc(hidden)]
2139+
pub trait TracingCaptureValueByValue {
2140+
fn __tracing_capture_value(&self) -> &dyn crate::field::Value;
2141+
}
2142+
2143+
impl<T: crate::field::Value> TracingCaptureValueByValue for T {
2144+
fn __tracing_capture_value(&self) -> &dyn crate::field::Value {
2145+
self
2146+
}
2147+
}
2148+
2149+
// autoref specialization level 1
2150+
#[doc(hidden)]
2151+
pub trait TracingCaptureValueByDebug {
2152+
fn __tracing_capture_value(&self) -> &dyn crate::field::Value;
2153+
}
2154+
2155+
impl<T: core::fmt::Debug> TracingCaptureValueByDebug for &T {
2156+
fn __tracing_capture_value(&self) -> &dyn crate::field::Value {
2157+
crate::field::debug_ref(self)
2158+
}
2159+
}
2160+
2161+
#[doc(hidden)]
2162+
#[macro_export]
2163+
macro_rules! __tracing_capture_value {
2164+
($e:expr) => {{
2165+
#[allow(unused_imports)]
2166+
use $crate::macros::{TracingCaptureValueByDebug, TracingCaptureValueByValue};
2167+
(&$e).__tracing_capture_value()
2168+
}};
2169+
}
2170+
21372171
#[cfg(feature = "log")]
21382172
#[doc(hidden)]
21392173
#[macro_export]

0 commit comments

Comments
 (0)