@@ -100,28 +100,208 @@ use syn::{
100
100
/// Instruments a function to create and enter a `tracing` [span] every time
101
101
/// the function is called.
102
102
///
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
+ ///
111
163
/// - multiple argument names can be passed to `skip`.
112
164
/// - arguments passed to `skip` do _not_ need to implement `fmt::Debug`.
113
165
///
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.
119
208
///
120
209
/// Note that overlap between the names of fields and (non-skipped) arguments
121
210
/// will result in a compile error.
122
211
///
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
+ ///
123
301
/// # Examples
302
+ ///
124
303
/// Instrumenting a function:
304
+ ///
125
305
/// ```
126
306
/// # use tracing_attributes::instrument;
127
307
/// #[instrument]
@@ -169,7 +349,7 @@ use syn::{
169
349
/// }
170
350
/// ```
171
351
///
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`:
173
353
///
174
354
/// ```
175
355
/// # use tracing_attributes::instrument;
@@ -251,7 +431,12 @@ use syn::{
251
431
/// which you implement the trait: `#[instrument(fields(tmp = std::any::type_name::<Bar>()))]`.
252
432
///
253
433
/// [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
255
440
/// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
256
441
#[ proc_macro_attribute]
257
442
pub fn instrument (
0 commit comments