You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We are writing a client library and need to attach several fields to each client method call. To support both generated code and hand-written code - especially for ease of the latter - we'd love to use the #[tracing::instrument] procedural macro. By default, self gets traced using a derived Debug-like behavior (we don't actually derive or impl Debug) but we don't want that for risk of exposing PII.
While generated code could use something like #[instrument(skip_all, fields(client.name = "ExampleClient", client.method = "foo")] pub async foo(&self, name: &str) -> Result<(), Error> that puts the burden on the dev to remember to add client.name each time.
Proposal
Perhaps in concert with #1570 if self implements valueable::Valuable that could be used instead of using Debug or derived-Debug-like generated code with the caveat, however, that struct-likes are flattened...or that we can optional flatten them e.g., perhaps a "#" prefix.
Might generate something like (using stdout subscriber):
2024-10-29T22:12:23.231910Z INFO foo { client: "ExampleClient" }: ExampleClient::foo: enter
If this would be a breaking change even for v2, perhaps we can override self using #[instrument(..., fields(self = #self)] or similar to flatten the fields defined by Valuable instead of having a self field that contains them as is the case now.
Alternatives
We could include some boilerplate code or even helper functions for each method that effectively takes some data from the associated struct. For generated code this is fine, but we also expect a significant amount of hand-authored code for which this will be tedious and error-prone.
If it'd even work - I have yet to try it - we could also write our own procedural macro that would expand to #[::tracing::instrument] with our own defaults such that we're not duplicating code herein and all the problems that come with that.
However, I opened this feature request because while investigating, I ran across a number of questions asking how to do something similar and the responses were typically along the lines of "just create the spans yourself" which, as I pointed out, gets very tedious when there are a lot of associated functions (methods) one has to generate and/or write. It'd be great to at least consider different ways to support methods and attach data from the associated struct (enum, etc.) to make this scenario easier.
The text was updated successfully, but these errors were encountered:
I just ran across #1123 that is similar and provides another alternative of a #[instrument_group] or something you can attach the associated type. That would also work, so long as any fields were flattened (or could be flattened).
This isn't quite what we want because the fields are still buried in a "self" field, despite numerous attempts to flatten them. Opened tokio-rs/tracing#3124 to track a feature request (or similar).
We have options but most are rather error prone. Perhaps the best way is our own attribute macro that would expand to `#[tracing::instrument]` with appropriate defaults to attach client-level fields like `az.namespace`.
We could also write a helper function or two to just wrap the whole thing, which would also give us better control over the error or return value as well, like attaching `error.type` per our guidelines.
Feature Request
Crates
tracing
Motivation
We are writing a client library and need to attach several fields to each client method call. To support both generated code and hand-written code - especially for ease of the latter - we'd love to use the
#[tracing::instrument]
procedural macro. By default,self
gets traced using a derivedDebug
-like behavior (we don't actually derive or implDebug
) but we don't want that for risk of exposing PII.While generated code could use something like
#[instrument(skip_all, fields(client.name = "ExampleClient", client.method = "foo")] pub async foo(&self, name: &str) -> Result<(), Error>
that puts the burden on the dev to remember to addclient.name
each time.Proposal
Perhaps in concert with #1570 if
self
implementsvalueable::Valuable
that could be used instead of usingDebug
or derived-Debug
-like generated code with the caveat, however, that struct-likes are flattened...or that we can optional flatten them e.g., perhaps a "#" prefix.Thus,
Might generate something like (using stdout subscriber):
If this would be a breaking change even for v2, perhaps we can override
self
using#[instrument(..., fields(self = #self)]
or similar to flatten the fields defined byValuable
instead of having aself
field that contains them as is the case now.Alternatives
We could include some boilerplate code or even helper functions for each method that effectively takes some data from the associated struct. For generated code this is fine, but we also expect a significant amount of hand-authored code for which this will be tedious and error-prone.
If it'd even work - I have yet to try it - we could also write our own procedural macro that would expand to
#[::tracing::instrument]
with our own defaults such that we're not duplicating code herein and all the problems that come with that.However, I opened this feature request because while investigating, I ran across a number of questions asking how to do something similar and the responses were typically along the lines of "just create the spans yourself" which, as I pointed out, gets very tedious when there are a lot of associated functions (methods) one has to generate and/or write. It'd be great to at least consider different ways to support methods and attach data from the associated struct (enum, etc.) to make this scenario easier.
The text was updated successfully, but these errors were encountered: