dipstick/src/proxy.rs

301 lines
9.7 KiB
Rust
Raw Normal View History

2018-03-29 18:22:43 +00:00
//! Decouple metric definition from configuration with trait objects.
2020-05-15 04:28:40 +00:00
use crate::attributes::{Attributes, MetricId, OnFlush, Prefixed, WithAttributes};
use crate::input::{InputKind, InputMetric, InputScope};
use crate::name::{MetricName, NameParts};
2020-05-23 03:47:18 +00:00
use crate::output::void::VOID_INPUT;
2020-05-15 04:28:40 +00:00
use crate::Flush;
2018-03-29 18:22:43 +00:00
2019-04-09 11:55:15 +00:00
use std::collections::{BTreeMap, HashMap};
use std::sync::{Arc, Weak};
2020-05-25 13:12:24 +00:00
use std::{fmt, io};
2018-03-29 18:22:43 +00:00
2019-04-09 11:55:15 +00:00
#[cfg(not(feature = "parking_lot"))]
use std::sync::RwLock;
2019-04-09 11:55:15 +00:00
#[cfg(feature = "parking_lot")]
use parking_lot::RwLock;
2018-03-29 18:22:43 +00:00
use atomic_refcell::*;
lazy_static! {
2018-06-17 02:59:51 +00:00
/// Root of the default metrics proxy, usable by all libraries and apps.
2018-05-31 18:24:06 +00:00
/// Libraries should create their metrics into sub subspaces of this.
2018-06-22 19:32:07 +00:00
/// Applications should configure on startup where the proxied metrics should go.
2018-06-22 05:08:04 +00:00
/// Exceptionally, one can create its own ProxyInput root, separate from this one.
2018-06-22 19:32:07 +00:00
static ref ROOT_PROXY: Proxy = Proxy::new();
2018-06-14 20:08:54 +00:00
}
/// A dynamically proxied metric.
2018-06-21 15:52:10 +00:00
#[derive(Debug)]
2018-06-22 05:08:04 +00:00
struct ProxyMetric {
2018-05-20 10:43:55 +00:00
// basic info for this metric, needed to recreate new corresponding trait object if target changes
2018-10-05 14:26:33 +00:00
name: NameParts,
2018-10-26 01:20:47 +00:00
kind: InputKind,
2018-05-20 10:43:55 +00:00
2018-06-17 02:59:51 +00:00
// the metric trait object to proxy metric values to
2018-05-20 10:43:55 +00:00
// the second part can be up to namespace.len() + 1 if this metric was individually targeted
// 0 if no target assigned
2020-04-17 11:52:46 +00:00
target: AtomicRefCell<(InputMetric, usize)>,
2018-05-20 10:43:55 +00:00
// a reference to the the parent proxy to remove the metric from when it is dropped
2018-06-17 02:59:51 +00:00
proxy: Arc<RwLock<InnerProxy>>,
2018-03-29 18:22:43 +00:00
}
/// Dispatcher weak ref does not prevent dropping but still needs to be cleaned out.
2018-06-22 05:08:04 +00:00
impl Drop for ProxyMetric {
2018-03-29 18:22:43 +00:00
fn drop(&mut self) {
write_lock!(self.proxy).drop_metric(&self.name)
2018-03-29 18:22:43 +00:00
}
}
/// A dynamic proxy for app and lib metrics.
2018-03-29 18:22:43 +00:00
/// Decouples metrics definition from backend configuration.
/// Allows defining metrics before a concrete type is configured.
2018-03-29 18:22:43 +00:00
/// Allows replacing metrics backend on the fly at runtime.
2018-06-21 15:52:10 +00:00
#[derive(Clone, Debug)]
2018-06-22 19:32:07 +00:00
pub struct Proxy {
2018-06-14 16:37:21 +00:00
attributes: Attributes,
inner: Arc<RwLock<InnerProxy>>,
2018-03-29 18:22:43 +00:00
}
2018-10-04 21:28:25 +00:00
impl Default for Proxy {
2018-06-26 15:46:55 +00:00
/// Return the default root metric proxy.
2018-10-04 21:28:25 +00:00
fn default() -> Self {
2018-06-26 15:46:55 +00:00
ROOT_PROXY.clone()
}
}
struct InnerProxy {
2018-05-20 10:43:55 +00:00
// namespaces can target one, many or no metrics
targets: HashMap<NameParts, Arc<dyn InputScope + Send + Sync>>,
2018-05-20 10:43:55 +00:00
// last part of the namespace is the metric's name
2018-10-05 14:26:33 +00:00
metrics: BTreeMap<NameParts, Weak<ProxyMetric>>,
2018-03-29 18:22:43 +00:00
}
2018-06-19 19:27:26 +00:00
2018-06-21 15:52:10 +00:00
impl fmt::Debug for InnerProxy {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "metrics: {:?}", self.metrics.keys())?;
write!(f, "targets: {:?}", self.targets.keys())
}
}
impl InnerProxy {
2018-05-20 10:43:55 +00:00
fn new() -> Self {
Self {
targets: HashMap::new(),
metrics: BTreeMap::new(),
2018-05-01 13:41:31 +00:00
}
}
fn set_target(
&mut self,
namespace: &NameParts,
target_scope: Arc<dyn InputScope + Send + Sync>,
) {
self.targets.insert(namespace.clone(), target_scope.clone());
for (metric_name, metric) in self.metrics.range_mut(namespace.clone()..) {
2018-03-29 18:22:43 +00:00
if let Some(metric) = metric.upgrade() {
2018-05-20 10:43:55 +00:00
// check for range end
2019-04-09 11:55:15 +00:00
if !metric_name.is_within(namespace) {
break;
}
2018-05-20 10:43:55 +00:00
// check if metric targeted by _lower_ namespace
2019-04-09 11:55:15 +00:00
if metric.target.borrow().1 > namespace.len() {
continue;
}
2018-05-20 10:43:55 +00:00
2018-10-05 14:26:33 +00:00
let target_metric = target_scope.new_metric(metric.name.short(), metric.kind);
*metric.target.borrow_mut() = (target_metric, namespace.len());
2018-03-29 18:22:43 +00:00
}
}
2018-04-09 20:29:07 +00:00
}
2019-04-09 11:55:15 +00:00
fn get_effective_target(
&self,
namespace: &NameParts,
) -> Option<(Arc<dyn InputScope + Send + Sync>, usize)> {
if let Some(target) = self.targets.get(namespace) {
return Some((target.clone(), namespace.len()));
2018-05-20 10:43:55 +00:00
}
// no 1:1 match, scan upper namespaces
let mut name = namespace.clone();
while let Some(_popped) = name.pop_back() {
2018-05-20 10:43:55 +00:00
if let Some(target) = self.targets.get(&name) {
2019-04-09 11:55:15 +00:00
return Some((target.clone(), name.len()));
2018-05-20 10:43:55 +00:00
}
}
None
2018-04-09 20:29:07 +00:00
}
2018-10-05 14:26:33 +00:00
fn unset_target(&mut self, namespace: &NameParts) {
2018-05-20 10:43:55 +00:00
if self.targets.remove(namespace).is_none() {
// nothing to do
2019-04-09 11:55:15 +00:00
return;
2018-05-20 10:43:55 +00:00
}
2019-04-09 11:55:15 +00:00
let (up_target, up_nslen) = self
.get_effective_target(namespace)
2018-09-14 10:47:31 +00:00
.unwrap_or_else(|| (VOID_INPUT.input_dyn(), 0));
2018-05-20 10:43:55 +00:00
// update all affected metrics to next upper targeted namespace
for (name, metric) in self.metrics.range_mut(namespace.clone()..) {
2018-05-20 10:43:55 +00:00
// check for range end
2019-04-09 11:55:15 +00:00
if !name.is_within(namespace) {
break;
}
2018-05-20 10:43:55 +00:00
if let Some(metric) = metric.upgrade() {
2018-05-20 10:43:55 +00:00
// check if metric targeted by _lower_ namespace
2019-04-09 11:55:15 +00:00
if metric.target.borrow().1 > namespace.len() {
continue;
}
2018-05-20 10:43:55 +00:00
2018-10-05 14:26:33 +00:00
let new_metric = up_target.new_metric(name.short(), metric.kind);
*metric.target.borrow_mut() = (new_metric, up_nslen);
2018-05-20 10:43:55 +00:00
}
}
2018-04-09 20:29:07 +00:00
}
2018-10-05 14:26:33 +00:00
fn drop_metric(&mut self, name: &NameParts) {
2018-05-20 10:43:55 +00:00
if self.metrics.remove(name).is_none() {
panic!("Could not remove DelegatingMetric weak ref from delegation point")
}
}
2018-04-09 20:29:07 +00:00
2020-05-23 03:47:18 +00:00
fn flush(&self, namespace: &NameParts) -> io::Result<()> {
2018-05-20 10:43:55 +00:00
if let Some((target, _nslen)) = self.get_effective_target(namespace) {
2018-06-11 18:56:40 +00:00
target.flush()
} else {
Ok(())
2018-04-09 20:29:07 +00:00
}
}
}
2018-06-22 19:32:07 +00:00
impl Proxy {
2018-06-17 02:59:51 +00:00
/// Create a new "private" metric proxy root. This is usually not what you want.
/// Since this proxy will not be part of the standard proxy tree,
2018-05-01 13:41:31 +00:00
/// it will need to be configured independently and since downstream code may not know about
2018-06-17 02:59:51 +00:00
/// its existence this may never happen and metrics will not be proxyed anywhere.
/// If you want to use the standard proxy tree, use #metric_proxy() instead.
2018-05-01 13:41:31 +00:00
pub fn new() -> Self {
2018-06-22 19:32:07 +00:00
Proxy {
2018-06-14 16:37:21 +00:00
attributes: Attributes::default(),
inner: Arc::new(RwLock::new(InnerProxy::new())),
2018-05-01 13:41:31 +00:00
}
}
/// Replace target for this proxy and its children.
2019-04-09 11:55:15 +00:00
#[deprecated(since = "0.7.2", note = "Use target()")]
2018-07-03 15:44:29 +00:00
pub fn set_target<T: InputScope + Send + Sync + 'static>(&self, target: T) {
self.target(target)
}
/// Replace target for this proxy and its children.
pub fn target<T: InputScope + Send + Sync + 'static>(&self, target: T) {
write_lock!(self.inner).set_target(self.get_prefixes(), Arc::new(target))
2018-04-09 20:29:07 +00:00
}
/// Replace target for this proxy and its children.
2018-04-09 20:29:07 +00:00
pub fn unset_target(&self) {
write_lock!(self.inner).unset_target(self.get_prefixes())
2018-03-29 18:22:43 +00:00
}
/// Install a new default target for all proxies.
2019-04-09 11:55:15 +00:00
#[deprecated(since = "0.7.2", note = "Use default_target()")]
2018-07-03 15:44:29 +00:00
pub fn set_default_target<T: InputScope + Send + Sync + 'static>(target: T) {
Self::default_target(target)
}
/// Install a new default target for all proxies.
pub fn default_target<T: InputScope + Send + Sync + 'static>(target: T) {
ROOT_PROXY.target(target)
2018-06-22 19:32:07 +00:00
}
/// Revert to initial state any installed default target for all proxies.
2018-06-22 19:32:07 +00:00
pub fn unset_default_target(&self) {
ROOT_PROXY.unset_target()
}
2018-06-11 18:56:40 +00:00
}
2018-04-06 21:11:50 +00:00
2018-06-22 19:32:07 +00:00
impl<S: AsRef<str>> From<S> for Proxy {
fn from(name: S) -> Proxy {
Proxy::new().named(name.as_ref())
2018-06-11 18:56:40 +00:00
}
2018-04-06 21:11:50 +00:00
}
2018-07-03 15:44:29 +00:00
impl InputScope for Proxy {
2018-06-17 02:59:51 +00:00
/// Lookup or create a proxy stub for the requested metric.
2018-10-26 01:20:47 +00:00
fn new_metric(&self, name: MetricName, kind: InputKind) -> InputMetric {
let name: MetricName = self.prefix_append(name);
let mut inner = write_lock!(self.inner);
2018-06-14 16:37:21 +00:00
let proxy = inner
.metrics
2018-06-14 16:37:21 +00:00
.get(&name)
2018-10-26 01:20:47 +00:00
// TODO validate that InputKind matches existing
2022-07-12 18:11:39 +00:00
.and_then(Weak::upgrade)
2018-03-29 18:22:43 +00:00
.unwrap_or_else(|| {
let namespace = &*name;
{
// not found, define new
2019-04-09 11:55:15 +00:00
let (target, target_namespace_length) = inner
.get_effective_target(namespace)
.unwrap_or_else(|| (VOID_INPUT.input_dyn(), 0));
2018-10-05 14:26:33 +00:00
let metric_object = target.new_metric(namespace.short(), kind);
let proxy = Arc::new(ProxyMetric {
name: namespace.clone(),
kind,
target: AtomicRefCell::new((metric_object, target_namespace_length)),
proxy: self.inner.clone(),
});
2019-04-09 11:55:15 +00:00
inner
.metrics
.insert(namespace.clone(), Arc::downgrade(&proxy));
proxy
}
2018-06-11 18:56:40 +00:00
});
2019-05-17 19:43:30 +00:00
InputMetric::new(MetricId::forge("proxy", name), move |value, labels| {
proxy.target.borrow().0.write(value, labels)
})
2018-03-29 18:22:43 +00:00
}
2018-06-24 04:31:34 +00:00
}
impl Flush for Proxy {
2020-05-23 03:47:18 +00:00
fn flush(&self) -> io::Result<()> {
2019-03-11 18:22:55 +00:00
self.notify_flush_listeners();
write_lock!(self.inner).flush(self.get_prefixes())
2018-03-29 18:22:43 +00:00
}
2018-05-29 02:58:58 +00:00
}
2018-06-22 19:32:07 +00:00
impl WithAttributes for Proxy {
2019-04-09 11:55:15 +00:00
fn get_attributes(&self) -> &Attributes {
&self.attributes
}
fn mut_attributes(&mut self) -> &mut Attributes {
&mut self.attributes
}
2018-03-29 18:22:43 +00:00
}
#[cfg(feature = "bench")]
mod bench {
2018-09-14 10:47:31 +00:00
use super::*;
2020-05-15 04:28:40 +00:00
use crate::AtomicBucket;
2018-04-06 21:11:50 +00:00
2018-03-29 18:22:43 +00:00
#[bench]
2018-06-17 02:59:51 +00:00
fn proxy_marker_to_aggregate(b: &mut test::Bencher) {
ROOT_PROXY.target(AtomicBucket::new());
let metric = ROOT_PROXY.marker("event_a");
2018-03-29 18:22:43 +00:00
b.iter(|| test::black_box(metric.mark()));
}
#[bench]
2018-06-17 02:59:51 +00:00
fn proxy_marker_to_void(b: &mut test::Bencher) {
let metric = ROOT_PROXY.marker("event_a");
2018-03-29 18:22:43 +00:00
b.iter(|| test::black_box(metric.mark()));
}
}