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 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
/*! A quick, modular metrics toolkit for Rust applications; similar to popular logging frameworks, but with counters, markers, gauges and timers. Dipstick builds on stable Rust with minimal dependencies and is published as a [crate.](https://crates.io/crates/dipstick) # Features - Send metrics to stdout, log, statsd or graphite (one or many) - Synchronous, asynchronous or mixed operation - Optional fast random statistical sampling - Immediate propagation or local aggregation of metrics (count, sum, average, min/max) - Periodic or programmatic publication of aggregated metrics - Customizable output statistics and formatting - Global or scoped (e.g. per request) metrics - Per-application and per-output metric namespaces - Predefined or ad-hoc metrics # Cookbook Dipstick is easy to add to your code: ```rust use dipstick::*; let app_metrics = metrics(to_graphite("host.com:2003")); app_metrics.counter("my_counter").count(3); ``` Metrics can be sent to multiple outputs at the same time: ```rust let app_metrics = metrics((to_stdout(), to_statsd("localhost:8125", "app1.host."))); ``` Since instruments are decoupled from the backend, outputs can be swapped easily. Metrics can be aggregated and scheduled to be published periodically in the background: ```rust use std::time::Duration; let (to_aggregate, from_aggregate) = aggregate(); publish_every(Duration::from_secs(10), from_aggregate, to_log("last_ten_secs:"), all_stats); let app_metrics = metrics(to_aggregate); ``` Aggregation is performed locklessly and is very fast. Count, sum, min, max and average are tracked where they make sense. Published statistics can be selected with presets such as `all_stats` (see previous example), `summary`, `average`. For more control over published statistics, a custom filter can be provided: ```rust let (_to_aggregate, from_aggregate) = aggregate(); publish(from_aggregate, to_log("my_custom_stats:"), |metric_kind, metric_name, metric_score| match metric_score { HitCount(hit_count) => Some((Counter, vec![metric_name, ".per_thousand"], hit_count / 1000)), _ => None }); ``` Metrics can be statistically sampled: ```rust let app_metrics = metrics(sample(0.001, to_statsd("server:8125", "app.sampled."))); ``` A fast random algorithm is used to pick samples. Outputs can use sample rate to expand or format published data. Metrics can be recorded asynchronously: ```rust let app_metrics = metrics(async(48, to_stdout())); ``` The async queue uses a Rust channel and a standalone thread. The current behavior is to block when full. Metric definitions can be cached to make using _ad-hoc metrics_ faster: ```rust let app_metrics = metrics(cache(512, to_log())); app_metrics.gauge(format!("my_gauge_{}", 34)).value(44); ``` The preferred way is to _predefine metrics_, possibly in a [lazy_static!](https://crates.io/crates/lazy_static) block: ```rust #[macro_use] external crate lazy_static; lazy_static! { pub static ref METRICS: GlobalMetrics<String> = metrics(to_stdout()); pub static ref COUNTER_A: Counter<Aggregate> = METRICS.counter("counter_a"); } COUNTER_A.count(11); ``` Timers can be used multiple ways: ```rust let timer = app_metrics.timer("my_timer"); time!(timer, {/* slow code here */} ); timer.time(|| {/* slow code here */} ); let start = timer.start(); /* slow code here */ timer.stop(start); timer.interval_us(123_456); ``` Related metrics can share a namespace: ```rust let db_metrics = app_metrics.with_prefix("database."); let db_timer = db_metrics.timer("db_timer"); let db_counter = db_metrics.counter("db_counter"); ``` */ #![cfg_attr(feature = "bench", feature(test))] #![warn( missing_copy_implementations, missing_docs, trivial_casts, trivial_numeric_casts, unused_extern_crates, unused_import_braces, unused_qualifications, // variant_size_differences, )] #[cfg(feature = "bench")] extern crate test; #[macro_use] extern crate log; extern crate time; extern crate num; #[macro_use] extern crate lazy_static; #[macro_use] extern crate derivative; mod pcg32; mod lru_cache; pub mod error; pub use error::*; pub mod core; pub use core::*; pub mod macros; mod output; pub use output::*; mod global_metrics; pub use global_metrics::*; mod scope_metrics; pub use scope_metrics::*; mod sample; pub use sample::*; mod scores; pub use scores::*; mod aggregate; pub use aggregate::*; mod publish; pub use publish::*; mod statsd; pub use statsd::*; mod namespace; pub use namespace::*; mod graphite; pub use graphite::*; mod socket; pub use socket::*; mod cache; pub use cache::*; mod multi; pub use multi::*; mod async; pub use async::*; mod schedule; pub use schedule::*; mod self_metrics; pub use self_metrics::snapshot;