Skip to content

Commit 9830f1f

Browse files
committed
tracing::instrument args by autoref specialization
1 parent a2ddc7b commit 9830f1f

File tree

5 files changed

+76
-108
lines changed

5 files changed

+76
-108
lines changed

tracing-attributes/src/expand.rs

Lines changed: 14 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -92,17 +92,12 @@ fn gen_block<B: ToTokens>(
9292
let span = (|| {
9393
// Pull out the arguments-to-be-skipped first, so we can filter results
9494
// below.
95-
let param_names: Vec<(Ident, (Ident, RecordType))> = params
95+
let param_names: Vec<(Ident, Ident)> = params
9696
.clone()
9797
.into_iter()
9898
.flat_map(|param| match param {
99-
FnArg::Typed(PatType { pat, ty, .. }) => {
100-
param_names(*pat, RecordType::parse_from_ty(&*ty))
101-
}
102-
FnArg::Receiver(_) => Box::new(iter::once((
103-
Ident::new("self", param.span()),
104-
RecordType::Debug,
105-
))),
99+
FnArg::Typed(PatType { pat, .. }) => param_names(*pat),
100+
FnArg::Receiver(_) => Box::new(iter::once(Ident::new("self", param.span()))),
106101
})
107102
// Little dance with new (user-exposed) names and old (internal)
108103
// names of identifiers. That way, we could do the following
@@ -114,13 +109,13 @@ fn gen_block<B: ToTokens>(
114109
// async fn foo(&self, v: usize) {}
115110
// }
116111
// ```
117-
.map(|(x, record_type)| {
112+
.map(|x| {
118113
// if we are inside a function generated by async-trait <=0.1.43, we need to
119114
// take care to rewrite "_self" as "self" for 'user convenience'
120115
if self_type.is_some() && x == "_self" {
121-
(Ident::new("self", x.span()), (x, record_type))
116+
(Ident::new("self", x.span()), x)
122117
} else {
123-
(x.clone(), (x, record_type))
118+
(x.clone(), x)
124119
}
125120
})
126121
.collect();
@@ -154,16 +149,13 @@ fn gen_block<B: ToTokens>(
154149
true
155150
}
156151
})
157-
.map(|(user_name, (real_name, record_type))| match record_type {
158-
RecordType::Value => quote!(#user_name = #real_name),
159-
RecordType::Debug => quote!(#user_name = tracing::field::debug(&#real_name)),
160-
})
152+
.map(|(user_name, real_name)| quote!(#user_name = tracing::__tracing_capture_value!(#real_name)))
161153
.collect();
162154

163155
// replace every use of a variable with its original name
164156
if let Some(Fields(ref mut fields)) = args.fields {
165157
let mut replacer = IdentAndTypesRenamer {
166-
idents: param_names.into_iter().map(|(a, (b, _))| (a, b)).collect(),
158+
idents: param_names,
167159
types: Vec::new(),
168160
};
169161

@@ -284,95 +276,24 @@ fn gen_block<B: ToTokens>(
284276
)
285277
}
286278

287-
/// Indicates whether a field should be recorded as `Value` or `Debug`.
288-
enum RecordType {
289-
/// The field should be recorded using its `Value` implementation.
290-
Value,
291-
/// The field should be recorded using `tracing::field::debug()`.
292-
Debug,
293-
}
294-
295-
impl RecordType {
296-
/// Array of primitive types which should be recorded as [RecordType::Value].
297-
const TYPES_FOR_VALUE: &'static [&'static str] = &[
298-
"bool",
299-
"str",
300-
"u8",
301-
"i8",
302-
"u16",
303-
"i16",
304-
"u32",
305-
"i32",
306-
"u64",
307-
"i64",
308-
"f32",
309-
"f64",
310-
"usize",
311-
"isize",
312-
"NonZeroU8",
313-
"NonZeroI8",
314-
"NonZeroU16",
315-
"NonZeroI16",
316-
"NonZeroU32",
317-
"NonZeroI32",
318-
"NonZeroU64",
319-
"NonZeroI64",
320-
"NonZeroUsize",
321-
"NonZeroIsize",
322-
"Wrapping",
323-
];
324-
325-
/// Parse `RecordType` from [syn::Type] by looking up
326-
/// the [RecordType::TYPES_FOR_VALUE] array.
327-
fn parse_from_ty(ty: &syn::Type) -> Self {
328-
match ty {
329-
syn::Type::Path(syn::TypePath { path, .. })
330-
if path
331-
.segments
332-
.iter()
333-
.last()
334-
.map(|path_segment| {
335-
let ident = path_segment.ident.to_string();
336-
Self::TYPES_FOR_VALUE.iter().any(|&t| t == ident)
337-
})
338-
.unwrap_or(false) =>
339-
{
340-
RecordType::Value
341-
}
342-
syn::Type::Reference(syn::TypeReference { elem, .. }) => {
343-
RecordType::parse_from_ty(&*elem)
344-
}
345-
_ => RecordType::Debug,
346-
}
347-
}
348-
}
349-
350-
fn param_names(pat: Pat, record_type: RecordType) -> Box<dyn Iterator<Item = (Ident, RecordType)>> {
279+
fn param_names(pat: Pat) -> Box<dyn Iterator<Item = Ident>> {
351280
match pat {
352-
Pat::Ident(PatIdent { ident, .. }) => Box::new(iter::once((ident, record_type))),
353-
Pat::Reference(PatReference { pat, .. }) => param_names(*pat, record_type),
281+
Pat::Ident(PatIdent { ident, .. }) => Box::new(iter::once(ident)),
282+
Pat::Reference(PatReference { pat, .. }) => param_names(*pat),
354283
// We can't get the concrete type of fields in the struct/tuple
355284
// patterns by using `syn`. e.g. `fn foo(Foo { x, y }: Foo) {}`.
356285
// Therefore, the struct/tuple patterns in the arguments will just
357286
// always be recorded as `RecordType::Debug`.
358287
Pat::Struct(PatStruct { fields, .. }) => Box::new(
359288
fields
360289
.into_iter()
361-
.flat_map(|FieldPat { pat, .. }| param_names(*pat, RecordType::Debug)),
362-
),
363-
Pat::Tuple(PatTuple { elems, .. }) => Box::new(
364-
elems
365-
.into_iter()
366-
.flat_map(|p| param_names(p, RecordType::Debug)),
290+
.flat_map(|FieldPat { pat, .. }| param_names(*pat)),
367291
),
292+
Pat::Tuple(PatTuple { elems, .. }) => Box::new(elems.into_iter().flat_map(param_names)),
368293
Pat::TupleStruct(PatTupleStruct {
369294
pat: PatTuple { elems, .. },
370295
..
371-
}) => Box::new(
372-
elems
373-
.into_iter()
374-
.flat_map(|p| param_names(p, RecordType::Debug)),
375-
),
296+
}) => Box::new(elems.into_iter().flat_map(param_names)),
376297

377298
// The above *should* cover all cases of irrefutable patterns,
378299
// 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
@@ -964,7 +964,8 @@ pub use self::span::Span;
964964
pub use tracing_attributes::instrument;
965965

966966
#[macro_use]
967-
mod macros;
967+
#[doc(hidden)]
968+
pub mod macros;
968969

969970
pub mod collect;
970971
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)