Skip to content

Commit 4a8542d

Browse files
authored
tracing: don't require delimiters for format_args (#288)
## Motivation Currently, the `tracing` macros require curly braces as delimiters when a `format_args` macro is used in addition to structured fields, like: ```rust info!({ field1 = value1, field2 = value2 }, "unstructured message"); ``` This is confusing, since the delimiters are not used in other cases; it makes the syntax more complex; and, most importantly, I think it looks kind of ugly. I've been planning to get rid of this when we transition to procedural macros, but the transition is currently blocked on a compiler bug, rust-lang/rust#62325. (see #133 (comment)) I've been getting tired of waiting for this. ## Solution: This branch updates the `tracing` crate's macros to support a format_args message after the structured key-value fields without curly braces. For example, ```rust let yay = "WITHOUT DELIMITERS!!!"; info!(field1 = value1, field2 = value2, "message: {}", yay); ``` I've updated the tests & examples in the `tracing` crate so that they show this usage rather than the old usage. The old form with curly braces is still supported, since removing it would be a breaking change, but we'll transition it out in examples & tutorials. (can you put a `deprecated` attribute on a specific macro arm???). Signed-off-by: Eliza Weisman <[email protected]>
1 parent 215d0ef commit 4a8542d

File tree

7 files changed

+231
-34
lines changed

7 files changed

+231
-34
lines changed

tracing/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ pub fn shave_the_yak(yak: &mut Yak) {
144144
// We can add the razor as a field rather than formatting it
145145
// as part of the message, allowing subscribers to consume it
146146
// in a more structured manner:
147-
info!({ %razor }, "Razor located");
147+
info!(%razor, "Razor located");
148148
yak.shave(razor);
149149
break;
150150
}

