@@ -100,28 +100,208 @@ use syn::{
100100/// Instruments a function to create and enter a `tracing` [span] every time
101101/// the function is called.
102102///
103- /// Unless overriden, a span with `info` level will be generated.
104- /// The generated span's name will be the name of the function. Any arguments
105- /// to that function will be recorded as fields using [`fmt::Debug`]. To skip
106- /// recording a function's or method's argument, pass the argument's name
107- /// to the `skip` argument on the `#[instrument]` macro. For example,
108- /// `skip` can be used when an argument to an instrumented function does
109- /// not implement [`fmt::Debug`], or to exclude an argument with a verbose
110- /// or costly Debug implementation. Note that:
103+ /// By default, the generated span's [name] will be the name of the function,
104+ /// the span's [target] will be the current module path, and the span's [level]
105+ /// will be [`INFO`], although these properties can be overridden. Any arguments
106+ /// to that function will be recorded as fields using [`fmt::Debug`].
107+ ///
108+ /// # Overriding Span Attributes
109+ ///
110+ /// To change the [name] of the generated span, add a `name` argument to the
111+ /// `#[instrument]` macro, followed by an equals sign and a string literal. For
112+ /// example:
113+ ///
114+ /// ```
115+ /// # use tracing_attributes::instrument;
116+ ///
117+ /// // The generated span's name will be "my_span" rather than "my_function".
118+ /// #[instrument(name = "my_span")]
119+ /// pub fn my_function() {
120+ /// // ... do something incredibly interesting and important ...
121+ /// }
122+ /// ```
123+ ///
124+ /// To override the [target] of the generated span, add a `target` argument to
125+ /// the `#[instrument]` macro, followed by an equals sign and a string literal
126+ /// for the new target. The [module path] is still recorded separately. For
127+ /// example:
128+ ///
129+ /// ```
130+ /// pub mod my_module {
131+ /// # use tracing_attributes::instrument;
132+ /// // The generated span's target will be "my_crate::some_special_target",
133+ /// // rather than "my_crate::my_module".
134+ /// #[instrument(target = "my_crate::some_special_target")]
135+ /// pub fn my_function() {
136+ /// // ... all kinds of neat code in here ...
137+ /// }
138+ /// }
139+ /// ```
140+ ///
141+ /// Finally, to override the [level] of the generated span, add a `level`
142+ /// argument, followed by an equals sign and a string literal with the name of
143+ /// the desired level. Level names are not case sensitive. For example:
144+ ///
145+ /// ```
146+ /// # use tracing_attributes::instrument;
147+ /// // The span's level will be TRACE rather than INFO.
148+ /// #[instrument(level = "trace")]
149+ /// pub fn my_function() {
150+ /// // ... I have written a truly marvelous implementation of this function,
151+ /// // which this example is too narrow to contain ...
152+ /// }
153+ /// ```
154+ ///
155+ /// # Skipping Fields
156+ ///
157+ /// To skip recording one or more arguments to a function or method, pass
158+ /// the argument's name inside the `skip()` argument on the `#[instrument]`
159+ /// macro. This can be used when an argument to an instrumented function does
160+ /// not implement [`fmt::Debug`], or to exclude an argument with a verbose or
161+ /// costly `Debug` implementation. Note that:
162+ ///
111163/// - multiple argument names can be passed to `skip`.
112164/// - arguments passed to `skip` do _not_ need to implement `fmt::Debug`.
113165///
114- /// You can also pass additional fields (key-value pairs with arbitrary data)
115- /// to the generated span. This is achieved using the `fields` argument on the
116- /// `#[instrument]` macro. You can use a string, integer or boolean literal as
117- /// a value for each field. The name of the field must be a single valid Rust
118- /// identifier, nested (dotted) field names are not supported.
166+ /// ## Examples
167+ ///
168+ /// ```
169+ /// # use tracing_attributes::instrument;
170+ /// // This type doesn't implement `fmt::Debug`!
171+ /// struct NonDebug;
172+ ///
173+ /// // `arg` will be recorded, while `non_debug` will not.
174+ /// #[instrument(skip(non_debug))]
175+ /// fn my_function(arg: usize, non_debug: NonDebug) {
176+ /// // ...
177+ /// }
178+ /// ```
179+ ///
180+ /// Skipping the `self` parameter:
181+ ///
182+ /// ```
183+ /// # use tracing_attributes::instrument;
184+ /// #[derive(Debug)]
185+ /// struct MyType {
186+ /// data: Vec<u8>, // Suppose this buffer is often quite long...
187+ /// }
188+ ///
189+ /// impl MyType {
190+ /// // Suppose we don't want to print an entire kilobyte of `data`
191+ /// // every time this is called...
192+ /// #[instrument(skip(self))]
193+ /// pub fn my_method(&mut self, an_interesting_argument: usize) {
194+ /// // ... do something (hopefully, using all that `data`!)
195+ /// }
196+ /// }
197+ /// ```
198+ ///
199+ /// # Adding Fields
200+ ///
201+ /// Additional fields (key-value pairs with arbitrary data) may be added to the
202+ /// generated span using the `fields` argument on the `#[instrument]` macro. Any
203+ /// Rust expression can be used as a field value in this manner. These
204+ /// expressions will be evaluated at the beginning of the function's body, sso
205+ /// arguments to the function may be used in these expressions. Field names may
206+ /// also be specified *without* values. Doing so will result in an [empty field]
207+ /// whose value may be recorded later within the function body.
119208///
120209/// Note that overlap between the names of fields and (non-skipped) arguments
121210/// will result in a compile error.
122211///
212+ /// ## Examples
213+ ///
214+ /// Adding a new field based on the value of an argument:
215+ ///
216+ /// ```
217+ /// # use tracing_attributes::instrument;
218+ ///
219+ /// // This will record a field named "i" with the value of `i` *and* a field
220+ /// // named "next" with the value of `i` + 1.
221+ /// #[instrument(fields(next = i + 1))]
222+ /// pub fn my_function(i: usize) {
223+ /// // ...
224+ /// }
225+ /// ```
226+ ///
227+ /// Recording specific properties of a struct as their own fields:
228+ ///
229+ /// ```
230+ /// # mod http {
231+ /// # pub struct Error;
232+ /// # pub struct Response<B> { pub(super) _b: std::marker::PhantomData<B> }
233+ /// # pub struct Request<B> { _b: B }
234+ /// # impl<B> std::fmt::Debug for Request<B> {
235+ /// # fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236+ /// # f.pad("request")
237+ /// # }
238+ /// # }
239+ /// # impl<B> Request<B> {
240+ /// # pub fn uri(&self) -> &str { "fake" }
241+ /// # pub fn method(&self) -> &str { "GET" }
242+ /// # }
243+ /// # }
244+ /// # use tracing_attributes::instrument;
245+ ///
246+ /// // This will record the request's URI and HTTP method as their own separate
247+ /// // fields.
248+ /// #[instrument(fields(http.uri = req.uri(), http.method = req.method()))]
249+ /// pub fn handle_request<B>(req: http::Request<B>) -> http::Response<B> {
250+ /// // ... handle the request ...
251+ /// # http::Response { _b: std::marker::PhantomData }
252+ /// }
253+ /// ```
254+ ///
255+ /// This can be used in conjunction with `skip` to record only some fields of a
256+ /// struct:
257+ /// ```
258+ /// # use tracing_attributes::instrument;
259+ /// // Remember the struct with the very large `data` field from the earlier
260+ /// // example? Now it also has a `name`, which we might want to include in
261+ /// // our span.
262+ /// #[derive(Debug)]
263+ /// struct MyType {
264+ /// name: &'static str,
265+ /// data: Vec<u8>,
266+ /// }
267+ ///
268+ /// impl MyType {
269+ /// // This will skip the `data` field, but will include `self.name`,
270+ /// // formatted using `fmt::Display`.
271+ /// #[instrument(skip(self), fields(self.name = %self.name))]
272+ /// pub fn my_method(&mut self, an_interesting_argument: usize) {
273+ /// // ... do something (hopefully, using all that `data`!)
274+ /// }
275+ /// }
276+ /// ```
277+ ///
278+ /// Adding an empty field to be recorded later:
279+ ///
280+ /// ```
281+ /// # use tracing_attributes::instrument;
282+ ///
283+ /// // This function does a very interesting and important mathematical calculation.
284+ /// // Suppose we want to record both the inputs to the calculation *and* its result...
285+ /// #[instrument(fields(result))]
286+ /// pub fn do_calculation(input_1: usize, input_2: usize) -> usize {
287+ /// // Rerform the calculation.
288+ /// let result = input_1 + input_2;
289+ ///
290+ /// // Record the result as part of the current span.
291+ /// tracing::Span::current().record("result", &result);
292+ ///
293+ /// // Now, the result will also be included on this event!
294+ /// tracing::info!("calculation complete!");
295+ ///
296+ /// // ... etc ...
297+ /// # 0
298+ /// }
299+ /// ```
300+ ///
123301/// # Examples
302+ ///
124303/// Instrumenting a function:
304+ ///
125305/// ```
126306/// # use tracing_attributes::instrument;
127307/// #[instrument]
@@ -169,7 +349,7 @@ use syn::{
169349/// }
170350/// ```
171351///
172- /// To add an additional context to the span, you can pass key-value pairs to `fields`:
352+ /// To add an additional context to the span, pass key-value pairs to `fields`:
173353///
174354/// ```
175355/// # use tracing_attributes::instrument;
@@ -251,7 +431,12 @@ use syn::{
251431/// which you implement the trait: `#[instrument(fields(tmp = std::any::type_name::<Bar>()))]`.
252432///
253433/// [span]: https://docs.rs/tracing/latest/tracing/span/index.html
254- /// [`tracing`]: https://github.com/tokio-rs/tracing
434+ /// [name]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.name
435+ /// [target]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.target
436+ /// [level]: https://docs.rs/tracing/latest/tracing/struct.Level.html
437+ /// [module path]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.module_path
438+ /// [`INFO`]: https://docs.rs/tracing/latest/tracing/struct.Level.html#associatedconstant.INFO
439+ /// [empty field]: https://docs.rs/tracing/latest/tracing/field/struct.Empty.html
255440/// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
256441#[ proc_macro_attribute]
257442pub fn instrument (
0 commit comments