metrics-rs / metrics

A metrics ecosystem for Rust.
MIT License
1.08k stars 148 forks source link

enhancement(metrics): add support for scoped (local) recorders #414

Closed tobz closed 8 months ago

tobz commented 9 months ago

Context

In #389, it's pointed out that the current situation of needing to use the undocumented metrics::clear_recorder() for testing recorders is very suboptimal. Installation of the global recorder is meant to happen once during the life of a process. Clearing the global recorder to install another is suboptimal for more than a few reasons, too:

Solution

In this PR, we've introduced the concept of scoped recorders, or local recorders as we call them. This is modeled after tracing, where a free function takes a reference to the dispatcher to temporarily set as the default, and a closure to run where only that overridden default dispatcher applies. It works on a thread-local basis so one instance of using a local recorder never conflicts with another.

A new function, metrics::with_local_recorder, takes a &dyn Recorder and a closure to run where the recorder used by the convenience macros -- counter!, etc -- will be temporarily overridden to use the given recorder.

While this feature primarily supports the ability to properly test recorder implementations, it has a side benefit that it also allows writing a Recorder implementation that does not need to be safe for concurrent use. As the local recorder override only applies to the current thread, the recorder can use something like RefCell internally, and entirely avoid locks, concurrent data structures, atomics, and so on. Between only needing to pass a temporary reference to the recorder, this means that single threaded use cases that wish to avoid the additional overhead of all of that now have the ability to do so.

Additionally, we've also changed the function for installing a global recorder, removing metrics::set_recorder and renaming metrics::set_boxed_recorder to metrics::set_global_recorder. The functions have been changed to be slightly more ergonomic (handle boxing the value for callers) but to also remove the illusion that metrics is designed to work well in no_std environments, which is generally the only reason a user would ever install a recorder via a &'static dyn Recorder reference.

Fixes #389. Fixes #409.