Skip to content

Commit 4ba6907

Browse files
authored
Support ident without value shorthand in macros (#57)
1 parent cff03f7 commit 4ba6907

File tree

5 files changed

+393
-42
lines changed

5 files changed

+393
-42
lines changed

src/macros/impl_.rs

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,25 @@ pub use crate::{__log as log, __tracing_span as tracing_span};
1818
#[macro_export]
1919
#[doc(hidden)]
2020
macro_rules! __tracing_span {
21-
(parent: $parent:expr, $level:expr, $format:expr, $($($path:ident).+ = $value:expr),*) => {{
21+
(parent: $parent:expr, $level:expr, $format:expr, $($($path:ident).+ $(= $value:expr)?),*) => {{
2222
// bind args early to avoid multiple evaluation
23-
$crate::__bind_single_ident_args!($($($path).+ = $value),*);
23+
$crate::__bind_single_ident_args!($($($path).+ $(= $value)?),*);
2424
tracing::span!(
2525
parent: $parent,
2626
$level,
2727
$format,
28-
$($($path).+ = $crate::__evaluate_arg!($($path).+ = $value),)*
28+
$($($path).+ = $crate::__evaluate_arg!($($path).+ $(= $value)?),)*
2929
logfire.msg = format_args!($format),
3030
logfire.json_schema = $crate::__json_schema!($($($path).+),*),
3131
)
3232
}};
33-
($level:expr, $format:expr, $($($path:ident).+ = $value:expr),*) => {{
33+
($level:expr, $format:expr, $($($path:ident).+ $(= $value:expr)?),*) => {{
3434
// bind args early to avoid multiple evaluation
35-
$crate::__bind_single_ident_args!($($($path).+ = $value),*);
35+
$crate::__bind_single_ident_args!($($($path).+ $(= $value)?),*);
3636
tracing::span!(
3737
$level,
3838
$format,
39-
$($($path).+ = $crate::__evaluate_arg!($($path).+ = $value),)*
39+
$($($path).+ = $crate::__evaluate_arg!($($path).+ $(= $value)?),)*
4040
logfire.msg = format_args!($format),
4141
logfire.json_schema = $crate::__json_schema!($($($path).+),*),
4242
)
@@ -246,14 +246,19 @@ macro_rules! __schema_args {
246246
#[macro_export]
247247
#[doc(hidden)]
248248
macro_rules! __bind_single_ident_args {
249-
// single-ident arg: bind it
249+
// single-ident arg with value: bind it
250250
($arg:ident = $value:expr $(, $($rest_arg:ident).+ = $rest_value:expr)*) => {
251251
let $arg = $value;
252252
$crate::__bind_single_ident_args!($($($rest_arg).+ = $rest_value),*)
253253
};
254+
// single-ident arg without value: bind it
255+
($arg:ident $(, $($rest_arg:ident).+ $(= $rest_value:expr)?)*) => {
256+
let $arg = $arg;
257+
$crate::__bind_single_ident_args!($($($rest_arg).+ $(= $rest_value)?),*)
258+
};
254259
// multi-ident arg: skip it
255-
($($path:ident).+ = $value:expr $(, $($rest_arg:ident).+ = $rest_value:expr)*) => {
256-
$crate::__bind_single_ident_args!($($($rest_arg).+ = $rest_value),*)
260+
($($path:ident).+ $(= $value:expr)? $(, $($rest_arg:ident).+ $(= $rest_value:expr)?)*) => {
261+
$crate::__bind_single_ident_args!($($($rest_arg).+ $(= $rest_value)?),*)
257262
};
258263
// base case: stop recursion
259264
() => { };
@@ -267,23 +272,27 @@ macro_rules! __bind_single_ident_args {
267272
#[doc(hidden)]
268273
macro_rules! __evaluate_arg {
269274
// single ident arg should already have been bound
270-
($arg:ident = $value:expr) => {
275+
($arg:ident $(= $value:expr)?) => {
271276
$arg
272277
};
273-
// multi-ident arg should be evaluated now
278+
// multi-ident arg with value: be evaluated now
274279
($($path:ident).+ = $value:expr) => {
275280
$value
276281
};
282+
// multi-ident arg evaluated from path
283+
($($path:ident).+) => {
284+
$($path).+
285+
};
277286
}
278287

279288
#[macro_export]
280289
#[doc(hidden)]
281290
macro_rules! __log {
282-
(parent: $parent:expr, $level:expr, $format:expr, $($($path:ident).+ = $value:expr),*) => {
291+
(parent: $parent:expr, $level:expr, $format:expr, $($($path:ident).+ $(= $value:expr)?),*) => {
283292
if tracing::span_enabled!($level) {
284293
// bind single ident args early to allow them in the format string
285294
// without multiple evaluation
286-
$crate::__bind_single_ident_args!($($($path).+ = $value),*);
295+
$crate::__bind_single_ident_args!($($($path).+ $(= $value)?),*);
287296
$crate::__macros_impl::export_log_span(
288297
$format,
289298
$parent,
@@ -295,7 +304,7 @@ macro_rules! __log {
295304
module_path!(),
296305
[
297306
$({
298-
let arg_value = $crate::__evaluate_arg!($($path).+ = $value);
307+
let arg_value = $crate::__evaluate_arg!($($path).+ $(= $value)?);
299308
$crate::__macros_impl::LogfireValue::new(
300309
stringify!($($path).+),
301310
$crate::__macros_impl::converter(&arg_value).convert_value(arg_value)

src/macros/mod.rs

Lines changed: 70 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -61,22 +61,41 @@ pub mod __macros_impl;
6161
/// // Attributes can either be a single name or a dotted.name
6262
/// // `dotted.name` is not available in the format string.
6363
/// let span = logfire::span!("Span with x = {x}, y = {y}", y = "hello", foo.bar = 42);
64+
///
65+
/// // If just an identifier is used without `= value`, it will be captured as an attribute
66+
/// let foo = "bar";
67+
/// let span = logfire::span!("Span with foo = {foo}", foo);
68+
///
69+
/// // This identifier shorthand also works for struct fields
70+
/// #[derive(Debug)]
71+
/// struct User {
72+
/// email: &'static str,
73+
/// name: &'static str,
74+
/// }
75+
///
76+
/// let user = User {
77+
/// email: "[email protected]",
78+
/// name: "John Doe",
79+
/// };
80+
///
81+
/// // NB the dotted name is not available in the format string
82+
/// let span = logfire::span!("Span user info", user.email, user.name);
6483
/// ```
6584
///
6685
/// [attributes]: https://opentelemetry.io/docs/concepts/signals/traces/#attributes
6786
#[macro_export]
6887
macro_rules! span {
69-
(parent: $parent:expr, level: $level:expr, $format:expr $(, $($path:ident).+ = $value:expr)* $(,)?) => {
70-
$crate::__macros_impl::tracing_span!(parent: $parent, $level, $format, $($($path).+ = $value),*)
88+
(parent: $parent:expr, level: $level:expr, $format:expr $(, $($path:ident).+ $(= $value:expr)?)* $(,)?) => {
89+
$crate::__macros_impl::tracing_span!(parent: $parent, $level, $format, $($($path).+ $(= $value)?),*)
7190
};
72-
(parent: $parent:expr, $format:expr $(, $($path:ident).+ = $value:expr)* $(,)?) => {
73-
$crate::__macros_impl::tracing_span!(parent: $parent, tracing::Level::INFO, $format, $($($path).+ = $value),*)
91+
(parent: $parent:expr, $format:expr $(, $($path:ident).+ $(= $value:expr)?)* $(,)?) => {
92+
$crate::__macros_impl::tracing_span!(parent: $parent, tracing::Level::INFO, $format, $($($path).+ $(= $value)?),*)
7493
};
75-
(level: $level:expr, $format:expr $(, $($path:ident).+ = $value:expr)* $(,)?) => {
76-
$crate::__macros_impl::tracing_span!($level, $format, $($($path).+ = $value),*)
94+
(level: $level:expr, $format:expr $(, $($path:ident).+ $(= $value:expr)?)* $(,)?) => {
95+
$crate::__macros_impl::tracing_span!($level, $format, $($($path).+ $(= $value)?),*)
7796
};
78-
($format:expr $(, $($path:ident).+ = $value:expr)* $(,)?) => {
79-
$crate::__macros_impl::tracing_span!(tracing::Level::INFO, $format, $($($path).+ = $value),*)
97+
($format:expr $(, $($path:ident).+ $(= $value:expr)?)* $(,)?) => {
98+
$crate::__macros_impl::tracing_span!(tracing::Level::INFO, $format, $($($path).+ $(= $value)?),*)
8099
};
81100
}
82101

@@ -85,11 +104,11 @@ macro_rules! span {
85104
/// See the [`log!`][macro@crate::log] macro for more details.
86105
#[macro_export]
87106
macro_rules! error {
88-
(parent: $parent:expr, $format:expr $(, $($path:ident).+ = $value:expr)* $(,)?) => {
89-
$crate::log!(parent: $parent, tracing::Level::ERROR, $format, $($($path).+ = $value),*)
107+
(parent: $parent:expr, $format:expr $(, $($path:ident).+ $(= $value:expr)?)* $(,)?) => {
108+
$crate::log!(parent: $parent, tracing::Level::ERROR, $format, $($($path).+ $(= $value)?),*)
90109
};
91-
($format:expr $(, $($path:ident).+ = $value:expr)* $(,)?) => {
92-
$crate::log!(tracing::Level::ERROR, $format, $($($path).+ = $value),*)
110+
($format:expr $(, $($path:ident).+ $(= $value:expr)?)* $(,)?) => {
111+
$crate::log!(tracing::Level::ERROR, $format, $($($path).+ $(= $value)?),*)
93112
};
94113
}
95114

@@ -98,11 +117,11 @@ macro_rules! error {
98117
/// See the [`log!`][macro@crate::log] macro for more details.
99118
#[macro_export]
100119
macro_rules! warn {
101-
(parent: $parent:expr, $format:expr $(, $($path:ident).+ = $value:expr)* $(,)?) => {
102-
$crate::log!(parent: $parent, tracing::Level::WARN, $format, $($($path).+ = $value),*)
120+
(parent: $parent:expr, $format:expr $(, $($path:ident).+ $(= $value:expr)?)* $(,)?) => {
121+
$crate::log!(parent: $parent, tracing::Level::WARN, $format, $($($path).+ $(= $value)?),*)
103122
};
104-
($format:expr $(, $($path:ident).+ = $value:expr)* $(,)?) => {
105-
$crate::log!(tracing::Level::WARN, $format, $($($path).+ = $value),*)
123+
($format:expr $(, $($path:ident).+ $(= $value:expr)?)* $(,)?) => {
124+
$crate::log!(tracing::Level::WARN, $format, $($($path).+ $(= $value)?),*)
106125
};
107126
}
108127

@@ -111,11 +130,11 @@ macro_rules! warn {
111130
/// See the [`log!`][macro@crate::log] macro for more details.
112131
#[macro_export]
113132
macro_rules! info {
114-
(parent: $parent:expr, $format:expr $(, $($path:ident).+ = $value:expr)* $(,)?) => {
115-
$crate::log!(parent: $parent, tracing::Level::INFO, $format, $($($path).+ = $value),*)
133+
(parent: $parent:expr, $format:expr $(, $($path:ident).+ $(= $value:expr)?)* $(,)?) => {
134+
$crate::log!(parent: $parent, tracing::Level::INFO, $format, $($($path).+ $(= $value)?),*)
116135
};
117-
($format:expr $(, $($path:ident).+ = $value:expr)* $(,)?) => {
118-
$crate::log!(tracing::Level::INFO, $format, $($($path).+ = $value),*)
136+
($format:expr $(, $($path:ident).+ $(= $value:expr)?)* $(,)?) => {
137+
$crate::log!(tracing::Level::INFO, $format, $($($path).+ $(= $value)?),*)
119138
};
120139
}
121140

@@ -124,11 +143,11 @@ macro_rules! info {
124143
/// See the [`log!`][macro@crate::log] macro for more details.
125144
#[macro_export]
126145
macro_rules! debug {
127-
(parent: $parent:expr, $format:expr $(, $($path:ident).+ = $value:expr)* $(,)?) => {
128-
$crate::log!(parent: $parent, tracing::Level::DEBUG, $format, $($($path).+ = $value),*)
146+
(parent: $parent:expr, $format:expr $(, $($path:ident).+ $(= $value:expr)?)* $(,)?) => {
147+
$crate::log!(parent: $parent, tracing::Level::DEBUG, $format, $($($path).+ $(= $value)?),*)
129148
};
130-
($format:expr $(, $($path:ident).+ = $value:expr)* $(,)?) => {
131-
$crate::log!(tracing::Level::DEBUG, $format, $($($path).+ = $value),*)
149+
($format:expr $(, $($path:ident).+ $(= $value:expr)?)* $(,)?) => {
150+
$crate::log!(tracing::Level::DEBUG, $format, $($($path).+ $(= $value)?),*)
132151
};
133152
}
134153

@@ -199,15 +218,38 @@ macro_rules! debug {
199218
/// logfire::log!(Level::INFO, "Log with x = {x}, y = {y}", y = "hello", foo.bar = 42);
200219
/// // or
201220
/// logfire::info!("Log with x = {x}, y = {y}", y = "hello", foo.bar = 42);
221+
///
222+
/// // If just an identifier is used without `= value`, it will be captured as an attribute
223+
/// let foo = "bar";
224+
/// logfire::log!(Level::INFO, "Log with foo = {foo}", foo);
225+
/// // or
226+
/// logfire::info!("Log with foo = {foo}", foo);
227+
///
228+
/// // This identifier shorthand also works for struct fields
229+
/// #[derive(Debug)]
230+
/// struct User {
231+
/// email: &'static str,
232+
/// name: &'static str,
233+
/// }
234+
///
235+
/// let user = User {
236+
/// email: "[email protected]",
237+
/// name: "John Doe",
238+
/// };
239+
///
240+
/// // NB the dotted name is not available in the format string
241+
/// logfire::log!(Level::INFO, "Log user info", user.email, user.name);
242+
/// // or
243+
/// logfire::info!("Log user info", user.email, user.name);
202244
/// ```
203245
///
204246
/// [attributes]: https://opentelemetry.io/docs/concepts/signals/traces/#attributes
205247
#[macro_export]
206248
macro_rules! log {
207-
(parent: $parent:expr, $level:expr, $format:expr $(, $($path:ident).+ = $value:expr)* $(,)?) => {
208-
$crate::__macros_impl::log!(parent: $parent, $level, $format, $($($path).+ = $value),*)
249+
(parent: $parent:expr, $level:expr, $format:expr $(, $($path:ident).+ $(= $value:expr)?)* $(,)?) => {
250+
$crate::__macros_impl::log!(parent: $parent, $level, $format, $($($path).+ $(= $value)?),*)
209251
};
210-
($level:expr, $format:expr $(, $($path:ident).+ = $value:expr)* $(,)?) => {
211-
$crate::__macros_impl::log!(parent: &tracing::Span::current(), $level, $format, $($($path).+ = $value),*)
252+
($level:expr, $format:expr $(, $($path:ident).+ $(= $value:expr)?)* $(,)?) => {
253+
$crate::__macros_impl::log!(parent: &tracing::Span::current(), $level, $format, $($($path).+ $(= $value)?),*)
212254
};
213255
}

src/test_utils.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,22 @@ pub struct DeterministicResourceMetrics {
220220
resource: Resource,
221221
scope_metrics: Vec<DeterministicScopeMetrics>,
222222
}
223+
224+
/// Find a span by name in a slice of SpanData.
225+
pub fn find_span<'a>(
226+
spans: &'a [opentelemetry_sdk::trace::SpanData],
227+
name: &str,
228+
) -> &'a opentelemetry_sdk::trace::SpanData {
229+
spans.iter().find(|s| s.name == name).expect("span present")
230+
}
231+
232+
/// Find an attribute by key in a span's attributes, panicking if not found.
233+
pub fn find_attr<'a>(
234+
span: &'a opentelemetry_sdk::trace::SpanData,
235+
key: &str,
236+
) -> &'a opentelemetry::KeyValue {
237+
span.attributes
238+
.iter()
239+
.find(|kv| kv.key.as_str() == key)
240+
.unwrap_or_else(|| panic!("attribute '{}' not found in span '{}'", key, span.name))
241+
}

0 commit comments

Comments
 (0)