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
    }};
}