tracing/examples/counters.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,15 +127,15 @@ fn main() {
127127
let mut foo: u64 = 2;
128128
span!(Level::TRACE, "my_great_span", foo_count = &foo).in_scope(|| {
129129
foo += 1;
130-
info!({ yak_shaved = true, yak_count = 1 }, "hi from inside my span");
130+
info!(yak_shaved = true, yak_count = 1, "hi from inside my span");
131131
span!(
132132
Level::TRACE,
133133
"my other span",
134134
foo_count = &foo,
135135
baz_count = 5
136136
)
137137
.in_scope(|| {
138-
warn!({ yak_shaved = false, yak_count = -1 }, "failed to shave yak");
138+
warn!(yak_shaved = false, yak_count = -1, "failed to shave yak");
139139
});
140140
});
141141

tracing/examples/sloggish/main.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,20 @@ fn main() {
3131
let peer1 = span!(Level::TRACE, "conn", peer_addr = "82.9.9.9", port = 42381);
3232
peer1.in_scope(|| {
3333
debug!("connected");
34-
debug!({ length = 2 }, "message received");
34+
debug!(length = 2, "message received");
3535
});
3636
let peer2 = span!(Level::TRACE, "conn", peer_addr = "8.8.8.8", port = 18230);
3737
peer2.in_scope(|| {
3838
debug!("connected");
3939
});
4040
peer1.in_scope(|| {
41-
warn!({ algo = "xor" }, "weak encryption requested");
42-
debug!({ length = 8 }, "response sent");
41+
warn!(algo = "xor", "weak encryption requested");
42+
debug!(length = 8, "response sent");
4343
debug!("disconnected");
4444
});
4545
peer2.in_scope(|| {
46-
debug!({ length = 5 }, "message received");
47-
debug!({ length = 8 }, "response sent");
46+
debug!(length = 5, "message received");
47+
debug!(length = 8, "response sent");
4848
debug!("disconnected");
4949
});
5050
warn!("internal error");

tracing/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@
171171
//! // We can add the razor as a field rather than formatting it
172172
//! // as part of the message, allowing subscribers to consume it
173173
//! // in a more structured manner:
174-
//! info!({ %razor }, "Razor located");
174+
//! info!(%razor, "Razor located");
175175
//! yak.shave(razor);
176176
//! break;
177177
//! }

tracing/src/macros.rs

Lines changed: 98 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,10 @@ macro_rules! error_span {
723723

724724
/// Constructs a new `Event`.
725725
///
726+
/// The event macro is invoked with a `Level` and up to 32 key-value fields.
727+
/// Optionally, a format string and arguments may follow the fields; this will
728+
/// be used to construct an implicit field named "message".
729+
///
726730
/// # Examples
727731
///
728732
/// ```rust
@@ -733,18 +737,20 @@ macro_rules! error_span {
733737
/// let private_data = "private";
734738
/// let error = "a bad error";
735739
///
736-
/// event!(Level::ERROR, %error, message = "Received error");
737-
/// event!(target: "app_events", Level::WARN, {
738-
/// private_data,
739-
/// ?data,
740-
/// },
741-
/// "App warning: {}", error
740+
/// event!(Level::ERROR, %error, "Received error");
741+
/// event!(
742+
/// target: "app_events",
743+
/// Level::WARN,
744+
/// private_data,
745+
/// ?data,
746+
/// "App warning: {}",
747+
/// error
742748
/// );
743749
/// event!(Level::INFO, the_answer = data.0);
744750
/// # }
745751
/// ```
746752
///
747-
/// Note that *unlike `$crate::span!`*, `$crate::event!` requires a value for all fields. As
753+
/// Note that *unlike `span!`*, `event!` requires a value for all fields. As
748754
/// events are recorded immediately when the macro is invoked, there is no
749755
/// opportunity for fields to be recorded later. A trailing comma on the final
750756
/// field is valid.
@@ -755,7 +761,7 @@ macro_rules! error_span {
755761
/// # extern crate tracing;
756762
/// # use tracing::Level;
757763
/// # fn main() {
758-
/// event!(Level::Info, foo = 5, bad_field, bar = "hello")
764+
/// event!(Level::INFO, foo = 5, bad_field, bar = "hello")
759765
/// #}
760766
/// ```
761767
/// Shorthand for `field::debug`:
@@ -839,7 +845,7 @@ macro_rules! event {
839845
}
840846
});
841847

842-
(target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ({
848+
(target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ({
843849
$crate::event!(
844850
target: $target,
845851
parent: $parent,
@@ -850,8 +856,8 @@ macro_rules! event {
850856
(target: $target:expr, parent: $parent:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => (
851857
$crate::event!(target: $target, parent: $parent, $lvl, { $($k).+ = $($fields)* })
852858
);
853-
(target: $target:expr, parent: $parent:expr, $lvl:expr, $($arg:tt)+ ) => (
854-
$crate::event!(target: $target, parent: $parent, $lvl, { }, $($arg)+)
859+
(target: $target:expr, parent: $parent:expr, $lvl:expr, $($arg:tt)+) => (
860+
$crate::event!(target: $target, parent: $parent, $lvl, { $($arg)+ })
855861
);
856862
(target: $target:expr, $lvl:expr, { $($fields:tt)* } )=> ({
857863
{
@@ -895,7 +901,7 @@ macro_rules! event {
895901
$crate::event!(target: $target, $lvl, { $($k).+ = $($fields)* })
896902
);
897903
(target: $target:expr, $lvl:expr, $($arg:tt)+ ) => (
898-
$crate::event!(target: $target, $lvl, { }, $($arg)+)
904+
$crate::event!(target: $target, $lvl, { $($arg)+ })
899905
);
900906
(parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
901907
$crate::event!(
@@ -962,7 +968,7 @@ macro_rules! event {
962968
)
963969
);
964970
(parent: $parent:expr, $lvl:expr, $($arg:tt)+ ) => (
965-
$crate::event!(target: module_path!(), parent: $parent, $lvl, { }, $($arg)+)
971+
$crate::event!(target: module_path!(), parent: $parent, $lvl, { $($arg)+ })
966972
);
967973
( $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
968974
$crate::event!(
@@ -1016,7 +1022,7 @@ macro_rules! event {
10161022
$crate::event!($lvl, $($k).+,)
10171023
);
10181024
( $lvl:expr, $($arg:tt)+ ) => (
1019-
$crate::event!(target: module_path!(), $lvl, { }, $($arg)+)
1025+
$crate::event!(target: module_path!(), $lvl, { $($arg)+ })
10201026
);
10211027
}
10221028

@@ -1043,11 +1049,13 @@ macro_rules! event {
10431049
/// let origin_dist = pos.dist(Position::ORIGIN);
10441050
///
10451051
/// trace!(position = ?pos, ?origin_dist);
1046-
/// trace!(target: "app_events",
1047-
/// { position = ?pos },
1048-
/// "x is {} and y is {}",
1049-
/// if pos.x >= 0.0 { "positive" } else { "negative" },
1050-
/// if pos.y >= 0.0 { "positive" } else { "negative" });
1052+
/// trace!(
1053+
/// target: "app_events",
1054+
/// position = ?pos,
1055+
/// "x is {} and y is {}",
1056+
/// if pos.x >= 0.0 { "positive" } else { "negative" },
1057+
/// if pos.y >= 0.0 { "positive" } else { "negative" }
1058+
/// );
10511059
/// # }
10521060
/// ```
10531061
#[macro_export]
@@ -1231,7 +1239,7 @@ macro_rules! trace {
12311239
/// let pos = Position { x: 3.234, y: -1.223 };
12321240
///
12331241
/// debug!(?pos.x, ?pos.y);
1234-
/// debug!(target: "app_events", { position = ?pos }, "New position");
1242+
/// debug!(target: "app_events", position = ?pos, "New position");
12351243
/// # }
12361244
/// ```
12371245
#[macro_export]
@@ -1434,7 +1442,7 @@ macro_rules! debug {
14341442
/// let addr = Ipv4Addr::new(127, 0, 0, 1);
14351443
/// let conn = Connection { port: 40, speed: 3.20 };
14361444
///
1437-
/// info!({ conn.port }, "connected to {:?}", addr);
1445+
/// info!(conn.port, "connected to {:?}", addr);
14381446
/// info!(
14391447
/// target: "connection_events",
14401448
/// ip = ?addr,
@@ -1640,7 +1648,7 @@ macro_rules! info {
16401648
/// warn!(?input, warning = warn_description);
16411649
/// warn!(
16421650
/// target: "input_events",
1643-
/// { warning = warn_description },
1651+
/// warning = warn_description,
16441652
/// "Received warning for input: {:?}", input,
16451653
/// );
16461654
/// # }
@@ -2123,7 +2131,7 @@ macro_rules! is_enabled {
21232131
macro_rules! valueset {
21242132

21252133
// === base case ===
2126-
(@ { $($val:expr),* }, $next:expr, $(,)*) => {
2134+
(@ { $(,)* $($val:expr),* $(,)* }, $next:expr $(,)*) => {
21272135
&[ $($val),* ]
21282136
};
21292137

@@ -2176,6 +2184,42 @@ macro_rules! valueset {
21762184
$($rest)*
21772185
)
21782186
};
2187+
(@ { $($out:expr),+ }, $next:expr, $($k:ident).+ = ?$val:expr) => {
2188+
$crate::valueset!(
2189+
@ { $($out),+, (&$next, Some(&debug(&$val) as &Value)) },
2190+
$next,
2191+
)
2192+
};
2193+
(@ { $($out:expr),+ }, $next:expr, $($k:ident).+ = %$val:expr) => {
2194+
$crate::valueset!(
2195+
@ { $($out),+, (&$next, Some(&display(&$val) as &Value)) },
2196+
$next,
2197+
)
2198+
};
2199+
(@ { $($out:expr),+ }, $next:expr, $($k:ident).+ = $val:expr) => {
2200+
$crate::valueset!(
2201+
@ { $($out),+, (&$next, Some(&$val as &Value)) },
2202+
$next,
2203+
)
2204+
};
2205+
(@ { $($out:expr),+ }, $next:expr, $($k:ident).+) => {
2206+
$crate::valueset!(
2207+
@ { $($out),+, (&$next, Some(&$($k).+ as &Value)) },
2208+
$next,
2209+
)
2210+
};
2211+
(@ { $($out:expr),+ }, $next:expr, ?$($k:ident).+) => {
2212+
$crate::valueset!(
2213+
@ { $($out),+, (&$next, Some(&debug(&$($k).+) as &Value)) },
2214+
$next,
2215+
)
2216+
};
2217+
(@ { $($out:expr),+ }, $next:expr, %$($k:ident).+) => {
2218+
$crate::valueset!(
2219+
@ { $($out),+, (&$next, Some(&display(&$($k).+) as &Value)) },
2220+
$next,
2221+
)
2222+
};
21792223

21802224
// == recursive case (more tts), empty out set ===
21812225

@@ -2202,6 +2246,30 @@ macro_rules! valueset {
22022246
(@ { }, $next:expr, %$($k:ident).+, $($rest:tt)*) => {
22032247
$crate::valueset!(@ { (&$next, Some(&display(&$($k).+) as &Value)) }, $next, $($rest)* )
22042248
};
2249+
// no trailing comma
2250+
(@ { }, $next:expr, $($k:ident).+ = ?$val:expr) => {
2251+
$crate::valueset!(@ { (&$next, Some(&debug(&$val) as &Value)) }, $next )
2252+
};
2253+
(@ { }, $next:expr, $($k:ident).+ = %$val:expr) => {
2254+
$crate::valueset!(@ { (&$next, Some(&display(&$val) as &Value)) }, $next)
2255+
};
2256+
(@ { }, $next:expr, $($k:ident).+ = $val:expr) => {
2257+
$crate::valueset!(@ { (&$next, Some(&$val as &Value)) }, $next)
2258+
};
2259+
(@ { }, $next:expr, $($k:ident).+) => {
2260+
$crate::valueset!(@ { (&$next, Some(&$($k).+ as &Value)) }, $next)
2261+
};
2262+
(@ { }, $next:expr, ?$($k:ident).+) => {
2263+
$crate::valueset!(@ { (&$next, Some(&debug(&$($k).+) as &Value)) }, $next)
2264+
};
2265+
(@ { }, $next:expr, %$($k:ident).+) => {
2266+
$crate::valueset!(@ { (&$next, Some(&display(&$($k).+) as &Value)) }, $next)
2267+
};
2268+
2269+
// Remainder is unparseable, but exists --- must be format args!
2270+
(@ { $($out:expr),* }, $next:expr, $($rest:tt)+) => {
2271+
$crate::valueset!(@ { $($out),*, (&$next, Some(&format_args!($($rest)+) as &Value)) }, $next, )
2272+
};
22052273

22062274
// === entry ===
22072275
($fields:expr, $($kvs:tt)+) => {
@@ -2212,7 +2280,7 @@ macro_rules! valueset {
22122280
$fields.value_set($crate::valueset!(
22132281
@ { },
22142282
iter.next().expect("FieldSet corrupted (this is a bug)"),
2215-
$($kvs)+,
2283+
$($kvs)+
22162284
))
22172285
}
22182286
};
@@ -2227,7 +2295,7 @@ macro_rules! valueset {
22272295
#[macro_export]
22282296
macro_rules! fieldset {
22292297
// == base case ==
2230-
(@ { $($out:expr),* $(,)* } $(,)*) => {
2298+
(@ { $(,)* $($out:expr),* $(,)* } $(,)*) => {
22312299
&[ $($out),* ]
22322300
};
22332301

@@ -2282,6 +2350,11 @@ macro_rules! fieldset {
22822350
$crate::fieldset!(@ { $($out),+, $crate::__tracing_stringify!($($k).+) } $($rest)*)
22832351
};
22842352

2353+
// Remainder is unparseable, but exists --- must be format args!
2354+
(@ { $($out:expr),* } $($rest:tt)+) => {
2355+
$crate::fieldset!(@ { $($out),*, "message" })
2356+
};
2357+
22852358
// == entry ==
22862359
($($args:tt)*) => {
22872360
$crate::fieldset!(@ { } $($args)*,)

tracing/tests/event.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,61 @@ fn event_with_message() {
6161
handle.assert_finished();
6262
}
6363

64+
#[test]
65+
fn message_without_delims() {
66+
let (subscriber, handle) = subscriber::mock()
67+
.event(
68+
event::mock().with_fields(
69+
field::mock("answer")
70+
.with_value(&42)
71+
.and(field::mock("question").with_value(&"life, the universe, and everything"))
72+
.and(
73+
field::mock("message").with_value(&tracing::field::debug(format_args!(
74+
"hello from my event! tricky? {:?}!",
75+
true
76+
))),
77+
)
78+
.only(),
79+
),
80+
)
81+
.done()
82+
.run_with_handle();
83+
84+
with_default(subscriber, || {
85+
let question = "life, the universe, and everything";
86+
debug!(answer = 42, question, "hello from {where}! tricky? {:?}!", true, where = "my event");
87+
});
88+
89+
handle.assert_finished();
90+
}
91+
92+
#[test]
93+
fn string_message_without_delims() {
94+
let (subscriber, handle) = subscriber::mock()
95+
.event(
96+
event::mock().with_fields(
97+
field::mock("answer")
98+
.with_value(&42)
99+
.and(field::mock("question").with_value(&"life, the universe, and everything"))
100+
.and(
101+
field::mock("message").with_value(&tracing::field::debug(format_args!(
102+
"hello from my event"
103+
))),
104+
)
105+
.only(),
106+
),
107+
)
108+
.done()
109+
.run_with_handle();
110+
111+
with_default(subscriber, || {
112+
let question = "life, the universe, and everything";
113+
debug!(answer = 42, question, "hello from my event");
114+
});
115+
116+
handle.assert_finished();
117+
}
118+
64119
#[test]
65120
fn one_with_everything() {
66121
let (subscriber, handle) = subscriber::mock()

0 commit comments

Comments
 (0)