Skip to content

Commit d6505ca

Browse files
matildasmedshds
andauthored
tracing: add record_all! macro for recording multiple values in one call (#3227)
## Motivation Currently, Span.record_all() is part of the public API and accepts ValueSet as a parameter. However, constructing a ValueSet is both verbose and undocumented, making it not so practical. ## Solution To make recording multiple values easier, we introduce a new macro: record_all!, which wraps the Span.record_all() function. As we don't intend anyone to call Span.record_all() directly, we hide it from the documentation. We reference the new macro from Span.record() doc comment instead. The new record_all! macro supports optional formatting sigils % and ?, ensuring a consistent DevEx with the other value-recording macros. Co-authored-by: Hayden Stainsby <[email protected]>
1 parent c400b75 commit d6505ca

File tree

3 files changed

+82
-2
lines changed

3 files changed

+82
-2
lines changed

tracing/src/macros.rs

+30
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,36 @@ macro_rules! span {
131131
};
132132
}
133133

134+
/// Records multiple values on a span in a single call. As with recording
135+
/// individual values, all fields must be declared when the span is created.
136+
///
137+
/// This macro supports two optional sigils:
138+
/// - `%` uses the Display implementation.
139+
/// - `?` uses the Debug implementation.
140+
///
141+
/// For more details, see the [top-level documentation][lib].
142+
///
143+
/// [lib]: tracing/#recording-fields
144+
///
145+
/// # Examples
146+
///
147+
/// ```
148+
/// # use tracing::{field, info_span, record_all};
149+
/// let span = info_span!("my span", field1 = field::Empty, field2 = field::Empty, field3 = field::Empty).entered();
150+
/// record_all!(span, field1 = ?"1", field2 = %"2", field3 = 3);
151+
/// ```
152+
#[macro_export]
153+
macro_rules! record_all {
154+
($span:expr, $($fields:tt)*) => {
155+
if let Some(meta) = $span.metadata() {
156+
$span.record_all(&$crate::valueset!(
157+
meta.fields(),
158+
$($fields)*
159+
));
160+
}
161+
};
162+
}
163+
134164
/// Constructs a span at the trace level.
135165
///
136166
/// [Fields] and [attributes] are set using the same syntax as the [`span!`]

tracing/src/span.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,11 @@ impl Span {
11911191
/// span.record("parting", "you will be remembered");
11921192
/// ```
11931193
///
1194+
/// <div class="example-wrap" style="display:inline-block">
1195+
/// <pre class="ignore" style="white-space:normal;font:inherit;">
1196+
/// **Note**: To record several values in just one call, see the [`record_all!`](crate::record_all!) macro.
1197+
/// </pre></div>
1198+
///
11941199
/// [`field::Empty`]: super::field::Empty
11951200
/// [`Metadata`]: super::Metadata
11961201
pub fn record<Q, V>(&self, field: &Q, value: V) -> &Self
@@ -1212,6 +1217,7 @@ impl Span {
12121217
}
12131218

12141219
/// Records all the fields in the provided `ValueSet`.
1220+
#[doc(hidden)]
12151221
pub fn record_all(&self, values: &field::ValueSet<'_>) -> &Self {
12161222
let record = Record::new(values);
12171223
if let Some(ref inner) = self.inner {

tracing/tests/span.rs

+46-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use std::thread;
88
use tracing::{
99
collect::with_default,
1010
error_span,
11-
field::{debug, display},
12-
Level, Span,
11+
field::{debug, display, Empty},
12+
record_all, Level, Span,
1313
};
1414
use tracing_mock::*;
1515

@@ -612,6 +612,50 @@ fn record_new_values_for_fields() {
612612
handle.assert_finished();
613613
}
614614

615+
/// Tests record_all! macro, which is a wrapper for Span.record_all().
616+
/// Placed here instead of tests/macros.rs, because it uses tracing_mock, which
617+
/// requires std lib. Other macro tests exclude std lib to verify the macros do
618+
/// not dependend on it.
619+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
620+
#[test]
621+
fn record_all_macro_records_new_values_for_fields() {
622+
let (collector, handle) = collector::mock()
623+
.new_span(
624+
expect::span()
625+
.named("foo")
626+
.with_fields(expect::field("bar")),
627+
)
628+
.record(
629+
expect::span().named("foo"),
630+
expect::field("bar")
631+
.with_value(&5)
632+
.and(expect::field("baz").with_value(&"BAZ"))
633+
.and(expect::field("qux").with_value(&display("qux")))
634+
.and(expect::field("quux").with_value(&debug("QuuX")))
635+
.only(),
636+
)
637+
.enter(expect::span().named("foo"))
638+
.exit(expect::span().named("foo"))
639+
.drop_span(expect::span().named("foo"))
640+
.only()
641+
.run_with_handle();
642+
643+
with_default(collector, || {
644+
let span = tracing::span!(
645+
Level::TRACE,
646+
"foo",
647+
bar = 1,
648+
baz = 2,
649+
qux = Empty,
650+
quux = Empty
651+
);
652+
record_all!(span, bar = 5, baz = "BAZ", qux = %"qux", quux = ?"QuuX");
653+
span.in_scope(|| {})
654+
});
655+
656+
handle.assert_finished();
657+
}
658+
615659
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
616660
#[test]
617661
fn new_span_with_target_and_log_level() {

0 commit comments

Comments
 (0)