pub struct StatsdClient { /* private fields */ }
Expand description
Client for Statsd that implements various traits to record metrics.
§Traits
The client is the main entry point for users of this library. It supports several traits for recording metrics of different types.
Counted
for emitting counters.Timed
for emitting timings.Gauged
for emitting gauge values.Metered
for emitting meter values.Histogrammed
for emitting histogram values.Distributed
for emitting distribution values.Setted
for emitting set values.MetricClient
for a combination of all of the above.
For more information about the uses for each type of metric, see the documentation for each mentioned trait.
§Sinks
The client uses some implementation of a MetricSink
to emit the metrics.
In simple use cases when performance isn’t critical, the UdpMetricSink
is an acceptable choice since it is the simplest to use and understand.
When performance is more important, users will want to use the
BufferedUdpMetricSink
in combination with the QueuingMetricSink
for
maximum isolation between the sending of metrics and your application as well
as minimum overhead when sending metrics.
§Threading
The StatsdClient
is designed to work in a multithreaded application. All
parts of the client can be shared between threads (i.e. it is Send
and
Sync
). An example of how to use the client in a multithreaded environment
is given below.
In the following example, we create a struct MyRequestHandler
that has a
single method that spawns a thread to do some work and emit a metric.
§Wrapping With An Arc
In order to share a client between multiple threads, you’ll need to wrap it
with an atomic reference counting pointer (std::sync::Arc
). You should refer
to the client by the trait of all its methods for recording metrics
(MetricClient
) as well as the Send
and Sync
traits since the idea is to
share this between threads.
use std::panic::RefUnwindSafe;
use std::net::UdpSocket;
use std::sync::Arc;
use std::thread;
use cadence::prelude::*;
use cadence::{StatsdClient, BufferedUdpMetricSink, DEFAULT_PORT};
struct MyRequestHandler {
metrics: Arc<dyn MetricClient + Send + Sync + RefUnwindSafe>,
}
impl MyRequestHandler {
fn new() -> MyRequestHandler {
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
let host = ("localhost", DEFAULT_PORT);
let sink = BufferedUdpMetricSink::from(host, socket).unwrap();
MyRequestHandler {
metrics: Arc::new(StatsdClient::from_sink("some.prefix", sink))
}
}
fn handle_some_request(&self) -> Result<(), String> {
let metric_ref = self.metrics.clone();
let _t = thread::spawn(move || {
println!("Hello from the thread!");
metric_ref.count("request.handler", 1);
});
Ok(())
}
}
Implementations§
source§impl StatsdClient
impl StatsdClient
sourcepub fn from_sink<T>(prefix: &str, sink: T) -> Self
pub fn from_sink<T>(prefix: &str, sink: T) -> Self
Create a new client instance that will use the given prefix for
all metrics emitted to the given MetricSink
implementation.
Note that this client will discard errors encountered when
sending metrics via the MetricBuilder::send()
method.
§No-op Example
use cadence::{StatsdClient, NopMetricSink};
let prefix = "my.stats";
let client = StatsdClient::from_sink(prefix, NopMetricSink);
§UDP Socket Example
use std::net::UdpSocket;
use cadence::{StatsdClient, UdpMetricSink, DEFAULT_PORT};
let prefix = "my.stats";
let host = ("127.0.0.1", DEFAULT_PORT);
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
socket.set_nonblocking(true).unwrap();
let sink = UdpMetricSink::from(host, socket).unwrap();
let client = StatsdClient::from_sink(prefix, sink);
§Buffered UDP Socket Example
use std::net::UdpSocket;
use cadence::{StatsdClient, BufferedUdpMetricSink, DEFAULT_PORT};
let prefix = "my.stats";
let host = ("127.0.0.1", DEFAULT_PORT);
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
let sink = BufferedUdpMetricSink::from(host, socket).unwrap();
let client = StatsdClient::from_sink(prefix, sink);
Examples found in repository?
More examples
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
fn main() {
let sink = NopMetricSink;
let client = StatsdClient::from_sink("example.prefix", sink);
client.count("example.counter", 1).unwrap();
client.gauge("example.gauge", 5).unwrap();
client.gauge("example.gauge", 5.0).unwrap();
client.time("example.timer", 32).unwrap();
client.time("example.timer", Duration::from_millis(32)).unwrap();
client.histogram("example.histogram", 22).unwrap();
client.histogram("example.histogram", Duration::from_nanos(22)).unwrap();
client.histogram("example.histogram", 22.0).unwrap();
client.distribution("example.distribution", 33).unwrap();
client.distribution("example.distribution", 33.0).unwrap();
client.meter("example.meter", 8).unwrap();
client.set("example.set", 44).unwrap();
}
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
fn main() {
let sock = UdpSocket::bind("0.0.0.0:0").unwrap();
let sink = UdpMetricSink::from(("localhost", DEFAULT_PORT), sock).unwrap();
let client = StatsdClient::from_sink("example.prefix", sink);
client.count("example.counter", 1).unwrap();
client.gauge("example.gauge", 5).unwrap();
client.gauge("example.gauge", 5.0).unwrap();
client.time("example.timer", 32).unwrap();
client.time("example.timer", Duration::from_millis(32)).unwrap();
client.histogram("example.histogram", 22).unwrap();
client.histogram("example.histogram", Duration::from_nanos(22)).unwrap();
client.histogram("example.histogram", 22.0).unwrap();
client.distribution("example.distribution", 33).unwrap();
client.distribution("example.distribution", 33.0).unwrap();
client.meter("example.meter", 8).unwrap();
client.set("example.set", 44).unwrap();
}
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
fn main() {
let real_sink = NopMetricSink;
let reference1 = CloneableSink::new(real_sink);
let reference2 = reference1.clone();
let client = StatsdClient::from_sink("prefix", reference1);
let _ = reference2.flush();
client.count("example.counter", 1).unwrap();
client.gauge("example.gauge", 5).unwrap();
client.gauge("example.gauge", 5.0).unwrap();
client.time("example.timer", 32).unwrap();
client.time("example.timer", Duration::from_millis(32)).unwrap();
client.histogram("example.histogram", 22).unwrap();
client.histogram("example.histogram", Duration::from_nanos(22)).unwrap();
client.histogram("example.histogram", 22.0).unwrap();
client.distribution("example.distribution", 33).unwrap();
client.distribution("example.distribution", 33.0).unwrap();
client.meter("example.meter", 8).unwrap();
client.set("example.set", 44).unwrap();
let _ = reference2.flush();
}
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
fn main() {
let sock = UdpSocket::bind("0.0.0.0:0").unwrap();
let buffered = BufferedUdpMetricSink::from(("localhost", DEFAULT_PORT), sock).unwrap();
let queued = QueuingMetricSink::from(buffered);
let client = StatsdClient::from_sink("example.prefix", queued);
client.count("example.counter", 1).unwrap();
client.gauge("example.gauge", 5).unwrap();
client.gauge("example.gauge", 5.0).unwrap();
client.time("example.timer", 32).unwrap();
client.time("example.timer", Duration::from_millis(32)).unwrap();
client.histogram("example.histogram", 22).unwrap();
client.histogram("example.histogram", Duration::from_nanos(22)).unwrap();
client.histogram("example.histogram", 22.0).unwrap();
client.distribution("example.distribution", 33).unwrap();
client.distribution("example.distribution", 33.0).unwrap();
client.meter("example.meter", 8).unwrap();
client.set("example.set", 44).unwrap();
}
sourcepub fn builder<T>(prefix: &str, sink: T) -> StatsdClientBuilder
pub fn builder<T>(prefix: &str, sink: T) -> StatsdClientBuilder
Create a new builder with the provided prefix and metric sink.
A prefix and a metric sink are required to create a new client instance. All other optional customizations can be set by calling methods on the returned builder. Any customizations that aren’t set by the caller will use defaults.
Note, though a metric prefix is required, you may pass an empty string as a prefix. In this case, the metrics emitted will use only the bare keys supplied when you call the various methods to emit metrics.
General defaults:
- A no-op error handler will be used by default. Note that this
only affects errors encountered when using the
MetricBuilder::send()
method (as opposed to.try_send()
or any other method for sending metrics).
§Example
use cadence::prelude::*;
use cadence::{StatsdClient, MetricError, NopMetricSink};
fn my_handler(err: MetricError) {
println!("Metric error: {}", err);
}
let client = StatsdClient::builder("some.prefix", NopMetricSink)
.with_error_handler(my_handler)
.build();
client.gauge_with_tags("some.key", 7)
.with_tag("region", "us-west-1")
.send();
Examples found in repository?
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
fn main() {
fn my_error_handler(err: MetricError) {
eprintln!("Error sending metrics: {}", err);
}
// Create a client with an error handler and default "region" tag
let client = StatsdClient::builder("my.prefix", NopMetricSink)
.with_error_handler(my_error_handler)
.with_container_id("container-123")
.build();
// In this case we are sending a counter metric with manually set timestamp,
// container id and sampling rate. If sending the metric fails, our error
// handler set above will be invoked to do something with the metric error.
client
.count_with_tags("counter.1", 1)
.with_timestamp(123456)
.with_container_id("container-456")
.with_sampling_rate(0.5)
.send();
// In this case we are sending the same counter metrics without any explicit container
// id, meaning that the client's container id will be used.
let res = client.count_with_tags("counter.2", 1).try_send();
println!("Result of metric send: {:?}", res);
}
More examples
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
fn main() {
fn my_error_handler(err: MetricError) {
eprintln!("Error sending metrics: {}", err);
}
let client = StatsdClient::builder("my.prefix", NopMetricSink)
.with_error_handler(my_error_handler)
.build();
// In this case we are sending a distribution metric with two tag key-value
// pairs. If sending the metric fails, our error handler set above will
// be invoked to do something with the metric error.
client
.distribution_with_tags("latency.milliseconds", vec![10, 20, 30, 40, 50])
.with_tag("app", "search")
.with_tag("region", "us-west-2")
.send();
// In this case we are sending the same distribution metrics with two tags.
// The results of sending the metric (or failing to send it) are returned
// to the caller to do something with.
let res = client
.distribution_with_tags("latency.milliseconds", vec![10, 20, 30, 40, 50])
.with_tag("app", "search")
.with_tag("region", "us-west-2")
.try_send();
println!("Result of metric send: {:?}", res);
}
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
fn main() {
fn my_error_handler(err: MetricError) {
eprintln!("Error sending metrics: {}", err);
}
// Create a client with an error handler and default "region" tag
let client = StatsdClient::builder("my.prefix", NopMetricSink)
.with_error_handler(my_error_handler)
.with_tag("region", "us-west-2")
.build();
// In this case we are sending a counter metric with two tag key-value
// pairs. If sending the metric fails, our error handler set above will
// be invoked to do something with the metric error.
client
.count_with_tags("requests.handled", 1)
.with_tag("app", "search")
.with_tag("user", "1234")
.send();
// In this case we are sending the same counter metrics with two tags.
// The results of sending the metric (or failing to send it) are returned
// to the caller to do something with.
let res = client
.count_with_tags("requests.handled", 1)
.with_tag("app", "search")
.with_tag("user", "1234")
.try_send();
println!("Result of metric send: {:?}", res);
}
sourcepub fn flush(&self) -> MetricResult<()>
pub fn flush(&self) -> MetricResult<()>
Flush the underlying metric sink.
This is helpful for when you’d like to buffer metrics
but still want strong control over when to emit them.
For example, you are using a BufferedUdpMetricSink and
have just emitted some time-sensitive metrics, but you
aren’t sure if the buffer is full or not. Thus, you can
use flush
to force the sink to flush your metrics now.
§Buffered UDP Socket Example
use std::net::UdpSocket;
use cadence::prelude::*;
use cadence::{StatsdClient, BufferedUdpMetricSink, DEFAULT_PORT};
let prefix = "my.stats";
let host = ("127.0.0.1", DEFAULT_PORT);
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
let sink = BufferedUdpMetricSink::from(host, socket).unwrap();
let client = StatsdClient::from_sink(prefix, sink);
client.count("time-sensitive.keyA", 1);
client.count("time-sensitive.keyB", 2);
client.count("time-sensitive.keyC", 3);
// Any number of time-sensitive metrics ...
client.flush();
Trait Implementations§
source§impl<T> Counted<T> for StatsdClientwhere
T: ToCounterValue,
impl<T> Counted<T> for StatsdClientwhere
T: ToCounterValue,
source§impl CountedExt for StatsdClient
impl CountedExt for StatsdClient
MetricBuilder
that can
be used to add tags to the metric.MetricBuilder
that can
be used to add tags to the metric.source§impl Debug for StatsdClient
impl Debug for StatsdClient
source§impl<T> Distributed<T> for StatsdClientwhere
T: ToDistributionValue,
impl<T> Distributed<T> for StatsdClientwhere
T: ToDistributionValue,
MetricBuilder
that can be used to add tags to the metric.