Skip to content

Conversation

@nico-incubiq
Copy link
Contributor

@nico-incubiq nico-incubiq commented Nov 27, 2024

Motivation

The #[instrument] proc macro only allows setting field names as identifiers, which is not on par with other macros such as span! or event! that allow constant expressions. Using constants for example can ensure consistency across a project for the field names used.

This addresses #2969, which was already mentioned in this comment here on #2617 (note that "classic macros" mentioned there already work, there are tests attesting of it).
I also updated the doc block to mention field values can be any arbitrary expressions, which was implemented by #672 but never updated.

Solution

I updated the instrument proc macro to allow constant expressions (const, const fn, literal str, ...) as field names, using the same syntax as #2617, enclosed in curly braces.

const CONST_FIELD_NAME: &str = "foo.bar";

#[instrument(fields({CONST_FIELD_NAME} = "quux"))]
fn fn_const_field_name() {}

Notes

  • The identifier (Punctuated) field names have a convenient feature allowing to supersede non-skipped function arguments (a field named s would be used instead of a function argument s in the span). As far as I'm aware this is not possible to implement for constant expressions, as the compiler doesn't allow to evaluate constants at build time (MIRI might be a solution but that seems complicated, and https://rustc-dev-guide.rust-lang.org/const-eval seems experimental). It's a minor inconsistency; in this scenario, the code would panic immediately at startup, and the workaround is as simple as skipping the function argument.

@nico-incubiq nico-incubiq requested review from a team, davidbarsky and hawkw as code owners November 27, 2024 01:40
@nico-incubiq nico-incubiq changed the title Support constant expressions as tracing field names Support constant expressions as instrument field names Nov 27, 2024
@nico-incubiq nico-incubiq force-pushed the const-field-names branch 2 times, most recently from acd38e1 to a2c17f3 Compare November 27, 2024 16:19
});
}

// TODO(#3158): To be consistent with event! and span! macros, the argument's value should be
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a test for the panic here, to ensure that this check doesn't get accidentally removed at some point in the future. It may be necessary to move the test to a "ui" test to validate the compiler error message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I no longer think adding a panic or deduplication logic for constant expressions is feasible at compile time. Every solution I tested incurs a runtime cost, as constant expressions need to be evaluated first, and then every value needs to be compared against each other.
Given that the impact of not doing it is "just" duplicated fields reported, and is limited to people newly opting into braced constant expressions, I don't expect this to cause much problem.

I updated the docs to explain this.

Copy link
Contributor Author

@nico-incubiq nico-incubiq Aug 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expanding on the previous message with more details:
The panic solution worked at compile time because it was fully integrated inside a constant context, which I learned recently the compiler is happy to execute. But I understand this is less than ideal from a user perspective, as it introduces a breaking change.

On the other hand, a new FieldSet::new_checked constructor would be very hard to surface, as it would force to duplicate a lot of the code, including the span! macro, at which point the code becomes unmaintainable.

I would prefer to implement deduplication, but this remained out of reach after many attempts.

  • The existing deduplication code in expand.rs occurs during macro expansion, while constant evaluation by the compiler only happens at a later stage.
  • Another point at which this could be implemented is around FieldSet creation, but given that ValueSet is created in a totally unrelated part of the code and the two need to stay in sync, it seems impossible to keep them aligned as duplicated fields are removed.
  • I have stayed away from runtime deduplication, as this is an undesirable cost to pay for something that should only be checked statically.

It'll be possible to do a follow-up PR to add deduplication when someone hopefully figures it out.

@NickLarsenNZ
Copy link

@nico-incubiq , are you still planning to work on this?

@nico-incubiq
Copy link
Contributor Author

nico-incubiq commented Jun 12, 2025

@nico-incubiq , are you still planning to work on this?

I'd like to pick this back up yes.
Although, I'm not sure the suggested approach of creating a new constructor to avoid introducing a panic achieves the original goal as it wouldn't be possible to use constants in existing attributes. I would like attributes to be on par with macros as introduced by #2617.
I've been looking for a way to evaluate the constant at compile time to avoid panicking, but I'm not sure how.

Also I've used Block for the FieldName because it is already parsed enclosed in braces, but that's much too broad, ideally I'd rather parse { + Expr + }. Done.

@nico-incubiq nico-incubiq requested a review from yaahc as a code owner June 13, 2025 00:42
@nico-incubiq nico-incubiq changed the base branch from master to main June 13, 2025 00:42
@nico-incubiq nico-incubiq force-pushed the const-field-names branch 2 times, most recently from e709479 to 4f01b67 Compare August 17, 2025 00:38
@nico-incubiq
Copy link
Contributor Author

This is ready for review again when someone has time 🙏🏼

Copy link
Contributor

@hds hds left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small docs nit. Otherwise, this looks good now!

@nico-incubiq
Copy link
Contributor Author

