-
Notifications
You must be signed in to change notification settings - Fork 814
Description
Feature Request
Crates
tracing-core
Motivation
- More easily record structured key/value pairs using
tracing_core::Value
without needing to take a public dependency on serde 1.0.
Proposal
David:
Implement
tracing_core::Value
to be implemented onT: dyn std::any::Any + 'static
. This would allow layers to opt-in to handle formatting of arbitrary types without requiring crates such as hyperium/http to take a public dependency ontracing_core::Value
. I haven't really thought through the ecosystem-wide implications of supporting this, but I suspect tracing-subscriber could support a registry of formatters for arbitrary types, such that subscribers and layers won't need to take an explicit dependency on a given formatter.
Eliza, continuing in #819:
Then, we could add a
Visit::record_any
method to theVisit
trait, where the visitor can just downcast the recorded type to whatever it wants (and, eventually, when we introduceValueSet
indexing,ValueSet::get_any
). We would probably add atracing::field::any
helper function, and/or a new sigil, for recording something as anAny
without having to cast it as adyn Any
.This does have one significant downside: currently, all the
record
methods fall through tofmt::Debug
. This means that if a subscriber does not have special handling for a particular type, it can just print it. However, anAny
trait object is not known to implementfmt::Debug
. This means that if you don't have a particular type to downcast to, you can't really do anything of value with anAny
.We could hack around that limitation by making the
Any
value type beT: Any + Debug
, and recording it by wrapping it in a special struct that stores adyn Any
and a closure that downcasts theAny
to its original type so that it can be formatted withDebug
. But, this is a bit awkward.This would also, critically, not allow us to record arbitrary
Serialize
types: only known ones. If the subscriber knows specificAny
types it wants to serialize, it could downcast them and use theirSerialize
implementations. However, it cannot say "i will record anything thatserde
can serialize".
To address the "I can only record types that I know how to downcast" problem, Layers and Subscribers would be encouraged to provide a registry of formatters + downcasters for std::any::Any
that the end-user (e.g., the person creating a binary executable) would register when creating their subscriber or layer.
Alternatives
Don't do this. Based off Eliza's response, I worry that supporting dyn Any + 'static
is strictly worse than something like Value::from_serde
or the current practice of extensions traits on Spans that allow users to directly write to a Subscriber's extensions.
Value::from_serde
, or something equivalent toValue::from_serde
, seems like a more general purpose and correct solution thandyn Any + 'static
because it doesn't require Layer or Subscriber-specific knowledge of types.- While Subscriber/Layer-specific extension traits are Layer/Subscriber-specific, this approach doesn't introduce a potential source of complexity and poor interoperability between Subscribers to
tracing_core
. dyn Any + 'static
could prevent the usage of non-'static
references, requiring a clone to record a value. This is something thattracing
has avoided when recording other values and wouldn't hit iftracing_core::Value
supported something serde-style serializers.
On the other hand, a registry of formatting/downcasting functions for std::any::Any
could serve nice compliment for specialized, associative collections like http::Request
and friends, in that it provides a handy escape hatch for types/crates that either can't or won't take a public dependency on tracing_core::Value
. That said, I'm not sure this benefit is worth the downsides because Serde's support for implementing Serialize/Deserialize on foreign types would handle this usecase nicely.