cadence_with_flush/
lib.rs

1// Cadence - An extensible Statsd client for Rust!
2//
3// Copyright 2015-2021 Nick Pillitteri
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! An extensible Statsd client for Rust!
12//!
13//! Cadence is a fast and flexible way to emit Statsd metrics from your application.
14//!
15//! ## Features
16//!
17//! * [Support](https://docs.rs/cadence/) for emitting counters, timers, histograms, distributions,
18//!   gauges, meters, and sets to Statsd over UDP (or optionally Unix sockets).
19//! * Support for alternate backends via the `MetricSink` trait.
20//! * Support for [Datadog](https://docs.datadoghq.com/developers/dogstatsd/) style metrics tags.
21//! * [Macros](https://docs.rs/cadence-macros/) to simplify common calls to emit metrics
22//! * A simple yet flexible API for sending metrics.
23//!
24//! ## Install
25//!
26//! To make use of `cadence` in your project, add it as a dependency in your `Cargo.toml` file.
27//!
28//! ```toml
29//! [dependencies]
30//! cadence = "x.y.z"
31//! ```
32//!
33//! That's all you need!
34//!
35//! ## Usage
36//!
37//! Some examples of how to use Cadence are shown below. The examples start
38//! simple and work up to how you should be using Cadence in a production
39//! application.
40//!
41//! ### Simple Use
42//!
43//! Simple usage of Cadence is shown below. In this example, we just import
44//! the client, create an instance that will write to some imaginary metrics
45//! server, and send a few metrics.
46//!
47//! ```rust,no_run
48//! use std::net::UdpSocket;
49//! use cadence::prelude::*;
50//! use cadence::{StatsdClient, UdpMetricSink, DEFAULT_PORT};
51//!
52//! // Create client that will write to the given host over UDP.
53//! //
54//! // Note that you'll probably want to actually handle any errors creating
55//! // the client when you use it for real in your application. We're just
56//! // using .unwrap() here since this is an example!
57//! let host = ("metrics.example.com", DEFAULT_PORT);
58//! let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
59//! let sink = UdpMetricSink::from(host, socket).unwrap();
60//! let client = StatsdClient::from_sink("my.metrics", sink);
61//!
62//! // Emit metrics!
63//! client.count("some.counter", 1);
64//! client.time("some.methodCall", 42);
65//! client.gauge("some.thing", 7);
66//! client.meter("some.value", 5);
67//! ```
68//!
69//! ### Buffered UDP Sink
70//!
71//! While sending a metric over UDP is very fast, the overhead of frequent
72//! network calls can start to add up. This is especially true if you are
73//! writing a high performance application that emits a lot of metrics.
74//!
75//! To make sure that metrics aren't interfering with the performance of
76//! your application, you may want to use a `MetricSink` implementation that
77//! buffers multiple metrics before sending them in a single network
78//! operation. For this, there's `BufferedUdpMetricSink`. An example of
79//! using this sink is given below.
80//!
81//! ```rust,no_run
82//! use std::net::UdpSocket;
83//! use cadence::prelude::*;
84//! use cadence::{StatsdClient, BufferedUdpMetricSink, DEFAULT_PORT};
85//!
86//! let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
87//! socket.set_nonblocking(true).unwrap();
88//!
89//! let host = ("metrics.example.com", DEFAULT_PORT);
90//! let sink = BufferedUdpMetricSink::from(host, socket).unwrap();
91//! let client = StatsdClient::from_sink("my.prefix", sink);
92//!
93//! client.count("my.counter.thing", 29);
94//! client.time("my.service.call", 214);
95//! ```
96//!
97//! As you can see, using this buffered UDP sink is no more complicated
98//! than using the regular, non-buffered, UDP sink.
99//!
100//! The only downside to this sink is that metrics aren't written to the
101//! Statsd server until the buffer is full. If you have a busy application
102//! that is constantly emitting metrics, this shouldn't be a problem.
103//! However, if your application only occasionally emits metrics, this sink
104//! might result in the metrics being delayed for a little while until the
105//! buffer fills. In this case, it may make sense to use the `UdpMetricSink`
106//! since it does not do any buffering.
107//!
108//! ### Queuing Asynchronous Metric Sink
109//!
110//! To make sure emitting metrics doesn't interfere with the performance
111//! of your application (even though emitting metrics is generally quite
112//! fast), it's probably a good idea to make sure metrics are emitted in
113//! in a different thread than your application thread.
114//!
115//! To allow you to do this, there is `QueuingMetricSink`. This sink allows
116//! you to wrap any other metric sink and send metrics to it via a queue,
117//! as it emits metrics in another thread, asynchronously from the flow of
118//! your application.
119//!
120//! The requirements for the wrapped metric sink are that it is thread
121//! safe, meaning that it implements the `Send` and `Sync` traits. If
122//! you're using the `QueuingMetricSink` with another sink from Cadence,
123//! you don't need to worry: they are all thread safe.
124//!
125//! An example of using the `QueuingMetricSink` to wrap a buffered UDP
126//! metric sink is given below. This is the preferred way to use Cadence
127//! in production.
128//!
129//! ```rust,no_run
130//! use std::net::UdpSocket;
131//! use cadence::prelude::*;
132//! use cadence::{StatsdClient, QueuingMetricSink, BufferedUdpMetricSink, DEFAULT_PORT};
133//!
134//! let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
135//! socket.set_nonblocking(true).unwrap();
136//!
137//! let host = ("metrics.example.com", DEFAULT_PORT);
138//! let udp_sink = BufferedUdpMetricSink::from(host, socket).unwrap();
139//! let queuing_sink = QueuingMetricSink::from(udp_sink);
140//! let client = StatsdClient::from_sink("my.prefix", queuing_sink);
141//!
142//! client.count("my.counter.thing", 29);
143//! client.time("my.service.call", 214);
144//! ```
145//!
146//! In the example above, we use the default constructor for the queuing
147//! sink which creates an **unbounded** queue, with no maximum size, to connect
148//! the main thread where the client sends metrics to the background thread
149//! in which the wrapped sink is running. If instead, you want to create a
150//! **bounded** queue with a maximum size, you can use the `with_capacity`
151//! constructor. An example of this is given below.
152//!
153//! ```rust,no_run
154//! use std::net::UdpSocket;
155//! use cadence::prelude::*;
156//! use cadence::{StatsdClient, QueuingMetricSink, BufferedUdpMetricSink,
157//!               DEFAULT_PORT};
158//!
159//! // Queue with a maximum capacity of 128K elements
160//! const QUEUE_SIZE: usize = 128 * 1024;
161//!
162//! let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
163//! socket.set_nonblocking(true).unwrap();
164//!
165//! let host = ("metrics.example.com", DEFAULT_PORT);
166//! let udp_sink = BufferedUdpMetricSink::from(host, socket).unwrap();
167//! let queuing_sink = QueuingMetricSink::with_capacity(udp_sink, QUEUE_SIZE);
168//! let client = StatsdClient::from_sink("my.prefix", queuing_sink);
169//!
170//! client.count("my.counter.thing", 29);
171//! client.time("my.service.call", 214);
172//! ```
173//!
174//! Using a `QueuingMetricSink` with a capacity set means that when the queue
175//! is full, attempts to emit metrics via the `StatsdClient` will fail. While
176//! this is bad, the alternative (if you instead used an unbounded queue) is
177//! for unsent metrics to slowly use up more and more memory until your
178//! application exhausts all memory.
179//!
180//! Using an **unbounded** queue means that the sending of metrics can absorb
181//! slowdowns of sending metrics until your application runs out of memory.
182//! Using a **bounded** queue puts a cap on the amount of memory that sending
183//! metrics will use in your application. This is a tradeoff that users of
184//! Cadence must decide for themselves.
185//!
186//! ### Use With Tags
187//!
188//! Adding tags to metrics is accomplished via the use of each of the `_with_tags`
189//! methods that are part of the Cadence `StatsdClient` struct. An example of using
190//! these methods is given below. Note that tags are an extension to the Statsd
191//! protocol and so may not be supported by all servers.
192//!
193//! See the [Datadog docs](https://docs.datadoghq.com/developers/dogstatsd/) for
194//! more information.
195//!
196//! ```rust,no_run
197//! use cadence::prelude::*;
198//! use cadence::{Metric, StatsdClient, NopMetricSink};
199//!
200//! let client = StatsdClient::from_sink("my.prefix", NopMetricSink);
201//!
202//! let res = client.count_with_tags("my.counter", 29)
203//!     .with_tag("host", "web03.example.com")
204//!     .with_tag_value("beta-test")
205//!     .try_send();
206//!
207//! assert_eq!(
208//!     concat!(
209//!         "my.prefix.my.counter:29|c|#",
210//!         "host:web03.example.com,",
211//!         "beta-test"
212//!     ),
213//!     res.unwrap().as_metric_str()
214//! );
215//! ```
216//!
217//! ### Default Tags
218//!
219//! Default tags can be added to a `StatsdClient` when constructed using the builder.
220//! Default tags are added to every metric emitted by the `StatsdClient` without any
221//! extra work after building the client. Note that tags are an extension to the Statsd
222//! protocol and so may not be supported by all servers.
223//!
224//! See the [Datadog docs](https://docs.datadoghq.com/developers/dogstatsd/) for
225//! more information.
226//!
227//! ```rust,no_run
228//! use cadence::prelude::*;
229//! use cadence::{Metric, StatsdClient, NopMetricSink};
230//!
231//! let client = StatsdClient::builder("my.prefix", NopMetricSink)
232//!     .with_tag("env", "prod")
233//!     .with_tag("app", "auth")
234//!     .build();
235//!
236//! let res = client.count_with_tags("my.counter", 29)
237//!     .with_tag("host", "web03.example.com")
238//!     .with_tag_value("beta-test")
239//!     .try_send();
240//!
241//! assert_eq!(
242//!     concat!(
243//!         "my.prefix.my.counter:29|c|#",
244//!         "env:prod,",
245//!         "app:auth,",
246//!         "host:web03.example.com,",
247//!         "beta-test"
248//!     ),
249//!     res.unwrap().as_metric_str()
250//! );
251//! ```
252//!
253//! ### Value Packing
254//!
255//! Value packing allows multiple values to be sent as a single metric for histograms,
256//! distributions, and timer types. The Cadence client accepts `Vec<T>` for histogram,
257//! distribution, and timer methods and will format multiple values as described below.
258//! Note that this feature is a Datadog extension and so may not be supported by your
259//! server. It is supported by versions `>=v6.25.0 && <v7.0.0` or `>=v7.25.0` of the
260//! Datadog agent.
261//!
262//! Packed metrics have the following format:
263//! ```text
264//! <METRIC_NAME>:<VALUE1>:<VALUE2>:<VALUE3>|<TYPE>|#<TAG_KEY_1>:<TAG_VALUE_1>,<TAG_2>`
265//! ```
266//!
267//! See the [Datadog Docs](https://docs.datadoghq.com/developers/dogstatsd/datagram_shell/?tab=metrics#dogstatsd-protocol-v11)
268//! for more information.
269//!
270//! ```rust,no_run
271//! use cadence::prelude::*;
272//! use cadence::{Metric, StatsdClient, NopMetricSink};
273//!
274//! let client = StatsdClient::from_sink("my.prefix", NopMetricSink);
275//!
276//! let res = client.distribution_with_tags("my.distribution", vec![29, 30, 31, 32])
277//!     .with_tag("host", "web03.example.com")
278//!     .with_tag_value("beta-test")
279//!     .try_send();
280//!
281//! assert_eq!(
282//!     concat!(
283//!         "my.prefix.my.distribution:29:30:31:32|d|#",
284//!         "host:web03.example.com,",
285//!         "beta-test"
286//!     ),
287//!     res.unwrap().as_metric_str()
288//! );
289//! ```
290//!
291//! ### Implemented Traits
292//!
293//! Each of the methods that the Cadence `StatsdClient` struct uses to send
294//! metrics are implemented as a trait. There is also a trait that combines
295//! all of these other traits. If we want, we can just use one of the trait
296//! types to refer to the client instance. This might be useful to you if
297//! you'd like to swap out the actual Cadence client with a dummy version
298//! when you are unit testing your code or want to abstract away all the
299//! implementation details of the client being used behind a trait and
300//! pointer.
301//!
302//! Each of these traits are exported in the prelude module. They are also
303//! available in the main module but aren't typically used like that.
304//!
305//! ```rust,no_run
306//! use std::net::UdpSocket;
307//! use cadence::prelude::*;
308//! use cadence::{StatsdClient, UdpMetricSink, DEFAULT_PORT};
309//!
310//! pub struct User {
311//!     id: u64,
312//!     username: String,
313//!     email: String
314//! }
315//!
316//!
317//! // Here's a simple DAO (Data Access Object) that doesn't do anything but
318//! // uses a metric client to keep track of the number of times the
319//! // 'getUserById' method gets called.
320//! pub struct MyUserDao {
321//!     metrics: Box<dyn MetricClient>
322//! }
323//!
324//!
325//! impl MyUserDao {
326//!     // Create a new instance that will use the StatsdClient
327//!     pub fn new<T: MetricClient + 'static>(metrics: T) -> MyUserDao {
328//!         MyUserDao { metrics: Box::new(metrics) }
329//!     }
330//!
331//!     /// Get a new user by their ID
332//!     pub fn get_user_by_id(&self, id: u64) -> Option<User> {
333//!         self.metrics.count("getUserById", 1);
334//!         None
335//!     }
336//! }
337//!
338//!
339//! // Create a new Statsd client that writes to "metrics.example.com"
340//! let host = ("metrics.example.com", DEFAULT_PORT);
341//! let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
342//! let sink = UdpMetricSink::from(host, socket).unwrap();
343//! let metrics = StatsdClient::from_sink("counter.example", sink);
344//!
345//! // Create a new instance of the DAO that will use the client
346//! let dao = MyUserDao::new(metrics);
347//!
348//! // Try to lookup a user by ID!
349//! match dao.get_user_by_id(123) {
350//!     Some(u) => println!("Found a user!"),
351//!     None => println!("No user!")
352//! };
353//! ```
354//!
355//! ### Quiet Metric Sending and Error Handling
356//!
357//! When sending metrics sometimes you don't really care about the `Result` of
358//! trying to send it or maybe you just don't want to deal with it inline with
359//! the rest of your code. In order to handle this, Cadence allows you to set a
360//! default error handler. This handler is invoked when there are errors sending
361//! metrics so that the calling code doesn't have to deal with them.
362//!
363//! An example of configuring an error handler and an example of when it might
364//! be invoked is given below.
365//!
366//! ```rust,no_run
367//! use cadence::prelude::*;
368//! use cadence::{MetricError, StatsdClient, NopMetricSink};
369//!
370//! fn my_error_handler(err: MetricError) {
371//!     println!("Metric error! {}", err);
372//! }
373//!
374//! let client = StatsdClient::builder("prefix", NopMetricSink)
375//!     .with_error_handler(my_error_handler)
376//!     .build();
377//!
378//! // When sending metrics via the `MetricBuilder` used for assembling tags,
379//! // callers may opt into sending metrics quietly via the `.send()` method
380//! // as opposed to the `.try_send()` method
381//! client.count_with_tags("some.counter", 42)
382//!     .with_tag("region", "us-east-2")
383//!     .send();
384//! ```
385//!
386//! ### Custom Metric Sinks
387//!
388//! The Cadence `StatsdClient` uses implementations of the `MetricSink`
389//! trait to send metrics to a metric server. Most users of the Cadence
390//! library probably want to use the `QueuingMetricSink` wrapping an instance
391//! of the `BufferedMetricSink`.
392//!
393//! However, maybe you want to do something not covered by an existing sink.
394//! An example of creating a custom sink is below.
395//!
396//! ```rust,no_run
397//! use std::io;
398//! use cadence::prelude::*;
399//! use cadence::{StatsdClient, MetricSink, DEFAULT_PORT};
400//!
401//! pub struct MyMetricSink;
402//!
403//!
404//! impl MetricSink for MyMetricSink {
405//!     fn emit(&self, metric: &str) -> io::Result<usize> {
406//!         // Your custom metric sink implementation goes here!
407//!         Ok(0)
408//!     }
409//! }
410//!
411//!
412//! let sink = MyMetricSink;
413//! let client = StatsdClient::from_sink("my.prefix", sink);
414//!
415//! client.count("my.counter.thing", 42);
416//! client.time("my.method.time", 25);
417//! client.count("some.other.counter", 1);
418//! ```
419//!
420//! ### Custom UDP Socket
421//!
422//! Most users of the Cadence `StatsdClient` will be using it to send metrics
423//! over a UDP socket. If you need to customize the socket, for example you
424//! want to use the socket in blocking mode but set a write timeout, you can
425//! do that as demonstrated below.
426//!
427//! ```rust,no_run
428//! use std::net::UdpSocket;
429//! use std::time::Duration;
430//! use cadence::prelude::*;
431//! use cadence::{StatsdClient, UdpMetricSink, DEFAULT_PORT};
432//!
433//! let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
434//! socket.set_write_timeout(Some(Duration::from_millis(1))).unwrap();
435//!
436//! let host = ("metrics.example.com", DEFAULT_PORT);
437//! let sink = UdpMetricSink::from(host, socket).unwrap();
438//! let client = StatsdClient::from_sink("my.prefix", sink);
439//!
440//! client.count("my.counter.thing", 29);
441//! client.time("my.service.call", 214);
442//! client.count("some.event", 33);
443//! client.set("users.uniques", 42);
444//! ```
445//!
446//! ### Unix Sockets
447//!
448//! Cadence also supports using Unix datagram sockets with the `UnixMetricSink`  or
449//! `BufferedUnixMetricSink`. Unix sockets can be used for sending metrics to a server
450//! or agent running on the same machine (physical machine, VM, containers in a pod)
451//! as your application. Unix sockets are somewhat similar to UDP sockets with a few
452//! important differences:
453//!
454//! * Sending metrics on a socket that doesn't exist or is not being listened to will
455//!   result in an error.
456//! * Metrics sent on a connected socket are guaranteed to be delievered (i.e. they are
457//!   reliable as opposed to UDP sockets). However, it's still possible that the metrics
458//!   won't be read by the server due to a variety of environment and server specific
459//!   reasons.
460//!
461//! An example of using the sinks is given below.
462//!
463//! ```rust,no_run
464//! use std::os::unix::net::UnixDatagram;
465//! use cadence::prelude::*;
466//! use cadence::{StatsdClient, BufferedUnixMetricSink};
467//!
468//! let socket = UnixDatagram::unbound().unwrap();
469//! socket.set_nonblocking(true).unwrap();
470//! let sink = BufferedUnixMetricSink::from("/run/statsd.sock", socket);
471//! let client = StatsdClient::from_sink("my.prefix", sink);
472//!
473//! client.count("my.counter.thing", 29);
474//! client.time("my.service.call", 214);
475//! client.count("some.event", 33);
476//! client.set("users.uniques", 42);
477//! ```
478//!
479//! NOTE: This feature is only available on Unix platforms (Linux, BSD, MacOS).
480//!
481
482#![forbid(unsafe_code)]
483
484pub const DEFAULT_PORT: u16 = 8125;
485
486pub use self::builder::MetricBuilder;
487
488pub use self::client::{
489    Counted, CountedExt, Distributed, Gauged, Histogrammed, Metered, MetricClient, Setted, StatsdClient,
490    StatsdClientBuilder, Timed,
491};
492
493pub use self::compat::Compat;
494
495pub use self::sinks::{
496    BufferedSpyMetricSink, BufferedUdpMetricSink, MetricSink, NopMetricSink, QueuingMetricSink, SpyMetricSink,
497    UdpMetricSink,
498};
499
500pub use self::types::{
501    Counter, Distribution, ErrorKind, Gauge, Histogram, Meter, Metric, MetricError, MetricResult, Set, Timer,
502};
503
504mod builder;
505mod client;
506mod compat;
507pub mod ext;
508mod io;
509pub mod prelude;
510mod sinks;
511mod types;
512
513// Utilities for running integration tests with Unix datagram sockets.
514#[cfg(unix)]
515#[doc(hidden)]
516pub mod test;
517
518// Sinks for sending metrics over Unix datagram sockets
519#[cfg(unix)]
520pub use crate::sinks::{BufferedUnixMetricSink, UnixMetricSink};
521
522mod sealed {
523    pub trait Sealed {}
524}