Thanks @hds, I merged your change and rebased off the latest main, some checks haven't ran i suppose you need to trigger them on your side?

@hds
Copy link
Contributor

hds commented Nov 16, 2025

@nico-incubiq run. Just a rustfmt failure (small one).

@nico-incubiq
Copy link
Contributor Author

Fixed

@nico-incubiq nico-incubiq requested a review from hds November 17, 2025 00:14
Copy link
Contributor

@hds hds left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for all your work on this PR!

@hds hds merged commit ee0713d into tokio-rs:main Nov 17, 2025
55 checks passed
hds added a commit that referenced this pull request Nov 25, 2025
# 0.1.31 (November 30, 2025)

### Added

- Support constant expressions as instrument field names ([#3158])

[#3158]: https://github.com/tokio-rs/tracing/pull/#3158
hds added a commit that referenced this pull request Nov 25, 2025
# 0.1.42 (November 30, 2025)

### Added

- **attributes**: Support constant expressions as instrument field names ([#3158])
- **core**: Improve code generation at trace points significantly ([#3398])

### Fixed

- Fix perf regression when `release_max_level_*` not set ([#3373])
- Use imported instead of fully qualified path ([#3374])
- Make `valueset` macro sanitary ([#3382])

### Documented

- **core**: Add missing `dyn` keyword in `Visit` documentation code sample ([#3387])

[#3158]: https://github.com/tokio-rs/tracing/pull/#3158
[#3373]: https://github.com/tokio-rs/tracing/pull/#3373
[#3374]: https://github.com/tokio-rs/tracing/pull/#3374
[#3382]: https://github.com/tokio-rs/tracing/pull/#3382
[#3387]: https://github.com/tokio-rs/tracing/pull/#3387
[#3398]: https://github.com/tokio-rs/tracing/pull/#3398
hds added a commit that referenced this pull request Nov 25, 2025
# 0.1.31 (November 30, 2025)

### Added

- Support constant expressions as instrument field names ([#3158])

[#3158]: https://github.com/tokio-rs/tracing/pull/#3158
hds added a commit that referenced this pull request Nov 26, 2025
# 0.1.31 (November 26, 2025)

### Added

- Support constant expressions as instrument field names ([#3158])

[#3158]: https://github.com/tokio-rs/tracing/pull/#3158
hds added a commit that referenced this pull request Nov 26, 2025
# 0.1.31 (November 26, 2025)

### Added

- Support constant expressions as instrument field names ([#3158])

[#3158]: https://github.com/tokio-rs/tracing/pull/#3158
hds added a commit that referenced this pull request Nov 26, 2025
# 0.1.42 (November 26, 2025)

### Added

- **attributes**: Support constant expressions as instrument field names ([#3158])
- **core**: Improve code generation at trace points significantly ([#3398])

### Changed

- `tracing-core`: updated to 0.1.35 ([#3414])
- `tracing-attributes`: updated to 0.1.31 ([#3417])

### Fixed

- Fix perf regression when `release_max_level_*` not set ([#3373])
- Use imported instead of fully qualified path ([#3374])
- Make `valueset` macro sanitary ([#3382])

### Documented

- **core**: Add missing `dyn` keyword in `Visit` documentation code sample ([#3387])

[#3158]: https://github.com/tokio-rs/tracing/pull/#3158
[#3373]: https://github.com/tokio-rs/tracing/pull/#3373
[#3374]: https://github.com/tokio-rs/tracing/pull/#3374
[#3382]: https://github.com/tokio-rs/tracing/pull/#3382
[#3387]: https://github.com/tokio-rs/tracing/pull/#3387
[#3398]: https://github.com/tokio-rs/tracing/pull/#3398
[#3414]: https://github.com/tokio-rs/tracing/pull/#3414
[#3417]: https://github.com/tokio-rs/tracing/pull/#3417
hds added a commit that referenced this pull request Nov 26, 2025
# 0.1.42 (November 26, 2025)

### Added

- **attributes**: Support constant expressions as instrument field names ([#3158])
- Add `record_all!` macro for recording multiple values in one call ([#3227])
- **core**: Improve code generation at trace points significantly ([#3398])

### Changed

- `tracing-core`: updated to 0.1.35 ([#3414])
- `tracing-attributes`: updated to 0.1.31 ([#3417])

### Fixed

- Fix "name / parent" variant of `event!` ([#2983])
- Remove 'r#' prefix from raw identifiers in field names ([#3130])
- Fix perf regression when `release_max_level_*` not set ([#3373])
- Use imported instead of fully qualified path ([#3374])
- Make `valueset` macro sanitary ([#3382])

### Documented

- **core**: Add missing `dyn` keyword in `Visit` documentation code sample ([#3387])

[#2983]: https://github.com/tokio-rs/tracing/pull/#2983
[#3130]: https://github.com/tokio-rs/tracing/pull/#3130
[#3158]: https://github.com/tokio-rs/tracing/pull/#3158
[#3227]: https://github.com/tokio-rs/tracing/pull/#3227
[#3373]: https://github.com/tokio-rs/tracing/pull/#3373
[#3374]: https://github.com/tokio-rs/tracing/pull/#3374
[#3382]: https://github.com/tokio-rs/tracing/pull/#3382
[#3387]: https://github.com/tokio-rs/tracing/pull/#3387
[#3398]: https://github.com/tokio-rs/tracing/pull/#3398
[#3414]: https://github.com/tokio-rs/tracing/pull/#3414
[#3417]: https://github.com/tokio-rs/tracing/pull/#3417
hds added a commit that referenced this pull request Nov 26, 2025
# 0.1.42 (November 26, 2025)

### Important

The [`Span::record_all`] method has been removed from the documented API. It
was always unsuable via the documented API as it requried a `ValueSet` which
has no publically documented constructors. The method remains, but should not
be used outside of `tracing` macros.

### Added

- **attributes**: Support constant expressions as instrument field names ([#3158])
- Add `record_all!` macro for recording multiple values in one call ([#3227])
- **core**: Improve code generation at trace points significantly ([#3398])

### Changed

- `tracing-core`: updated to 0.1.35 ([#3414])
- `tracing-attributes`: updated to 0.1.31 ([#3417])

### Fixed

- Fix "name / parent" variant of `event!` ([#2983])
- Remove 'r#' prefix from raw identifiers in field names ([#3130])
- Fix perf regression when `release_max_level_*` not set ([#3373])
- Use imported instead of fully qualified path ([#3374])
- Make `valueset` macro sanitary ([#3382])

### Documented

- **core**: Add missing `dyn` keyword in `Visit` documentation code sample ([#3387])

[#2983]: https://github.com/tokio-rs/tracing/pull/#2983
[#3130]: https://github.com/tokio-rs/tracing/pull/#3130
[#3158]: https://github.com/tokio-rs/tracing/pull/#3158
[#3227]: https://github.com/tokio-rs/tracing/pull/#3227
[#3373]: https://github.com/tokio-rs/tracing/pull/#3373
[#3374]: https://github.com/tokio-rs/tracing/pull/#3374
[#3382]: https://github.com/tokio-rs/tracing/pull/#3382
[#3387]: https://github.com/tokio-rs/tracing/pull/#3387
[#3398]: https://github.com/tokio-rs/tracing/pull/#3398
[#3414]: https://github.com/tokio-rs/tracing/pull/#3414
[#3417]: https://github.com/tokio-rs/tracing/pull/#3417
[`Span::record_all`]: https://docs.rs/tracing/0.1.41/tracing/struct.Span.html#method.record_all
hds added a commit that referenced this pull request Nov 26, 2025
# 0.1.42 (November 26, 2025)

### Important

The [`Span::record_all`] method has been removed from the documented API. It
was always unsuable via the documented API as it requried a `ValueSet` which
has no publically documented constructors. The method remains, but should not
be used outside of `tracing` macros.

### Added

- **attributes**: Support constant expressions as instrument field names ([#3158])
- Add `record_all!` macro for recording multiple values in one call ([#3227])
- **core**: Improve code generation at trace points significantly ([#3398])

### Changed

- `tracing-core`: updated to 0.1.35 ([#3414])
- `tracing-attributes`: updated to 0.1.31 ([#3417])

### Fixed

- Fix "name / parent" variant of `event!` ([#2983])
- Remove 'r#' prefix from raw identifiers in field names ([#3130])
- Fix perf regression when `release_max_level_*` not set ([#3373])
- Use imported instead of fully qualified path ([#3374])
- Make `valueset` macro sanitary ([#3382])

### Documented

- **core**: Add missing `dyn` keyword in `Visit` documentation code sample ([#3387])

[#2983]: https://github.com/tokio-rs/tracing/pull/#2983
[#3130]: https://github.com/tokio-rs/tracing/pull/#3130
[#3158]: https://github.com/tokio-rs/tracing/pull/#3158
[#3227]: https://github.com/tokio-rs/tracing/pull/#3227
[#3373]: https://github.com/tokio-rs/tracing/pull/#3373
[#3374]: https://github.com/tokio-rs/tracing/pull/#3374
[#3382]: https://github.com/tokio-rs/tracing/pull/#3382
[#3387]: https://github.com/tokio-rs/tracing/pull/#3387
[#3398]: https://github.com/tokio-rs/tracing/pull/#3398
[#3414]: https://github.com/tokio-rs/tracing/pull/#3414
[#3417]: https://github.com/tokio-rs/tracing/pull/#3417
[`Span::record_all`]: https://docs.rs/tracing/0.1.41/tracing/struct.Span.html#method.record_all
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants