Description
During the last 10 month, helping to maintain this library, I had several ideas how to enhance rust-prometheus. I prototyped my ideas, starting from scratch end of last year, somewhat accidentally ending up with a full-featured client library - rust-open-metrics-client. Below I want to describe the differences between rust-prometheus and rust-open-metrics-client.
I am posting this here first off to collect feedback. In case people like some of my ideas, we could port them to rust-prometheus.
-
Strongly typed label sets: While rust-prometheus treats both label keys and values as strings, rust-open-metrics-client allows any Rust type to act as a label set. More concretely with rust-open-metrics-client one can use both
(String, String)
as a label set, as well as a defined custom type. Example:#[derive(Clone, Hash, PartialEq, Eq, Encode)] struct Labels { method: Method, path: String, }; #[derive(Clone, Hash, PartialEq, Eq, Encode)] enum Method { GET, PUT, }; let http_requests = Family::<Labels, Counter<AtomicU64>>::default(); http_requests.get_or_create( &Labels { method: Method::GET, path: "/metrics".to_string() } ).inc();
Using a custom type instead of some string type gives the user all of the safety benefits the Rust type system provides. In addition, using simple enums instead of a string allows various optimizations, as the former can potentially be stack allocated.
-
Reduced allocations in hot-path: There are two performance critical paths when instrumenting applications, metric tracking and metric encoding. I think rust-prometheus can improve in the latter case. I.e. the
Collector
trait forces string allocations of the metric type, help,name, ... on each collect call. rust-open-metrics-client instead uses the visitor pattern, requiring no allocations when collecting, instead, directly writing the encoded metrics out to the provided I/O resource. This leads to a large performance improvement of ~40% (see benchmarks). -
Smaller scoped metric metadata: In rust-prometheus metric metadata (name, help, type) is both carried by the metric reference passed to business logic as well as the metric reference owned by the metric registry. rust-open-meitrcs-client tracks metric metadata in the registry only. The metric reference owned by the business logic e.g. compiles down to a plain
AtomicXXX
for a counter. -
Access to underlying atomics: rust-open-metrics-client allows advanced users to access the underlying atomic. Useful e.g. for Tracking peak/max value #358.
-
Open Metrics Compliance: rust-open-metrics-client is compatible with the Open Metrics specification. Given that the Open Metrics format is backwardds-compatible with the Prometheus format, rust-open-metrics-client is compatible with both the Open Metrics format as well as the Prometheus format.
You can find the code of rust-open-metrics-client here. In addition I hope I did a reasonable job documenting the crate.
Curious what you think and whether you would like to see any of the features of rust-open-metrics-client to be ported to rust-prometheus.