metrics/metrics-runtime/src/receiver.rs

119 lines
3.7 KiB
Rust

use crate::{
builder::{Builder, BuilderError},
common::Scope,
config::Configuration,
control::Controller,
registry::{MetricRegistry, ScopeRegistry},
sink::Sink,
};
use metrics::Recorder;
use metrics_core::Key;
use quanta::{Builder as UpkeepBuilder, Clock, Handle as UpkeepHandle};
use std::{cell::RefCell, sync::Arc};
thread_local! {
static SINK: RefCell<Option<Sink>> = RefCell::new(None);
}
/// Central store for metrics.
///
/// `Receiver` is the nucleus for all metrics operations. While no operations are performed by it
/// directly, it holds the registeries and references to resources and so it must live as long as
/// any [`Sink`] or [`Controller`] does.
pub struct Receiver {
metric_registry: Arc<MetricRegistry>,
scope_registry: Arc<ScopeRegistry>,
clock: Clock,
_upkeep_handle: UpkeepHandle,
}
impl Receiver {
pub(crate) fn from_config(config: Configuration) -> Result<Receiver, BuilderError> {
// Configure our clock and configure the quanta upkeep thread. The upkeep thread does that
// for us, and keeps us within `upkeep_interval` of the true time. The reads of this cache
// time are faster than calling the underlying time source directly, and for histogram
// windowing, we can afford to have a very granular value compared to the raw nanosecond
// precsion provided by quanta by default.
let clock = Clock::new();
let upkeep = UpkeepBuilder::new_with_clock(config.upkeep_interval, clock.clone());
let _upkeep_handle = upkeep.start().map_err(|_| BuilderError::UpkeepFailure)?;
let scope_registry = Arc::new(ScopeRegistry::new());
let metric_registry = Arc::new(MetricRegistry::new(
scope_registry.clone(),
config,
clock.clone(),
));
Ok(Receiver {
metric_registry,
scope_registry,
clock,
_upkeep_handle,
})
}
/// Creates a new [`Builder`] for building a [`Receiver`].
pub fn builder() -> Builder {
Builder::default()
}
/// Installs this receiver as the global metrics facade.
pub fn install(self) {
metrics::set_boxed_recorder(Box::new(self)).unwrap();
}
/// Creates a [`Sink`] bound to this receiver.
pub fn sink(&self) -> Sink {
Sink::new(
self.metric_registry.clone(),
self.scope_registry.clone(),
Scope::Root,
self.clock.clone(),
)
}
/// Creates a [`Controller`] bound to this receiver.
pub fn controller(&self) -> Controller {
Controller::new(self.metric_registry.clone(), self.scope_registry.clone())
}
}
impl Recorder for Receiver {
fn increment_counter(&self, key: Key, value: u64) {
SINK.with(move |sink| {
let mut sink = sink.borrow_mut();
if sink.is_none() {
let new_sink = self.sink();
*sink = Some(new_sink);
}
sink.as_mut().unwrap().increment_counter(key, value);
});
}
fn update_gauge(&self, key: Key, value: i64) {
SINK.with(move |sink| {
let mut sink = sink.borrow_mut();
if sink.is_none() {
let new_sink = self.sink();
*sink = Some(new_sink);
}
sink.as_mut().unwrap().update_gauge(key, value);
});
}
fn record_histogram(&self, key: Key, value: u64) {
SINK.with(move |sink| {
let mut sink = sink.borrow_mut();
if sink.is_none() {
let new_sink = self.sink();
*sink = Some(new_sink);
}
sink.as_mut().unwrap().record_value(key, value);
});
}
}