dipstick/README.md

147 lines
4.5 KiB
Markdown
Raw Normal View History

2018-01-08 05:32:32 +00:00
# dipstick
A quick, modular metrics toolkit for Rust applications of all types. Similar to popular logging frameworks,
but with counters, markers, gauges and timers.
2017-08-19 18:09:17 +00:00
2018-01-08 05:32:32 +00:00
[![Build Status](https://travis-ci.org/fralalonde/dipstick.svg?branch=master)](https://travis-ci.org/fralalonde/dipstick)
[![crates.io](https://img.shields.io/crates/v/dipstick.svg)](https://crates.io/crates/dipstick)
2017-12-13 19:58:42 +00:00
Dipstick's main attraction is the ability to send metrics to multiple customized outputs.
2018-01-08 05:32:32 +00:00
For example, metrics could be written immediately to the log _and_
2017-12-13 19:58:42 +00:00
sent over the network after a period of aggregation.
2018-01-08 05:32:32 +00:00
Dipstick promotes structured metrics for clean, safe code and good performance.
Dipstick builds on stable Rust with minimal dependencies.
2017-06-29 21:52:37 +00:00
## Features
2017-09-29 20:45:09 +00:00
- 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
2018-01-08 05:32:32 +00:00
## Examples
2017-09-29 20:45:09 +00:00
2018-01-08 05:32:32 +00:00
For complete applications see the [examples](https://github.com/fralalonde/dipstick/tree/master/examples).
2018-01-08 05:32:32 +00:00
To use Dipstick in your project, add the following line to your `Cargo.toml`
in the `[dependencies]` section:
```toml
2018-01-17 17:37:38 +00:00
dipstick = "0.6.5"
2017-09-28 22:17:16 +00:00
```
2018-01-08 05:32:32 +00:00
Then add it to your code:
```rust,skt-fail,no_run
2018-03-29 18:22:43 +00:00
let metrics = metric_scope(to_graphite("host.com:2003")?);
2018-01-08 05:32:32 +00:00
let counter = metrics.counter("my_counter");
counter.count(3);
```
Send metrics to multiple outputs:
```rust,skt-fail,no_run
2018-03-29 18:22:43 +00:00
let _app_metrics = metric_scope((
2018-01-08 05:32:32 +00:00
to_stdout(),
to_statsd("localhost:8125")?.with_namespace(&["my", "app"])
));
2017-09-28 22:17:16 +00:00
```
2017-09-29 20:45:09 +00:00
Since instruments are decoupled from the backend, outputs can be swapped easily.
2018-01-08 05:32:32 +00:00
Aggregate metrics and schedule to be periodical publication in the background:
```rust,skt-run
2017-09-28 22:17:16 +00:00
use std::time::Duration;
2018-01-08 05:32:32 +00:00
2018-03-29 18:22:43 +00:00
let app_metrics = metric_scope(aggregate());
2018-03-27 20:30:12 +00:00
route_aggregate_metrics(to_stdout());
2018-01-08 05:32:32 +00:00
app_metrics.flush_every(Duration::from_secs(3));
2017-09-28 22:17:16 +00:00
```
2018-01-08 05:32:32 +00:00
2017-09-29 20:45:09 +00:00
Aggregation is performed locklessly and is very fast.
2017-09-29 18:41:22 +00:00
Count, sum, min, max and average are tracked where they make sense.
2017-10-10 14:11:42 +00:00
Published statistics can be selected with presets such as `all_stats` (see previous example),
`summary`, `average`.
2017-09-29 18:41:22 +00:00
2018-01-08 05:32:32 +00:00
For more control over published statistics, provide your own strategy:
```rust,skt-run
2018-03-27 20:30:12 +00:00
metrics(aggregate());
set_default_aggregate_fn(|_kind, name, score|
match score {
ScoreType::Count(count) =>
Some((Kind::Counter, vec![name, ".per_thousand"], count / 1000)),
_ => None
});
2017-09-29 20:45:09 +00:00
```
2017-09-05 04:24:43 +00:00
2018-01-08 05:32:32 +00:00
Apply statistical sampling to metrics:
```rust,skt-fail
2018-03-29 18:22:43 +00:00
let _app_metrics = metric_scope(to_statsd("server:8125")?.with_sampling_rate(0.01));
```
2017-09-29 20:45:09 +00:00
A fast random algorithm is used to pick samples.
Outputs can use sample rate to expand or format published data.
2017-10-10 14:11:42 +00:00
Metrics can be recorded asynchronously:
2018-01-08 05:32:32 +00:00
```rust,skt-run
2018-03-29 18:22:43 +00:00
let _app_metrics = metric_scope(to_stdout().with_async_queue(64));
2017-09-28 22:17:16 +00:00
```
2017-10-10 14:11:42 +00:00
The async queue uses a Rust channel and a standalone thread.
The current behavior is to block when full.
2017-09-28 22:17:16 +00:00
2018-01-17 16:24:25 +00:00
For speed and easier maintenance, metrics are usually defined statically:
2018-01-08 05:32:32 +00:00
```rust,skt-plain
2018-01-16 20:00:47 +00:00
#[macro_use] extern crate dipstick;
2018-01-08 05:32:32 +00:00
#[macro_use] extern crate lazy_static;
use dipstick::*;
2017-09-29 20:45:09 +00:00
2018-03-29 18:22:43 +00:00
dispatch_metrics!("my_app" => {
2018-03-13 13:54:12 +00:00
@Counter COUNTER_A: "counter_a";
2018-01-16 20:00:47 +00:00
});
2018-01-08 05:32:32 +00:00
fn main() {
2018-03-27 20:30:12 +00:00
route_aggregate_metrics(to_stdout());
2018-01-08 05:32:32 +00:00
COUNTER_A.count(11);
2017-09-29 20:45:09 +00:00
}
```
2018-01-16 20:00:47 +00:00
Metric definition macros are just `lazy_static!` wrappers.
Where necessary, metrics can be defined _ad-hoc_:
```rust,skt-run
let user_name = "john_day";
2018-03-29 18:22:43 +00:00
let app_metrics = metric_scope(to_log()).with_cache(512);
2018-01-16 20:00:47 +00:00
app_metrics.gauge(format!("gauge_for_user_{}", user_name)).value(44);
```
Defining a cache is optional but will speed up re-definition of common ad-hoc metrics.
2017-10-10 14:11:42 +00:00
Timers can be used multiple ways:
2018-01-08 05:32:32 +00:00
```rust,skt-run
2018-03-29 18:22:43 +00:00
let app_metrics = metric_scope(to_stdout());
2017-09-28 22:17:16 +00:00
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);
2017-09-28 22:17:16 +00:00
timer.interval_us(123_456);
2017-06-29 21:52:37 +00:00
```
2017-10-10 14:11:42 +00:00
Related metrics can share a namespace:
2018-01-08 05:32:32 +00:00
```rust,skt-run
2018-03-29 18:22:43 +00:00
let app_metrics = metric_scope(to_stdout());
2018-06-21 15:52:10 +00:00
let db_metrics = app_metrics.add_prefix("database");
2018-01-08 05:32:32 +00:00
let _db_timer = db_metrics.timer("db_timer");
let _db_counter = db_metrics.counter("db_counter");
2017-09-28 22:17:16 +00:00
```
2018-01-08 05:32:32 +00:00
## License
Dipstick is licensed under the terms of the Apache 2.0 and MIT license.
2017-09-29 20:45:09 +00:00