Eliza Weisman d24a43aaee
attributes: support arbitrary field expressions (#672)
## Motivation

Fields on spans generated by `#[instrument]` consist of the parameters
to the `instrument`ed function, and a list of optional fields with
literal values passed in the `fields` argument of the attribute. The
current API for additional user-defined fields is pretty limited, since
it only accepts literals (and doesn't accept dotted field names). It
would be nice to have an API for including additional fields with values
set by calling methods on `self` or on parameters, or by accessing
values from parameters.

## Solution

This branch extends the currently supported `fields` argument to allow
providing arbitrary expressions which are invoked within the function's
scope. This is a superset of the previous support for literal values
only. In addition, field names passed to `fields` may now contain dotted
Rust identifiers.

Implementing this required rewriting how arguments to the
`#[instrument]` attribute are parsed. Previously, we used `syn`'s
`AttributeArgs` type, which parses a comma-separated of "nested meta"
items, consisting of `$ident($nested meta)`, `$ident = $nested_meta`,
paths, and literals. By replacing the use of `AttributeArgs` with our
own types implementing `syn::parse::Parse`, we can accept more
expressions in the attribute arguments position. This also lets us
reject more invalid inputs at parse-time, which improves syntax error
reporting a bit.

One thing that's worth noting is that the current implementation will
generate an _empty_ field when a field name is provided without an `=`
and a value. This makes sense when only simple fields with literal
values are permitted. However, if we accept arbitrary expressions in the
macro, this is not the ideal behavior --- we would prefer to use the
same local variable shorthand as the function-like `tracing` macros.
However, changing this now is a breaking change. Any code which uses a
name that doesn't exist in the current scope to declare an empty field
would fail to compile, because it attempts to reference a name that
doesn't exist. Instead, I left a comment noting that this is not the
ideal behavior and it should be changed next time we're ready to break
the proc macros.

Fixes: #650

Signed-off-by: Eliza Weisman <eliza@buoyant.io>

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
2020-05-23 14:20:41 -07:00
..
2020-03-17 15:47:21 -07:00
2019-12-20 17:03:34 -08:00