1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
//! # Fast, ergonomic metrics for Rust! //! //! Metered helps you measure the performance of your programs in production. //! Inspired by Coda Hale's Java metrics library, Metered makes live //! measurements easy by providing measurement declarative and procedural //! macros, and a variety of useful metrics ready out-of-the-box: //! * [`HitCount`](common/struct.HitCount.html): a counter tracking how much a //! piece of code was hit. //! * [`ErrorCount`](common/struct.ErrorCount.html): a counter tracking how many //! errors were returned -- (works on any expression returning a std `Result`) //! * [`InFlight`](common/struct.InFlight.html): a gauge tracking how many //! requests are active //! * [`ResponseTime`](common/struct.ResponseTime.html): statistics backed by an //! HdrHistogram of the duration of an expression //! * [`Throughput`](common/struct.Throughput.html): statistics backed by an //! HdrHistogram of how many times an expression is called per second. //! //! These metrics are usually applied to methods, using provided procedural //! macros that generate the boilerplate. //! //! To achieve higher performance, these stock metrics can be customized to use //! non-thread safe (`!Sync`/`!Send`) datastructures, but they default to //! thread-safe datastructures implemented using lock-free strategies where //! possible. This is an ergonomical choice to provide defaults that work in all //! situations. //! //! Metered is designed as a zero-overhead abstraction -- in the sense that the //! higher-level ergonomics should not cost over manually adding metrics. //! Notably, stock metrics will *not* allocate memory after they're initialized //! the first time. However, they are triggered at every method call and it can //! be interesting to use lighter metrics (e.g //! [`HitCount`](common/struct.HitCount.html)) in hot code paths and favour //! heavier metrics ([`Throughput`](common/struct.Throughput.html), //! [`ResponseTime`](common/struct.ResponseTime.html)) in higher-level entry //! points. //! //! If a metric you need is missing, or if you want to customize a metric (for //! instance, to track how many times a specific error occurs, or react //! depending on your return type), it is possible to implement your own metrics //! simply by implementing the [`Metric`](metric/trait.Metric.html) trait . //! //! Metered does not use statics or shared global state. Instead, it lets you //! either build your own metric registry using the metrics you need, or can //! generate a metric registry for you using method attributes. Metered will //! generate one registry per `impl` block annotated with the `metered` //! attribute, under the name provided as the `registry` parameter. By default, //! Metered will expect the registry to be accessed as `self.metrics` but the //! expression can be overridden with the `registry_expr` attribute parameter. //! See the demos for more examples. //! //! Metered will generate metric registries that derive `Debug` and //! `serde::Serialize` to extract your metrics easily. Metered generates one //! sub-registry per method annotated with the `measure` attribute, hence //! organizing metrics hierarchically. This ensures access time to metrics in //! generated registries is always constant (and, when possible, //! cache-friendly), without any overhead other than the metric itself. //! //! Metered will happily measure any method, whether it is `async` or not, and //! the metrics will work as expected (e.g, //! [`ResponseTime`](common/struct.ResponseTime.html) will return the completion //! time across `await`'ed invocations). //! //! Right now, Metered does not provide bridges to external metric storage or //! monitoring systems. Such support is planned in separate modules //! (contributions welcome!). //! //! ## Example using procedural macros (recommended) //! //! ``` //! # extern crate metered; //! # extern crate rand; //! //! use metered::{metered, Throughput, HitCount}; //! //! #[derive(Default, Debug)] //! pub struct Biz { //! metrics: BizMetrics, //! } //! //! #[metered::metered(registry = BizMetrics)] //! impl Biz { //! #[measure([HitCount, Throughput])] //! pub fn biz(&self) { //! let delay = std::time::Duration::from_millis(rand::random::<u64>() % 200); //! std::thread::sleep(delay); //! } //! } //! //! # fn main() { //! # } //! ``` //! //! In the snippet above, we will measure the //! [`HitCount`](common/struct.HitCount.html) and //! [`Throughput`](common/struct.Throughput.html) of the `biz` method. //! //! This works by first annotating the `impl` block with the `metered` //! annotation and specifying the name Metered should give to the metric //! registry (here `BizMetrics`). Later, Metered will assume the expression to //! access that repository is `self.metrics`, hence we need a `metrics` field //! with the `BizMetrics` type in `Biz`. It would be possible to use another //! field name by specificying another registry expression, such as //! `#[metered(registry = BizMetrics, registry_expr = self.my_custom_metrics)]`. //! //! Then, we must annotate which methods we wish to measure using the `measure` //! attribute, specifying the metrics we wish to apply: the metrics here are //! simply types of structures implementing the `Metric` trait, and you can //! define your own. Since there is no magic, we must ensure `self.metrics` can //! be accessed, and this will only work on methods with a `&self` or `&mut //! self` receiver. //! //! ## Example of manually using metrics //! //! ``` //! use metered::{measure, HitCount, ErrorCount}; //! //! #[derive(Default, Debug)] //! struct TestMetrics { //! hit_count: HitCount, //! error_count: ErrorCount, //! } //! //! fn test(should_fail: bool, metrics: &TestMetrics) -> Result<u32, &'static str> { //! let hit_count = &metrics.hit_count; //! let error_count = &metrics.error_count; //! measure!(hit_count, { //! measure!(error_count, { //! if should_fail { //! Err("Failed!") //! } else { //! Ok(42) //! } //! }) //! }) //! } //! ``` //! //! The code above shows how different metrics compose, and in general the kind //! of boilerplate generated by the `#[metered]` procedural macro. #![deny(missing_docs)] #![deny(warnings)] pub mod atomic; pub mod clear; pub mod common; pub mod hdr_histogram; pub mod int_counter; pub mod int_gauge; pub mod metric; pub mod time_source; pub use common::{ErrorCount, HitCount, InFlight, ResponseTime, Throughput}; pub use metered_macro::metered; /// Re-export this type so 3rd-party crates don't need to depend on the /// `aspect-rs` crate. pub use aspect::Enter; /// The `measure!` macro takes a reference to a metric and an expression. /// /// It applies the metric and the expression is returned unchanged. #[macro_export] macro_rules! measure { ($metric:ident, $e:expr) => {{ let _metric = $metric; let _enter = $crate::Enter::enter(_metric); let _result = $e; $crate::metric::on_result(_metric, _enter, &_result); _result }}; }