pub trait MetricsSink: Send + Sync + 'static {
fn counter(&self, name: &str, labels: &[(&str, &str)], value: u64);
fn gauge(&self, name: &str, labels: &[(&str, &str)], value: f64);
fn histogram(&self, name: &str, labels: &[(&str, &str)], value: f64);
fn inc(&self, name: &str) {
self.counter(name, &[], 1);
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct NoopSink;
impl MetricsSink for NoopSink {
fn counter(&self, _name: &str, _labels: &[(&str, &str)], _value: u64) {}
fn gauge(&self, _name: &str, _labels: &[(&str, &str)], _value: f64) {}
fn histogram(&self, _name: &str, _labels: &[(&str, &str)], _value: f64) {}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
struct CountingSink {
counters: AtomicU64,
gauges: AtomicU64,
histograms: AtomicU64,
}
impl MetricsSink for CountingSink {
fn counter(&self, _name: &str, _labels: &[(&str, &str)], _value: u64) {
self.counters.fetch_add(1, Ordering::SeqCst);
}
fn gauge(&self, _name: &str, _labels: &[(&str, &str)], _value: f64) {
self.gauges.fetch_add(1, Ordering::SeqCst);
}
fn histogram(&self, _name: &str, _labels: &[(&str, &str)], _value: f64) {
self.histograms.fetch_add(1, Ordering::SeqCst);
}
}
#[test]
fn noop_sink_no_panics() {
let s = NoopSink;
s.counter("a", &[], 1);
s.gauge("a", &[("x", "y")], 1.5);
s.histogram("a", &[], 2.0);
s.inc("a");
}
#[test]
fn inc_default_delegates_to_counter() {
let s: Arc<CountingSink> = Arc::new(CountingSink {
counters: AtomicU64::new(0),
gauges: AtomicU64::new(0),
histograms: AtomicU64::new(0),
});
s.inc("x");
assert_eq!(s.counters.load(Ordering::SeqCst), 1);
assert_eq!(s.gauges.load(Ordering::SeqCst), 0);
}
#[test]
fn arc_dyn_sink_is_object_safe() {
let s: Arc<dyn MetricsSink> = Arc::new(NoopSink);
s.counter("a", &[], 1);
}
}