-
Couldn't load subscription status.
- Fork 837
Description
Feature Request
Crates
tracing-core
Motivation
- More easily record structured key/value pairs using
tracing_core::Valuewithout needing to take a public dependency on serde 1.0.
Proposal
David:
Implement
tracing_core::Valueto 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_anymethod to theVisittrait, where the visitor can just downcast the recorded type to whatever it wants (and, eventually, when we introduceValueSetindexing,ValueSet::get_any). We would probably add atracing::field::anyhelper function, and/or a new sigil, for recording something as anAnywithout having to cast it as adyn Any.This does have one significant downside: currently, all the
recordmethods 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, anAnytrait 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
Anyvalue type beT: Any + Debug, and recording it by wrapping it in a special struct that stores adyn Anyand a closure that downcasts theAnyto 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
Serializetypes: only known ones. If the subscriber knows specificAnytypes it wants to serialize, it could downcast them and use theirSerializeimplementations. However, it cannot say "i will record anything thatserdecan 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 + 'staticbecause 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 + 'staticcould prevent the usage of non-'staticreferences, requiring a clone to record a value. This is something thattracinghas avoided when recording other values and wouldn't hit iftracing_core::Valuesupported 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.