Originally, metrics (and `hotmic` before it was converted) was based on an event loop that centered around `mio`'s `Poll` interface with a custom channel to read and write metrics to. That model required a dedicated thread to run to poll for writes, and ingest them, managing the internal data structures in turn. Eventually, I rewrote that portion to be based on `crossbeam-channel` but we still depended on a background thread to pop samples off the channel and process them. Instead, we've rewritten the core of metrics to be based purely on atomics, with the caveat that we still do have a background thread. Instead of a single channel that metrics are funneled into, each underlying metric becomes a single-track codepath: each metric is backed by an atomic structure which means we can pass handles to that storage as far as the callers themselves, eliminating the need to funnel metrics into the "core" where they all contend for processing. Counters are gauges are now, effectively, wrapped atomic integers, which means we can process over 100 million counter/gauge updates per core. Histograms are based on a brand-new atomic "bucket" that allows for fast, unbounded writes and the ability to snapshot at any time. The end result is that we can process a mixed workload (counter, gauge, and histogram) at sample rates of up to 30 million samples per second per core, with p999 ingest latencies of in the low hundreds of nanoseconds. Taking snapshots also now avoids stalling the event loop and driving up tail latencies for ingest, and writers can proceed with no interruption. There is still a background thread that is part of quanta's new "recent" time support, which allows a background thread to incrementally update a shared global time, which can be accessed more quickly than grabbing the time directly. For our purposes, only histograms need the time to perform the window upkeep inherent to the sliding windows we use, and the time they need can be far less precise than what quanta is capable of. This background thread is spawned automatically when creating a receiver, and drops when the receiver goes away. By default, it updates 20 times a second performing an operation which itself takes less than 100ns, so all in all, this background thread should be imperceptible, performance-wise, on all systems*. On top of all of this, we've embraced the natural pattern of defining metrics individually at the variable/field level, and added supported for proxy types, which can be acquired from a sink and embedded as fields within your existing types, which lets you directly update metrics with the ease of accessing a field in an object. Sinks still have the ability to have metrics pushed directly into them, but this just opens up more possibilities. * - famous last words |
||
---|---|---|
metrics | ||
metrics-core | ||
metrics-exporter-http | ||
metrics-exporter-log | ||
metrics-recorder-prometheus | ||
metrics-recorder-text | ||
metrics-util | ||
.gitignore | ||
CODE_OF_CONDUCT.md | ||
COPYRIGHT | ||
Cargo.toml | ||
LICENSE | ||
README.md |
README.md
metrics
metrics is a high-quality, batteries-included metrics library for Rust.
code of conduct
NOTE: All conversations and contributions to this project shall adhere to the Code of Conduct.
what's it all about?
Running applications in production can be hard when you don't have insight into what the application is doing. We're lucky to have so many good system monitoring programs and services to show us how are servers are performing, but we still have to do the work of instrumenting our applications to gain deep insight into their behavior and performance.
metrics
makes it easy to instrument your application to provide real-time insight into what's happening. It provides a straight-forward interface for you to collect metrics at different points, and a flexible approach to exporting those metrics in a way that meets your needs.
Some of the most common scenarios for collecting metrics from an application:
- see how many times a codepath was hit
- track the time it takes for a piece of code to execute
- expose internal counters and values in a standardized way
The number of reasons why you'd want to collect metrics is too large to list out here, and some applications emit metrics that have nothing to do with the application performance itself! Ultimately, metrics
strives to simply provide support for the most basic types of metrics so that you can spend more time focusing on the data you'd like to collect and less time on how you're going to accomplish that.
high-level technical features
- Supports the three most common metric types: counters, gauges, and histograms.
- Based on
metrics-core
for composability at the exporter level. - Access to ultra-high-speed timing facilities out-of-the-box with quanta.
- Scoped metrics for effortless nesting.
- Bundled with Prometheus pull endpoint capabilities by default.
performance
High. metrics
is fast enough that you'll barely notice the overhead.
There is a benchmark
example in the crate that can be run to see the type of performance acheivable on your system. A 2015 MacBook Pro (4c/8t, 2.1GHz) can push over 5 million samples per second from a single thread.