yeah, that's annoying, but that's somewhat to be expected: rust doesn't have builtin runtime reflection by design, (think java java.lang.reflect
, C# System.Reflection
, etc), libraries have to pick some mechanism to do runtime inspection if they want to support arbitrary user defined types, and being generic isn't always feasible.
in the case of tracing
, the trade off (between usability and flexibility) is, in most common cases, you can record your custom type with the string representation through Display
or Debug
; but you still have the option to control how the inspection should behave through Valuable
if the former doesn't suit your need.
personally, I think this design is good enough, as I barely need to record very complicated states into traces, and Valuable
isn't too hard to incorporate into my own code. altough the valuable
feature is explicitly stated to be unstable API, I don't see it will be ditched very soon, after all, they need to support some form of runtime inspection anyway. yeah, visitor pattern is OO, and I don't like it, but that's what we have today.
serde is a perfectly valid option if Debug
(or Display
) is not suitable. and personally I would not worry about the performance in such cases.
for one thing, the tracing
crate employs many tricks to keep the overhead as low as possible, for instance, each span!()
or event!()
invocation is conditional executed, guarded by looking up through a static
·Callsite
object, and the fast path, when the callsite is disabled, is just a relaxed atomic load followed by a single branch instruction;
on the other hand, I barely instrument performance critical code paths (inside tight loops), and use mostly TRACE
level if I have to, since I like to disable TRACE
level in release builds using "release_max_level_debug" feature flag.