mirror of https://github.com/fralalonde/dipstick
Split Name and Namespace to separate module
This commit is contained in:
parent
306c404191
commit
969f0ed66c
|
@ -1,11 +1,8 @@
|
|||
|
||||
![a dipstick picture](https://raw.githubusercontent.com/fralalonde/dipstick/master/assets/dipstick_single_ok_horiz_transparent.png)
|
||||
|
||||
[![crates.io](https://img.shields.io/crates/v/dipstick.svg)](https://crates.io/crates/dipstick)
|
||||
[![docs.rs](https://docs.rs/dipstick/badge.svg)](https://docs.rs/dipstick)
|
||||
[![Build Status](https://travis-ci.org/fralalonde/dipstick.svg?branch=master)](https://travis-ci.org/fralalonde/dipstick)
|
||||
|
||||
# dipstick
|
||||
# dipstick ![a dipstick picture](https://raw.githubusercontent.com/fralalonde/dipstick/master/assets/dipstick_single_ok_horiz_transparent_small.png)
|
||||
|
||||
A one-stop shop metrics library for Rust applications with lots of features,
|
||||
minimal impact on applications and a choice of output to downstream systems.
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -20,7 +20,7 @@ fn main() {
|
|||
app_metrics.counter("just_once").count(4);
|
||||
|
||||
// metric names can be prepended with a common prefix
|
||||
let prefixed_metrics = app_metrics.add_prefix("subsystem");
|
||||
let prefixed_metrics = app_metrics.namespace("subsystem");
|
||||
let event = prefixed_metrics.marker("event_c");
|
||||
let gauge = prefixed_metrics.gauge("gauge_d");
|
||||
|
||||
|
|
|
@ -7,11 +7,11 @@ use std::time::Duration;
|
|||
use dipstick::*;
|
||||
|
||||
fn main() {
|
||||
let bucket = Bucket::new().add_prefix("test");
|
||||
let bucket = Bucket::new().namespace("test");
|
||||
|
||||
// Bucket::set_default_output(to_stdout());
|
||||
bucket.set_target(Graphite::send_to("localhost:2003").expect("Socket")
|
||||
.add_prefix("machine1").add_prefix("application"));
|
||||
.namespace("machine1").namespace("application"));
|
||||
|
||||
bucket.flush_every(Duration::from_secs(3));
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::io;
|
|||
use dipstick::*;
|
||||
|
||||
fn main() {
|
||||
let metrics = Bucket::new().add_prefix("test");
|
||||
let metrics = Bucket::new().namespace("test");
|
||||
|
||||
// Bucket::set_default_output(to_stdout());
|
||||
metrics.set_target(Text::write_to(io::stdout()));
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::io;
|
|||
use dipstick::*;
|
||||
|
||||
fn main() {
|
||||
let metrics = Text::write_to(io::stdout()).cached(5).input().add_prefix("cache");
|
||||
let metrics = Text::write_to(io::stdout()).cached(5).input().namespace("cache");
|
||||
|
||||
loop {
|
||||
// report some ad-hoc metric values from our "application" loop
|
||||
|
|
|
@ -33,7 +33,7 @@ fn main() {
|
|||
.add_target(one_minute)
|
||||
.add_target(five_minutes)
|
||||
.add_target(fifteen_minutes)
|
||||
.add_prefix("machine_name");
|
||||
.namespace("machine_name");
|
||||
|
||||
// send application metrics to aggregator
|
||||
Proxy::default_root().set_target(all_buckets);
|
||||
|
|
|
@ -19,12 +19,12 @@ fn main() {
|
|||
|
||||
// prepend and append to metric name
|
||||
(_, ScoreType::Count(count)) => {
|
||||
if let Some(last) = name.pop() {
|
||||
name.push("customized_add_prefix".into());
|
||||
name.push(format!("{}_and_a_suffix", last));
|
||||
if let Some(last) = name.pop_back() {
|
||||
// let name = ;
|
||||
Some((
|
||||
Kind::Counter,
|
||||
name,
|
||||
name.append("customized_add_prefix")
|
||||
.append(format!("{}_and_a_suffix", last)),
|
||||
count,
|
||||
))
|
||||
} else {
|
||||
|
@ -33,7 +33,7 @@ fn main() {
|
|||
},
|
||||
|
||||
// scaling the score value and appending unit to name
|
||||
(kind, ScoreType::Sum(sum)) => Some((kind, name.concat("per_thousand"), sum / 1000)),
|
||||
(kind, ScoreType::Sum(sum)) => Some((kind, name.append("per_thousand"), sum / 1000)),
|
||||
|
||||
// using the unmodified metric name
|
||||
(kind, ScoreType::Mean(avg)) => Some((kind, name, avg.round() as u64)),
|
||||
|
|
|
@ -10,7 +10,7 @@ fn main() {
|
|||
let metrics =
|
||||
Graphite::send_to("localhost:2003")
|
||||
.expect("Connected")
|
||||
.add_prefix("my_app")
|
||||
.namespace("my_app")
|
||||
.input();
|
||||
|
||||
loop {
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
//! A sample application sending ad-hoc counter values both to statsd _and_ to stdout.
|
||||
|
||||
//#[macro_use]
|
||||
//extern crate dipstick;
|
||||
//#[macro_use]
|
||||
//extern crate lazy_static;
|
||||
|
||||
//use dipstick::*;
|
||||
//use std::time::Duration;
|
||||
//
|
||||
//#[ignore(deprecated)]
|
||||
//app_metrics!(
|
||||
// MultiOutput, DIFFERENT_TYPES = to_multi()
|
||||
// .with_output(to_statsd("localhost:8125").expect("Statsd"))
|
||||
// .with_output(to_stdout())
|
||||
//);
|
||||
//
|
||||
//#[ignore(deprecated)]
|
||||
//app_metrics!(
|
||||
// MultiOutput, SAME_TYPE = to_multi()
|
||||
// .with_output(to_stdout().add_prefix("yeah"))
|
||||
// .with_output(to_stdout().add_prefix("ouch"))
|
||||
//);
|
||||
//
|
||||
//#[ignore(deprecated)]
|
||||
//app_metrics!(
|
||||
// MultiOutput, MUTANT_CHILD = SAME_TYPE.add_prefix("super").add_prefix("duper")
|
||||
//);
|
||||
|
||||
fn main() {
|
||||
// let mmm: &Output = &to_stdout();
|
||||
//
|
||||
// loop {
|
||||
// DIFFERENT_TYPES.counter("counter_a").count(123);
|
||||
// SAME_TYPE.timer("timer_a").interval_us(2000000);
|
||||
// MUTANT_CHILD.gauge("gauge_z").value(34534);
|
||||
// std::thread::sleep(Duration::from_millis(40));
|
||||
// }
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
#[macro_use]
|
||||
extern crate dipstick;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
pub extern crate lazy_static;
|
||||
|
||||
use dipstick::*;
|
||||
|
||||
|
@ -39,7 +39,7 @@ metrics!(LIB_METRICS => {
|
|||
});
|
||||
|
||||
fn main() {
|
||||
Proxy::set_default_target(Text::write_to(io::stdout()).input());
|
||||
dipstick::Proxy::set_default_target(dipstick::Text::write_to(io::stdout()).input());
|
||||
|
||||
loop {
|
||||
ROOT_COUNTER.count(123);
|
|
@ -2,22 +2,22 @@
|
|||
|
||||
extern crate dipstick;
|
||||
|
||||
use dipstick::{MultiInput, Graphite, Text, AddPrefix, Input, InputScope};
|
||||
use dipstick::{MultiInput, Graphite, Text, Input, InputScope, Naming};
|
||||
use std::time::Duration;
|
||||
use std::io;
|
||||
|
||||
fn main() {
|
||||
// will output metrics to graphite and to stdout
|
||||
let different_type_metrics = MultiInput::inputs()
|
||||
let different_type_metrics = MultiInput::input()
|
||||
.add_target(Graphite::send_to("localhost:2003").expect("Connecting"))
|
||||
.add_target(Text::write_to(io::stdout()))
|
||||
.input();
|
||||
|
||||
// will output metrics twice, once with "cool.yeah" prefix and once with "cool.ouch" prefix.
|
||||
let same_type_metrics = MultiInput::inputs()
|
||||
.add_target(Text::write_to(io::stdout()).add_prefix("yeah"))
|
||||
.add_target(Text::write_to(io::stdout()).add_prefix("ouch"))
|
||||
.add_prefix("cool")
|
||||
let same_type_metrics = MultiInput::input()
|
||||
.add_target(Text::write_to(io::stdout()).namespace("yeah"))
|
||||
.add_target(Text::write_to(io::stdout()).namespace("ouch"))
|
||||
.namespace("cool")
|
||||
.input();
|
||||
|
||||
loop {
|
||||
|
|
|
@ -8,16 +8,16 @@ use std::io;
|
|||
|
||||
fn main() {
|
||||
// will output metrics to graphite and to stdout
|
||||
let different_type_metrics = MultiOutput::metrics()
|
||||
let different_type_metrics = MultiOutput::output()
|
||||
.add_target(Graphite::send_to("localhost:2003").expect("Connecting"))
|
||||
.add_target(Text::write_to(io::stdout()))
|
||||
.input();
|
||||
|
||||
// will output metrics twice, once with "cool.yeah" prefix and once with "cool.ouch" prefix.
|
||||
let same_type_metrics = MultiOutput::metrics()
|
||||
.add_target(Text::write_to(io::stdout()).add_prefix("yeah"))
|
||||
.add_target(Text::write_to(io::stdout()).add_prefix("ouch"))
|
||||
.add_prefix("cool").input();
|
||||
let same_type_metrics = MultiOutput::output()
|
||||
.add_target(Text::write_to(io::stderr()).namespace("out_1"))
|
||||
.add_target(Text::write_to(io::stderr()).namespace("out_2"))
|
||||
.namespace("out_both").input();
|
||||
|
||||
loop {
|
||||
different_type_metrics.new_metric("counter_a".into(), Kind::Counter).write(123);
|
||||
|
|
|
@ -5,11 +5,12 @@ extern crate dipstick;
|
|||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
use std::io;
|
||||
use dipstick::{Proxy, Text, InputScope, AddPrefix, Input};
|
||||
use dipstick::{Proxy, Text, InputScope, Input, Naming};
|
||||
|
||||
|
||||
fn main() {
|
||||
let root = Proxy::default_root();
|
||||
let sub = root.add_prefix("sub");
|
||||
let sub = root.namespace("sub");
|
||||
|
||||
let count1 = root.counter("counter_a");
|
||||
|
||||
|
@ -21,12 +22,12 @@ fn main() {
|
|||
count2.count(2);
|
||||
|
||||
// route every metric from the root to stdout with prefix "root"
|
||||
root.set_target(Text::write_to(io::stdout()).add_prefix("root").input());
|
||||
root.set_target(Text::write_to(io::stdout()).namespace("root").input());
|
||||
count1.count(3);
|
||||
count2.count(4);
|
||||
|
||||
// route metrics from "sub" to stdout with prefix "mutant"
|
||||
sub.set_target(Text::write_to(io::stdout()).add_prefix("mutant").input());
|
||||
sub.set_target(Text::write_to(io::stdout()).namespace("mutant").input());
|
||||
count1.count(5);
|
||||
count2.count(6);
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ fn main() {
|
|||
Statsd::send_to("localhost:8125")
|
||||
.expect("Connected")
|
||||
// .with_sampling(Sampling::Random(0.2))
|
||||
.add_prefix("my_app")
|
||||
.namespace("my_app")
|
||||
.input();
|
||||
|
||||
let counter = metrics.counter("counter_a");
|
||||
|
|
|
@ -11,7 +11,7 @@ fn main() {
|
|||
Statsd::send_to("localhost:8125")
|
||||
.expect("Connected")
|
||||
.sampled(Sampling::Random(0.2))
|
||||
.add_prefix("my_app")
|
||||
.namespace("my_app")
|
||||
.input();
|
||||
|
||||
let counter = metrics.counter("counter_a");
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Maintain aggregated metrics for deferred reporting,
|
||||
|
||||
use core::component::{Attributes, Name, WithAttributes, AddPrefix};
|
||||
use core::component::{Attributes, WithAttributes, Naming};
|
||||
use core::name::{Name};
|
||||
use core::input::{Kind, InputScope, InputMetric};
|
||||
use core::output::{OutputDyn, OutputScope, OutputMetric, Output, output_none};
|
||||
use core::clock::TimeHandle;
|
||||
|
@ -130,7 +131,7 @@ impl InnerBucket {
|
|||
|
||||
impl<S: AsRef<str>> From<S> for Bucket {
|
||||
fn from(name: S) -> Bucket {
|
||||
Bucket::new().add_prefix(name.as_ref())
|
||||
Bucket::new().namespace(name.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,7 +211,7 @@ impl InputScope for Bucket {
|
|||
.write()
|
||||
.expect("Aggregator")
|
||||
.metrics
|
||||
.entry(self.qualified_name(name))
|
||||
.entry(self.qualify(name))
|
||||
.or_insert_with(|| Arc::new(Scoreboard::new(kind)))
|
||||
.clone();
|
||||
InputMetric::new(move |value| scoreb.update(value))
|
||||
|
@ -236,12 +237,12 @@ impl WithAttributes for Bucket {
|
|||
#[allow(dead_code)]
|
||||
pub fn stats_all(kind: Kind, name: Name, score: ScoreType) -> Option<(Kind, Name, Value)> {
|
||||
match score {
|
||||
ScoreType::Count(hit) => Some((Kind::Counter, name.concat("count"), hit)),
|
||||
ScoreType::Sum(sum) => Some((kind, name.concat("sum"), sum)),
|
||||
ScoreType::Mean(mean) => Some((kind, name.concat("mean"), mean.round() as Value)),
|
||||
ScoreType::Max(max) => Some((Kind::Gauge, name.concat("max"), max)),
|
||||
ScoreType::Min(min) => Some((Kind::Gauge, name.concat("min"), min)),
|
||||
ScoreType::Rate(rate) => Some((Kind::Gauge, name.concat("rate"), rate.round() as Value)),
|
||||
ScoreType::Count(hit) => Some((Kind::Counter, name.qualify("count"), hit)),
|
||||
ScoreType::Sum(sum) => Some((kind, name.qualify("sum"), sum)),
|
||||
ScoreType::Mean(mean) => Some((kind, name.qualify("mean"), mean.round() as Value)),
|
||||
ScoreType::Max(max) => Some((Kind::Gauge, name.qualify("max"), max)),
|
||||
ScoreType::Min(min) => Some((Kind::Gauge, name.qualify("min"), min)),
|
||||
ScoreType::Rate(rate) => Some((Kind::Gauge, name.qualify("rate"), rate.round() as Value)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -291,7 +292,6 @@ pub fn stats_summary(kind: Kind, name: Name, score: ScoreType) -> Option<(Kind,
|
|||
mod bench {
|
||||
|
||||
use test;
|
||||
use core::clock::*;
|
||||
use super::*;
|
||||
|
||||
#[bench]
|
||||
|
@ -322,7 +322,7 @@ mod test {
|
|||
fn make_stats(stats_fn: &StatsFn) -> BTreeMap<String, Value> {
|
||||
mock_clock_reset();
|
||||
|
||||
let metrics = Bucket::new().add_prefix("test");
|
||||
let metrics = Bucket::new().namespace("test");
|
||||
|
||||
let counter = metrics.counter("counter_a");
|
||||
let timer = metrics.timer("timer_a");
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
use core::Flush;
|
||||
use core::input::{Kind, Input, InputScope, InputMetric, InputDyn};
|
||||
use core::component::{Attributes, WithAttributes, Name, AddPrefix};
|
||||
use core::component::{Attributes, WithAttributes, Naming};
|
||||
use core::name::Name;
|
||||
use cache::lru_cache as lru;
|
||||
use core::error;
|
||||
|
||||
|
@ -70,7 +71,7 @@ impl WithAttributes for InputScopeCache {
|
|||
|
||||
impl InputScope for InputScopeCache {
|
||||
fn new_metric(&self, name: Name, kind: Kind) -> InputMetric {
|
||||
let name = self.qualified_name(name);
|
||||
let name = self.qualify(name);
|
||||
let lookup = {
|
||||
let mut cache = self.cache.write().expect("Cache Lock");
|
||||
cache.get(&name).map(|found| found.clone())
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
//! Cache metric definitions.
|
||||
|
||||
use core::Flush;
|
||||
use core::component::{Attributes, WithAttributes, Name, AddPrefix};
|
||||
use core::component::{Attributes, WithAttributes, Naming};
|
||||
use core::name::Name;
|
||||
use core::output::{Output, OutputMetric, OutputScope, OutputDyn};
|
||||
use core::input::Kind;
|
||||
use cache::lru_cache as lru;
|
||||
|
@ -72,7 +73,7 @@ impl WithAttributes for OutputScopeCache {
|
|||
|
||||
impl OutputScope for OutputScopeCache {
|
||||
fn new_metric(&self, name: Name, kind: Kind) -> OutputMetric {
|
||||
let name = self.qualified_name(name);
|
||||
let name = self.qualify(name);
|
||||
let lookup = {
|
||||
let mut cache = self.cache.write().expect("Cache Lock");
|
||||
cache.get(&name).map(|found| found.clone())
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
#[cfg(test)]
|
||||
use std::ops::Add;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
#[cfg(test)]
|
||||
use std::time::Duration;
|
||||
|
||||
use std::time::Instant;
|
||||
|
||||
use core::Value;
|
||||
|
||||
|
@ -37,6 +42,7 @@ thread_local! {
|
|||
/// Enables writing reproducible metrics tests in combination with #mock_clock_advance()
|
||||
/// Should be called at beginning of test, before the metric scope is created.
|
||||
/// Not feature-gated so it stays visible to outside crates but may not be used outside of tests.
|
||||
#[cfg(test)]
|
||||
pub fn mock_clock_reset() {
|
||||
if !cfg!(not(test)) {
|
||||
warn!("Mock clock used outside of cfg[]tests has no effect")
|
||||
|
@ -51,6 +57,7 @@ pub fn mock_clock_reset() {
|
|||
/// Enables writing reproducible metrics tests in combination with #mock_clock_reset()
|
||||
/// Should be after metrics have been produced but before they are published.
|
||||
/// Not feature-gated so it stays visible to outside crates but may not be used outside of tests.
|
||||
#[cfg(test)]
|
||||
pub fn mock_clock_advance(period: Duration) {
|
||||
MOCK_CLOCK.with(|now| {
|
||||
let mut now = now.borrow_mut();
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
use std::sync::Arc;
|
||||
use std::ops;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap};
|
||||
|
||||
use core::name::{Namespace, Name};
|
||||
|
||||
/// The actual distribution (random, fixed-cycled, etc) depends on selected sampling method.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Sampling {
|
||||
/// Do not sample, use all data.
|
||||
Full,
|
||||
|
||||
/// Floating point sampling rate
|
||||
/// - 1.0+ records everything
|
||||
/// - 0.5 records one of two values
|
||||
|
@ -15,20 +13,11 @@ pub enum Sampling {
|
|||
Random(f64)
|
||||
}
|
||||
|
||||
impl Default for Sampling {
|
||||
fn default() -> Self {
|
||||
Sampling::Full
|
||||
}
|
||||
}
|
||||
|
||||
/// A metrics buffering strategy.
|
||||
/// All strategies other than `Unbuffered` are applied as a best-effort, meaning that the buffer
|
||||
/// may be flushed at any moment before reaching the limit, for any or no reason in particular.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Buffering {
|
||||
/// No buffering is performed (default).
|
||||
Unbuffered,
|
||||
|
||||
/// A buffer of maximum specified size is used.
|
||||
BufferSize(usize),
|
||||
|
||||
|
@ -36,24 +25,15 @@ pub enum Buffering {
|
|||
Unlimited,
|
||||
}
|
||||
|
||||
impl Default for Buffering {
|
||||
fn default() -> Self {
|
||||
Buffering::Unbuffered
|
||||
}
|
||||
}
|
||||
|
||||
/// One struct to rule them all.
|
||||
/// Possible attributes of metric outputs and scopes.
|
||||
/// Private trait used by impls of specific With* traits.
|
||||
/// Not all attributes are used by all structs!
|
||||
/// This is a design choice to centralize code at the expense of slight waste of memory.
|
||||
/// Fields have also not been made `pub` to make it easy to change this mechanism.
|
||||
/// Field access must go through `is_` and `get_` methods declared in sub-traits.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Attributes {
|
||||
namespace: Name,
|
||||
sampling: Sampling,
|
||||
buffering: Buffering,
|
||||
namespace: Namespace,
|
||||
sampling: Option<Sampling>,
|
||||
buffering: Option<Buffering>,
|
||||
}
|
||||
|
||||
/// The only trait that requires concrete impl by metric components.
|
||||
|
@ -79,15 +59,15 @@ pub trait WithAttributes: Clone {
|
|||
}
|
||||
|
||||
/// Name operations support.
|
||||
pub trait AddPrefix {
|
||||
/// Return the namespace of the component.
|
||||
fn get_namespace(&self) -> &Name;
|
||||
pub trait Naming {
|
||||
/// Returns namespace of component.
|
||||
fn get_namespace(&self) -> &Namespace;
|
||||
|
||||
/// Join namespace and prepend in newly defined metrics.
|
||||
fn add_prefix(&self, name: &str) -> Self;
|
||||
fn namespace<S: Into<String>>(&self, name: S) -> Self;
|
||||
|
||||
/// Append the specified name to the local namespace and return the concatenated result.
|
||||
fn qualified_name(&self, metric_name: Name) -> Name;
|
||||
fn qualify<S: Into<Name>>(&self, name: S) -> Name;
|
||||
}
|
||||
|
||||
/// Name operations support.
|
||||
|
@ -100,20 +80,22 @@ pub trait Label {
|
|||
|
||||
}
|
||||
|
||||
impl<T: WithAttributes> AddPrefix for T {
|
||||
fn get_namespace(&self) -> &Name {
|
||||
impl<T: WithAttributes> Naming for T {
|
||||
|
||||
/// Returns namespace of component.
|
||||
fn get_namespace(&self) -> &Namespace {
|
||||
&self.get_attributes().namespace
|
||||
}
|
||||
|
||||
/// Join namespace and prepend in newly defined metrics.
|
||||
fn add_prefix(&self, name: &str) -> Self {
|
||||
self.with_attributes(|new_attr| new_attr.namespace = new_attr.namespace.concat(name))
|
||||
fn namespace<S: Into<String>>(&self, name: S) -> Self {
|
||||
let name = name.into();
|
||||
self.with_attributes(|new_attr| new_attr.namespace.push_back(name.clone()))
|
||||
}
|
||||
|
||||
/// Append the specified name to the local namespace and return the concatenated result.
|
||||
fn qualified_name(&self, name: Name) -> Name {
|
||||
// FIXME (perf) store name in reverse to prepend with an actual push() to the vec
|
||||
self.get_attributes().namespace.concat(name)
|
||||
fn qualify<S: Into<Name>>(&self, name: S) -> Name {
|
||||
name.into().append(self.get_attributes().namespace.clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,11 +103,11 @@ impl<T: WithAttributes> AddPrefix for T {
|
|||
pub trait Sampled: WithAttributes {
|
||||
/// Perform random sampling of values according to the specified rate.
|
||||
fn sampled(&self, sampling: Sampling) -> Self {
|
||||
self.with_attributes(|new_attr| new_attr.sampling = sampling)
|
||||
self.with_attributes(|new_attr| new_attr.sampling = Some(sampling))
|
||||
}
|
||||
|
||||
/// Get the sampling strategy for this component, if any.
|
||||
fn get_sampling(&self) -> Sampling {
|
||||
fn get_sampling(&self) -> Option<Sampling> {
|
||||
self.get_attributes().sampling
|
||||
}
|
||||
}
|
||||
|
@ -136,85 +118,11 @@ pub trait Sampled: WithAttributes {
|
|||
pub trait Buffered: WithAttributes {
|
||||
/// Return a clone with the specified buffering set.
|
||||
fn buffered(&self, buffering: Buffering) -> Self {
|
||||
self.with_attributes(|new_attr| new_attr.buffering = buffering)
|
||||
}
|
||||
|
||||
/// Is this component using buffering?
|
||||
fn is_buffered(&self) -> bool {
|
||||
match self.get_buffering() {
|
||||
Buffering::Unbuffered => false,
|
||||
_ => true
|
||||
}
|
||||
self.with_attributes(|new_attr| new_attr.buffering = Some(buffering))
|
||||
}
|
||||
|
||||
/// Return the buffering.
|
||||
fn get_buffering(&self) -> Buffering {
|
||||
fn get_buffering(&self) -> Option<Buffering> {
|
||||
self.get_attributes().buffering
|
||||
}
|
||||
}
|
||||
|
||||
/// A namespace for metrics.
|
||||
/// Does _not_ include the metric's "short" name itself.
|
||||
/// Can be empty.
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Default)]
|
||||
pub struct Name {
|
||||
inner: Vec<String>,
|
||||
}
|
||||
|
||||
impl Name {
|
||||
|
||||
/// Concatenate with another namespace into a new one.
|
||||
pub fn concat(&self, name: impl Into<Name>) -> Self {
|
||||
let mut cloned = self.clone();
|
||||
cloned.inner.extend_from_slice(&name.into().inner);
|
||||
cloned
|
||||
}
|
||||
|
||||
/// Returns true if the specified namespace is a subset or is equal to this namespace.
|
||||
pub fn starts_with(&self, name: &Name) -> bool {
|
||||
(self.inner.len() >= name.inner.len()) && (name.inner[..] == self.inner[..name.inner.len()])
|
||||
}
|
||||
|
||||
/// Combine name parts into a string.
|
||||
pub fn join(&self, separator: &str) -> String {
|
||||
|
||||
let mut buf = String::with_capacity(64);
|
||||
let mut i = self.inner.iter();
|
||||
if let Some(n) = i.next() {
|
||||
buf.push_str(n.as_ref());
|
||||
} else {
|
||||
return "".into()
|
||||
}
|
||||
for n in i {
|
||||
buf.push_str(separator);
|
||||
buf.push_str(n.as_ref());
|
||||
}
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Deref for Name {
|
||||
type Target = Vec<String>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::DerefMut for Name {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Into<String>> From<S> for Name {
|
||||
fn from(name: S) -> Name {
|
||||
let name: String = name.into();
|
||||
if name.is_empty() {
|
||||
Name::default()
|
||||
} else {
|
||||
Name { inner: vec![name] }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use core::clock::TimeHandle;
|
||||
use core::{Value, Flush};
|
||||
use core::component::Name;
|
||||
use core::name::Name;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::fmt;
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
//! Because the possibly high volume of data, this is pre-set to use aggregation.
|
||||
//! This is also kept in a separate module because it is not to be exposed outside of the crate.
|
||||
|
||||
use core::component::AddPrefix;
|
||||
use core::input::{Marker, InputScope, Counter};
|
||||
use core::component::Naming;
|
||||
use core::proxy::Proxy;
|
||||
|
||||
metrics!{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
pub mod error;
|
||||
pub mod name;
|
||||
pub mod component;
|
||||
pub mod input;
|
||||
pub mod output;
|
||||
|
@ -38,11 +39,10 @@ pub mod test {
|
|||
#[cfg(feature = "bench")]
|
||||
pub mod bench {
|
||||
|
||||
use core::{TimeHandle, Marker, Input};
|
||||
use aggregate::bucket::Bucket;
|
||||
use super::clock::TimeHandle;
|
||||
use super::input::*;
|
||||
use super::clock::*;
|
||||
use super::super::aggregate::bucket::*;
|
||||
use test;
|
||||
use aggregate::Bucket;
|
||||
|
||||
#[bench]
|
||||
fn get_instant(b: &mut test::Bencher) {
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
use std::ops::{Deref,DerefMut};
|
||||
use std::collections::{VecDeque};
|
||||
|
||||
/// Primitive struct for Namespace and Name
|
||||
/// A double-ended vec of strings constituting a metric name or a future part thereof.
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Default)]
|
||||
pub struct Namespace {
|
||||
/// Nodes are stored in order or their final appearance in the names
|
||||
/// If there is no namespace, the deque is empty.
|
||||
nodes: VecDeque<String>,
|
||||
}
|
||||
|
||||
impl Namespace {
|
||||
|
||||
/// Build a new StringDeque
|
||||
/// This is a private shortcut constructor,
|
||||
/// no one outside this module should need to do that, only use Name or Namespace.
|
||||
fn new() -> Self {
|
||||
Namespace { nodes: VecDeque::new() }
|
||||
}
|
||||
|
||||
/// Returns true if this instance is equal to or a subset (more specific) of the target instance.
|
||||
/// e.g. `a.b.c` is within `a.b`
|
||||
/// e.g. `a.d.c` is not within `a.b`
|
||||
pub fn is_within(&self, other: &Namespace) -> bool {
|
||||
// quick check: if this name has less parts it cannot be equal or more specific
|
||||
if self.len() < other.nodes.len() {
|
||||
return false
|
||||
}
|
||||
for (i, part) in other.nodes.iter().enumerate() {
|
||||
if part != &self.nodes[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn qualify<S: Into<String>>(&self, leaf: S) -> Name {
|
||||
let mut nodes = self.clone();
|
||||
nodes.push_back(leaf.into());
|
||||
Name { nodes }
|
||||
}
|
||||
|
||||
pub fn leaf(&self) -> Name {
|
||||
self.back().expect("Short metric name").clone().into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Turn any string into a StringDeque
|
||||
impl<S: Into<String>> From<S> for Namespace {
|
||||
fn from(name_part: S) -> Self {
|
||||
let name: String = name_part.into();
|
||||
// can we do better than asserting? empty names should not exist, ever...
|
||||
debug_assert!(!name.is_empty());
|
||||
let mut nodes = Namespace::new();
|
||||
nodes.push_front(name);
|
||||
nodes
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable use of VecDeque methods such as len(), push_*, insert()...
|
||||
impl Deref for Namespace {
|
||||
type Target = VecDeque<String>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.nodes
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable use of VecDeque methods such as len(), push_*, insert()...
|
||||
impl DerefMut for Namespace {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.nodes
|
||||
}
|
||||
}
|
||||
|
||||
/// The name of a metric, including the concatenated possible namespaces in which it was defined.
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub struct Name {
|
||||
nodes: Namespace,
|
||||
}
|
||||
|
||||
impl Name {
|
||||
|
||||
/// Prepend to the existing namespace.
|
||||
pub fn prepend<S: Into<Namespace>>(mut self, namespace: S) -> Self {
|
||||
let parts: Namespace = namespace.into();
|
||||
parts.iter().rev().for_each(|node|
|
||||
self.nodes.push_front(node.clone())
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
/// Append to the existing namespace.
|
||||
pub fn append<S: Into<Namespace>>(mut self, namespace: S) -> Self {
|
||||
let offset = self.nodes.len() - 1;
|
||||
let parts: Namespace = namespace.into();
|
||||
for (i, part) in parts.iter().enumerate() {
|
||||
self.nodes.insert(i + offset, part.clone())
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Combine name parts into a string.
|
||||
pub fn join(&self, separator: &str) -> String {
|
||||
self.nodes.iter().map(|s| &**s).collect::<Vec<&str>>().join(separator)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Into<String>> From<S> for Name {
|
||||
fn from(name: S) -> Self {
|
||||
Name { nodes: Namespace::from(name) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Name {
|
||||
type Target = Namespace;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.nodes
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Name {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.nodes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn string_deque_within_same() {
|
||||
let mut sd1: Namespace = "c".into();
|
||||
sd1.push_front("b".into());
|
||||
|
||||
assert_eq!(true, sd1.is_within(&sd1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_deque_within_other() {
|
||||
let mut sd1: Namespace = "b".into();
|
||||
sd1.push_front("a".into());
|
||||
|
||||
let mut sd2: Namespace = "c".into();
|
||||
sd2.push_front("b".into());
|
||||
sd2.push_front("a".into());
|
||||
|
||||
assert_eq!(true, sd2.is_within(&sd1));
|
||||
assert_eq!(false, sd1.is_within(&sd2));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
use core::input::{InputScope, InputMetric, Input, Kind};
|
||||
use core::output::{Output, OutputScope};
|
||||
use core::component::{Attributes, WithAttributes, Name, AddPrefix};
|
||||
use core::component::{Attributes, WithAttributes, Naming};
|
||||
use core::name::Name;
|
||||
use core::Flush;
|
||||
use core::error;
|
||||
use std::rc::Rc;
|
||||
|
@ -23,7 +24,7 @@ impl WithAttributes for LockingScopeBox {
|
|||
impl InputScope for LockingScopeBox {
|
||||
|
||||
fn new_metric(&self, name: Name, kind: Kind) -> InputMetric {
|
||||
let name = self.qualified_name(name);
|
||||
let name = self.qualify(name);
|
||||
let raw_metric = self.inner.lock().expect("RawScope Lock").new_metric(name, kind);
|
||||
let mutex = self.inner.clone();
|
||||
InputMetric::new(move |value| {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use core::{Flush, Value};
|
||||
use core::input::Kind;
|
||||
use core::component::Name;
|
||||
use core::name::Name;
|
||||
use core::void::Void;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Decouple metric definition from configuration with trait objects.
|
||||
|
||||
use core::component::{Attributes, WithAttributes, Name, AddPrefix};
|
||||
use core::component::{Attributes, WithAttributes, Naming};
|
||||
use core::name::{Name, Namespace};
|
||||
use core::Flush;
|
||||
use core::input::{Kind, InputMetric, InputScope};
|
||||
use core::void::VOID_INPUT;
|
||||
|
@ -24,7 +25,7 @@ lazy_static! {
|
|||
#[derive(Debug)]
|
||||
struct ProxyMetric {
|
||||
// basic info for this metric, needed to recreate new corresponding trait object if target changes
|
||||
name: Name,
|
||||
name: Namespace,
|
||||
kind: Kind,
|
||||
|
||||
// the metric trait object to proxy metric values to
|
||||
|
@ -62,9 +63,9 @@ impl Proxy {
|
|||
|
||||
struct InnerProxy {
|
||||
// namespaces can target one, many or no metrics
|
||||
targets: HashMap<Name, Arc<InputScope + Send + Sync>>,
|
||||
targets: HashMap<Namespace, Arc<InputScope + Send + Sync>>,
|
||||
// last part of the namespace is the metric's name
|
||||
metrics: BTreeMap<Name, Weak<ProxyMetric>>,
|
||||
metrics: BTreeMap<Namespace, Weak<ProxyMetric>>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for InnerProxy {
|
||||
|
@ -83,30 +84,31 @@ impl InnerProxy {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_target(&mut self, target_name: Name, target_scope: Arc<InputScope + Send + Sync>) {
|
||||
self.targets.insert(target_name.clone(), target_scope.clone());
|
||||
for (metric_name, metric) in self.metrics.range_mut(target_name.clone()..) {
|
||||
fn set_target(&mut self, namespace: &Namespace, target_scope: Arc<InputScope + Send + Sync>) {
|
||||
self.targets.insert(namespace.clone(), target_scope.clone());
|
||||
|
||||
for (metric_name, metric) in self.metrics.range_mut(namespace.clone()..) {
|
||||
if let Some(metric) = metric.upgrade() {
|
||||
// check for range end
|
||||
if !metric_name.starts_with(&target_name) { break }
|
||||
if !metric_name.is_within(namespace) { break }
|
||||
|
||||
// check if metric targeted by _lower_ namespace
|
||||
if metric.target.borrow().1 > target_name.len() { continue }
|
||||
if metric.target.borrow().1 > namespace.len() { continue }
|
||||
|
||||
let target_metric = target_scope.new_metric(metric.name.clone(), metric.kind);
|
||||
*metric.target.borrow_mut() = (target_metric, target_name.len());
|
||||
let target_metric = target_scope.new_metric(metric.name.leaf(), metric.kind);
|
||||
*metric.target.borrow_mut() = (target_metric, namespace.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_effective_target(&self, name: &Name) -> Option<(Arc<InputScope + Send + Sync>, usize)> {
|
||||
if let Some(target) = self.targets.get(name) {
|
||||
return Some((target.clone(), name.len()));
|
||||
fn get_effective_target(&self, namespace: &Namespace) -> Option<(Arc<InputScope + Send + Sync>, usize)> {
|
||||
if let Some(target) = self.targets.get(namespace) {
|
||||
return Some((target.clone(), namespace.len()));
|
||||
}
|
||||
|
||||
// no 1:1 match, scan upper namespaces
|
||||
let mut name = name.clone();
|
||||
while let Some(_popped) = name.pop() {
|
||||
let mut name = namespace.clone();
|
||||
while let Some(_popped) = name.pop_back() {
|
||||
if let Some(target) = self.targets.get(&name) {
|
||||
return Some((target.clone(), name.len()))
|
||||
}
|
||||
|
@ -114,7 +116,7 @@ impl InnerProxy {
|
|||
None
|
||||
}
|
||||
|
||||
fn unset_target(&mut self, namespace: &Name) {
|
||||
fn unset_target(&mut self, namespace: &Namespace) {
|
||||
if self.targets.remove(namespace).is_none() {
|
||||
// nothing to do
|
||||
return
|
||||
|
@ -124,27 +126,27 @@ impl InnerProxy {
|
|||
.unwrap_or_else(|| (VOID_INPUT.input_dyn(), 0));
|
||||
|
||||
// update all affected metrics to next upper targeted namespace
|
||||
for (name, metric) in self.metrics.range_mut(namespace..) {
|
||||
for (name, metric) in self.metrics.range_mut(namespace.clone()..) {
|
||||
// check for range end
|
||||
if !name.starts_with(namespace) { break }
|
||||
if !name.is_within(namespace) { break }
|
||||
|
||||
if let Some(mut metric) = metric.upgrade() {
|
||||
// check if metric targeted by _lower_ namespace
|
||||
if metric.target.borrow().1 > namespace.len() { continue }
|
||||
|
||||
let new_metric = up_target.new_metric(name.clone(), metric.kind);
|
||||
let new_metric = up_target.new_metric(name.leaf(), metric.kind);
|
||||
*metric.target.borrow_mut() = (new_metric, up_nslen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn drop_metric(&mut self, name: &Name) {
|
||||
fn drop_metric(&mut self, name: &Namespace) {
|
||||
if self.metrics.remove(name).is_none() {
|
||||
panic!("Could not remove DelegatingMetric weak ref from delegation point")
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&self, namespace: &Name) -> error::Result<()> {
|
||||
fn flush(&self, namespace: &Namespace) -> error::Result<()> {
|
||||
if let Some((target, _nslen)) = self.get_effective_target(namespace) {
|
||||
target.flush()
|
||||
} else {
|
||||
|
@ -171,7 +173,7 @@ impl Proxy {
|
|||
/// Replace target for this proxy and it's children.
|
||||
pub fn set_target<T: InputScope + Send + Sync + 'static>(&self, target: T) {
|
||||
let mut inner = self.inner.write().expect("Dispatch Lock");
|
||||
inner.set_target(self.get_namespace().clone(), Arc::new(target));
|
||||
inner.set_target(self.get_namespace(), Arc::new(target));
|
||||
}
|
||||
|
||||
/// Replace target for this proxy and it's children.
|
||||
|
@ -194,14 +196,14 @@ impl Proxy {
|
|||
|
||||
impl<S: AsRef<str>> From<S> for Proxy {
|
||||
fn from(name: S) -> Proxy {
|
||||
Proxy::new().add_prefix(name.as_ref())
|
||||
Proxy::new().namespace(name.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl InputScope for Proxy {
|
||||
/// Lookup or create a proxy stub for the requested metric.
|
||||
fn new_metric(&self, name: Name, kind: Kind) -> InputMetric {
|
||||
let name = self.qualified_name(name);
|
||||
let name: Name = self.qualify(name);
|
||||
let mut inner = self.inner.write().expect("Dispatch Lock");
|
||||
let proxy = inner
|
||||
.metrics
|
||||
|
@ -209,19 +211,21 @@ impl InputScope for Proxy {
|
|||
// TODO validate that Kind matches existing
|
||||
.and_then(|proxy_ref| Weak::upgrade(proxy_ref))
|
||||
.unwrap_or_else(|| {
|
||||
let name2 = name.clone();
|
||||
// not found, define new
|
||||
let (target, target_namespace_length) = inner.get_effective_target(&name)
|
||||
.unwrap_or_else(|| (VOID_INPUT.input_dyn(), 0));
|
||||
let metric_object = target.new_metric(name.clone(), kind);
|
||||
let proxy = Arc::new(ProxyMetric {
|
||||
name,
|
||||
kind,
|
||||
target: AtomicRefCell::new((metric_object, target_namespace_length)),
|
||||
proxy: self.inner.clone(),
|
||||
});
|
||||
inner.metrics.insert(name2, Arc::downgrade(&proxy));
|
||||
proxy
|
||||
let namespace = &*name;
|
||||
{
|
||||
// not found, define new
|
||||
let (target, target_namespace_length) = inner.get_effective_target(namespace)
|
||||
.unwrap_or_else(|| (VOID_INPUT.input_dyn(), 0));
|
||||
let metric_object = target.new_metric(namespace.leaf(), kind);
|
||||
let proxy = Arc::new(ProxyMetric {
|
||||
name: namespace.clone(),
|
||||
kind,
|
||||
target: AtomicRefCell::new((metric_object, target_namespace_length)),
|
||||
proxy: self.inner.clone(),
|
||||
});
|
||||
inner.metrics.insert(namespace.clone(), Arc::downgrade(&proxy));
|
||||
proxy
|
||||
}
|
||||
});
|
||||
InputMetric::new(move |value| proxy.target.borrow().0.write(value))
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ impl CancelHandle {
|
|||
|
||||
/// Schedule a task to run periodically.
|
||||
/// Starts a new thread for every task.
|
||||
pub fn set_schedule<F>(every: Duration, operation: F) -> CancelHandle
|
||||
fn set_schedule<F>(every: Duration, operation: F) -> CancelHandle
|
||||
where
|
||||
F: Fn() -> () + Send + 'static,
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use core::output::{Output, OutputScope, OutputMetric};
|
||||
use core::component::Name;
|
||||
use core::input::{Kind, InputDyn};
|
||||
use core::name::Name;
|
||||
use core::input::{Kind, InputDyn, InputScope};
|
||||
use core::Flush;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
@ -9,8 +9,8 @@ lazy_static! {
|
|||
/// The reference instance identifying an uninitialized metric config.
|
||||
pub static ref VOID_INPUT: Arc<InputDyn + Send + Sync> = Arc::new(Void::metrics());
|
||||
|
||||
// /// The reference instance identifying an uninitialized metric scope.
|
||||
// pub static ref NO_METRIC_SCOPE: Arc<InputScope + Send + Sync> = VOID_INPUT.input_dyn();
|
||||
/// The reference instance identifying an uninitialized metric scope.
|
||||
pub static ref NO_METRIC_SCOPE: Arc<InputScope + Send + Sync> = VOID_INPUT.input_dyn();
|
||||
}
|
||||
|
||||
/// Discard metrics output.
|
||||
|
|
41
src/lib.rs
41
src/lib.rs
|
@ -2,7 +2,7 @@
|
|||
|
||||
#![cfg_attr(feature = "bench", feature(test))]
|
||||
#![warn(missing_docs, trivial_casts, trivial_numeric_casts, unused_extern_crates,
|
||||
unused_import_braces, unused_qualifications)]
|
||||
unused_qualifications)]
|
||||
#![recursion_limit="32"]
|
||||
|
||||
#[cfg(feature = "bench")]
|
||||
|
@ -27,34 +27,39 @@ mod macros;
|
|||
|
||||
mod core;
|
||||
pub use core::{Flush, Value};
|
||||
pub use core::component::*;
|
||||
pub use core::input::*;
|
||||
pub use core::output::*;
|
||||
pub use core::scheduler::*;
|
||||
pub use core::out_lock::*;
|
||||
pub use core::component::{Naming, Sampling, Sampled, Buffered, Buffering};
|
||||
pub use core::name::{Name, Namespace};
|
||||
pub use core::input::{Input, InputDyn, InputScope, InputMetric, Counter, Timer, Marker, Gauge, Kind};
|
||||
pub use core::output::{Output, OutputDyn, OutputScope, OutputMetric};
|
||||
pub use core::scheduler::{ScheduleFlush, CancelHandle};
|
||||
pub use core::out_lock::{LockingScopeBox};
|
||||
pub use core::error::{Error, Result};
|
||||
pub use core::clock::{TimeHandle, mock_clock_advance, mock_clock_reset};
|
||||
pub use core::clock::{TimeHandle};
|
||||
|
||||
#[cfg(test)]
|
||||
pub use core::clock::{mock_clock_advance, mock_clock_reset};
|
||||
|
||||
pub use core::proxy::Proxy;
|
||||
|
||||
mod output;
|
||||
pub use output::text::*;
|
||||
pub use output::graphite::*;
|
||||
pub use output::statsd::*;
|
||||
pub use output::map::*;
|
||||
pub use output::logging::*;
|
||||
pub use output::text::{Text, TextScope};
|
||||
pub use output::graphite::{Graphite, GraphiteScope, GraphiteMetric};
|
||||
pub use output::statsd::{Statsd, StatsdScope, StatsdMetric};
|
||||
pub use output::map::{StatsMap};
|
||||
pub use output::logging::{Log, LogScope};
|
||||
|
||||
mod aggregate;
|
||||
pub use aggregate::bucket::*;
|
||||
pub use aggregate::scores::*;
|
||||
pub use aggregate::bucket::{Bucket, stats_all, stats_average, stats_summary};
|
||||
pub use aggregate::scores::{ScoreType, Scoreboard};
|
||||
|
||||
mod cache;
|
||||
pub use cache::cache_in::CachedInput;
|
||||
pub use cache::cache_out::CachedOutput;
|
||||
|
||||
mod multi;
|
||||
pub use multi::multi_in::*;
|
||||
pub use multi::multi_out::*;
|
||||
pub use multi::multi_in::{MultiInput, MultiInputScope};
|
||||
pub use multi::multi_out::{MultiOutput, MultiOutputScope};
|
||||
|
||||
mod queue;
|
||||
pub use queue::queue_in::*;
|
||||
pub use queue::queue_out::*;
|
||||
pub use queue::queue_in::{QueuedInput, InputQueue, InputQueueScope};
|
||||
pub use queue::queue_out::{QueuedOutput, OutputQueue, OutputQueueScope};
|
||||
|
|
|
@ -90,27 +90,27 @@ macro_rules! __in_context {
|
|||
|
||||
// SUB BRANCH NODE - public identifier
|
||||
($WITH:expr; $TY:ty; $(#[$attr:meta])* pub $IDENT:ident = $e:expr => { $($BRANCH:tt)*} $($REST:tt)*) => {
|
||||
lazy_static! { $(#[$attr])* pub static ref $IDENT = $WITH.add_prefix($e); }
|
||||
lazy_static! { $(#[$attr])* pub static ref $IDENT = $WITH.namespace($e); }
|
||||
__in_context!($IDENT; $TY; $($BRANCH)*);
|
||||
__in_context!($WITH; $TY; $($REST)*);
|
||||
};
|
||||
|
||||
// SUB BRANCH NODE - private identifier
|
||||
($WITH:expr; $TY:ty; $(#[$attr:meta])* $IDENT:ident = $e:expr => { $($BRANCH:tt)*} $($REST:tt)*) => {
|
||||
lazy_static! { $(#[$attr])* static ref $IDENT = $WITH.add_prefix($e); }
|
||||
lazy_static! { $(#[$attr])* static ref $IDENT = $WITH.namespace($e); }
|
||||
__in_context!($IDENT; $TY; $($BRANCH)*);
|
||||
__in_context!($WITH; $TY; $($REST)*);
|
||||
};
|
||||
|
||||
// SUB BRANCH NODE (not yet)
|
||||
($WITH:expr; $TY:ty; $(#[$attr:meta])* pub $e:expr => { $($BRANCH:tt)*} $($REST:tt)*) => {
|
||||
__in_context!($WITH.add_prefix($e); $TY; $($BRANCH)*);
|
||||
__in_context!($WITH.namespace($e); $TY; $($BRANCH)*);
|
||||
__in_context!($WITH; $TY; $($REST)*);
|
||||
};
|
||||
|
||||
// SUB BRANCH NODE (not yet)
|
||||
($WITH:expr; $TY:ty; $(#[$attr:meta])* $e:expr => { $($BRANCH:tt)*} $($REST:tt)*) => {
|
||||
__in_context!($WITH.add_prefix($e); $TY; $($BRANCH)*);
|
||||
__in_context!($WITH.namespace($e); $TY; $($BRANCH)*);
|
||||
__in_context!($WITH; $TY; $($REST)*);
|
||||
};
|
||||
|
||||
|
|
|
@ -2,24 +2,12 @@
|
|||
|
||||
use core::Flush;
|
||||
use core::input::{Kind, Input, InputScope, InputMetric, InputDyn};
|
||||
use core::component::{Attributes, WithAttributes, Name, AddPrefix};
|
||||
use core::component::{Attributes, WithAttributes, Naming};
|
||||
use core::name::Name;
|
||||
use core::error;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Wrap this output behind an asynchronous metrics dispatch queue.
|
||||
/// This is not strictly required for multi threading since the provided scopes
|
||||
/// are already Send + Sync but might be desired to lower the latency
|
||||
pub trait WithMultiInputScope: InputScope + Send + Sync + 'static + Sized {
|
||||
/// Wrap this output with an asynchronous dispatch queue of specified length.
|
||||
fn add_target<OUT: InputScope + Send + Sync + 'static>(self, target: OUT) -> MultiInputScope {
|
||||
MultiInputScope::new().add_target(self).add_target(target)
|
||||
}
|
||||
}
|
||||
|
||||
/// Blanket scope concatenation.
|
||||
impl<T: InputScope + Send + Sync + 'static + Sized> WithMultiInputScope for T {}
|
||||
|
||||
/// Opens multiple scopes at a time from just as many outputs.
|
||||
#[derive(Clone)]
|
||||
pub struct MultiInput {
|
||||
|
@ -42,7 +30,7 @@ impl Input for MultiInput {
|
|||
impl MultiInput {
|
||||
|
||||
/// Create a new multi-output.
|
||||
pub fn inputs() -> MultiInput {
|
||||
pub fn input() -> MultiInput {
|
||||
MultiInput {
|
||||
attributes: Attributes::default(),
|
||||
outputs: vec![],
|
||||
|
@ -88,7 +76,7 @@ impl MultiInputScope {
|
|||
|
||||
impl InputScope for MultiInputScope {
|
||||
fn new_metric(&self, name: Name, kind: Kind) -> InputMetric {
|
||||
let ref name = self.qualified_name(name);
|
||||
let ref name = self.qualify(name);
|
||||
let metrics: Vec<InputMetric> = self.scopes.iter()
|
||||
.map(move |scope| scope.new_metric(name.clone(), kind))
|
||||
.collect();
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
//! Dispatch metrics to multiple sinks.
|
||||
|
||||
use core::Flush;
|
||||
use core::component::{Attributes, WithAttributes, Name, AddPrefix};
|
||||
use core::component::{Attributes, WithAttributes, Naming};
|
||||
use core::name::Name;
|
||||
use core::input::Kind;
|
||||
use core::output::{Output, OutputMetric, OutputScope, OutputDyn};
|
||||
use core::error;
|
||||
|
@ -30,7 +31,7 @@ impl Output for MultiOutput {
|
|||
|
||||
impl MultiOutput {
|
||||
/// Create a new multi-output.
|
||||
pub fn metrics() -> MultiOutput {
|
||||
pub fn output() -> MultiOutput {
|
||||
MultiOutput {
|
||||
attributes: Attributes::default(),
|
||||
outputs: vec![],
|
||||
|
@ -76,7 +77,7 @@ impl MultiOutputScope {
|
|||
|
||||
impl OutputScope for MultiOutputScope {
|
||||
fn new_metric(&self, name: Name, kind: Kind) -> OutputMetric {
|
||||
let ref name = self.qualified_name(name);
|
||||
let ref name = self.qualify(name);
|
||||
let metrics: Vec<OutputMetric> = self.scopes.iter()
|
||||
.map(move |scope| scope.new_metric(name.clone(), kind))
|
||||
.collect();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Send metrics to a graphite server.
|
||||
|
||||
use core::component::{Buffered, Attributes, WithAttributes, Name, AddPrefix};
|
||||
use core::component::{Buffered, Attributes, WithAttributes, Naming};
|
||||
use core::name::Name;
|
||||
use core::{Flush, Value};
|
||||
use core::input::Kind;
|
||||
use core::metrics;
|
||||
|
@ -71,7 +72,7 @@ pub struct GraphiteScope {
|
|||
impl OutputScope for GraphiteScope {
|
||||
/// Define a metric of the specified type.
|
||||
fn new_metric(&self, name: Name, kind: Kind) -> OutputMetric {
|
||||
let mut prefix = self.qualified_name(name).join(".");
|
||||
let mut prefix = self.qualify(name).join(".");
|
||||
prefix.push(' ');
|
||||
|
||||
let scale = match kind {
|
||||
|
@ -125,7 +126,7 @@ impl GraphiteScope {
|
|||
}
|
||||
};
|
||||
|
||||
if !self.is_buffered() {
|
||||
if self.get_buffering().is_none() {
|
||||
if let Err(e) = self.flush_inner(buffer) {
|
||||
debug!("Could not send to graphite {}", e)
|
||||
}
|
||||
|
@ -186,7 +187,8 @@ impl Drop for GraphiteScope {
|
|||
#[cfg(feature = "bench")]
|
||||
mod bench {
|
||||
|
||||
use core::*;
|
||||
use core::component::*;
|
||||
use core::input::*;
|
||||
use super::*;
|
||||
use test;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use core::{Flush, Value};
|
||||
use core::input::{Kind, Input, InputScope, InputMetric};
|
||||
use core::component::{Attributes, WithAttributes, Buffered, Name, AddPrefix};
|
||||
use core::component::{Attributes, WithAttributes, Buffered, Naming};
|
||||
use core::name::Name;
|
||||
use core::error;
|
||||
use cache::cache_in;
|
||||
use queue::queue_in;
|
||||
|
@ -69,13 +70,13 @@ impl cache_in::CachedInput for Log {}
|
|||
|
||||
impl InputScope for LogScope {
|
||||
fn new_metric(&self, name: Name, kind: Kind) -> InputMetric {
|
||||
let name = self.qualified_name(name);
|
||||
let name = self.qualify(name);
|
||||
let template = (self.output.format_fn)(&name, kind);
|
||||
|
||||
let print_fn = self.output.print_fn.clone();
|
||||
let entries = self.entries.clone();
|
||||
|
||||
if self.is_buffered() {
|
||||
if let Some(_buffering) = self.get_buffering() {
|
||||
InputMetric::new(move |value| {
|
||||
let mut buffer = Vec::with_capacity(32);
|
||||
match (print_fn)(&mut buffer, &template, value) {
|
||||
|
@ -87,6 +88,7 @@ impl InputScope for LogScope {
|
|||
}
|
||||
})
|
||||
} else {
|
||||
// unbuffered
|
||||
InputMetric::new(move |value| {
|
||||
let mut buffer = Vec::with_capacity(32);
|
||||
match (print_fn)(&mut buffer, &template, value) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use core::{Flush, Value};
|
||||
use core::input::Kind;
|
||||
use core::component::Name;
|
||||
use core::name::Name;
|
||||
use core::output::{OutputMetric, OutputScope};
|
||||
|
||||
use std::rc::Rc;
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
use core::{Flush, Value};
|
||||
use core::input::{Kind, Input, InputScope, InputMetric};
|
||||
use core::component::{Attributes, WithAttributes, Buffered, Buffering, Name, AddPrefix};
|
||||
use core::component::{Attributes, WithAttributes, Buffered, Buffering, Naming};
|
||||
use core::name::Name;
|
||||
use core::output::{Output, OutputMetric, OutputScope};
|
||||
use core::error;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Send metrics to a statsd server.
|
||||
|
||||
use core::component::{Buffered, Attributes, Sampled, Sampling, WithAttributes, Name, AddPrefix};
|
||||
use core::component::{Buffered, Attributes, Sampled, Sampling, WithAttributes, Naming};
|
||||
use core::name::Name;
|
||||
use core::pcg32;
|
||||
use core::{Flush, Value};
|
||||
use core::input::Kind;
|
||||
|
@ -78,7 +79,7 @@ impl Sampled for StatsdScope {}
|
|||
impl OutputScope for StatsdScope {
|
||||
/// Define a metric of the specified type.
|
||||
fn new_metric(&self, name: Name, kind: Kind) -> OutputMetric {
|
||||
let mut prefix = self.qualified_name(name).join(".");
|
||||
let mut prefix = self.qualify(name).join(".");
|
||||
prefix.push(':');
|
||||
|
||||
let mut suffix = String::with_capacity(16);
|
||||
|
@ -97,7 +98,7 @@ impl OutputScope for StatsdScope {
|
|||
|
||||
let cloned = self.clone();
|
||||
|
||||
if let Sampling::Random(float_rate) = self.get_sampling() {
|
||||
if let Some(Sampling::Random(float_rate)) = self.get_sampling() {
|
||||
suffix.push_str(&format!{"|@{}\n", float_rate});
|
||||
let int_sampling_rate = pcg32::to_int_rate(float_rate);
|
||||
let metric = StatsdMetric { prefix, suffix, scale };
|
||||
|
@ -153,7 +154,7 @@ impl StatsdScope {
|
|||
buffer.push_str(&metric.suffix);
|
||||
}
|
||||
|
||||
if !self.is_buffered() {
|
||||
if self.get_buffering().is_none() {
|
||||
if let Err(e) = self.flush_inner(buffer) {
|
||||
debug!("Could not send to statsd {}", e)
|
||||
}
|
||||
|
@ -205,7 +206,8 @@ impl Drop for StatsdScope {
|
|||
#[cfg(feature = "bench")]
|
||||
mod bench {
|
||||
|
||||
use core::*;
|
||||
use core::component::*;
|
||||
use core::input::*;
|
||||
use super::*;
|
||||
use test;
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
|
||||
use core::{Flush, Value};
|
||||
use core::input::Kind;
|
||||
use core::component::{Attributes, WithAttributes, Buffered, Name, AddPrefix};
|
||||
use core::component::{Attributes, WithAttributes, Buffered, Naming};
|
||||
use core::name::Name;
|
||||
use core::output::{Output, OutputMetric, OutputScope};
|
||||
use core::error;
|
||||
use cache::cache_out;
|
||||
|
@ -122,13 +123,13 @@ impl<W: Write + Send + Sync + 'static> Buffered for TextScope<W> {}
|
|||
|
||||
impl<W: Write + Send + Sync + 'static> OutputScope for TextScope<W> {
|
||||
fn new_metric(&self, name: Name, kind: Kind) -> OutputMetric {
|
||||
let name = self.qualified_name(name);
|
||||
let name = self.qualify(name);
|
||||
let template = (self.output.format_fn)(&name, kind);
|
||||
|
||||
let print_fn = self.output.print_fn.clone();
|
||||
let entries = self.entries.clone();
|
||||
|
||||
if self.is_buffered() {
|
||||
if let Some(_buffering) = self.get_buffering() {
|
||||
OutputMetric::new(move |value| {
|
||||
let mut buffer = Vec::with_capacity(32);
|
||||
match (print_fn)(&mut buffer, &template, value) {
|
||||
|
@ -140,6 +141,7 @@ impl<W: Write + Send + Sync + 'static> OutputScope for TextScope<W> {
|
|||
}
|
||||
})
|
||||
} else {
|
||||
// unbuffered
|
||||
let output = self.output.clone();
|
||||
OutputMetric::new(move |value| {
|
||||
let mut buffer = Vec::with_capacity(32);
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
//! Metrics definitions are still synchronous.
|
||||
//! If queue size is exceeded, calling code reverts to blocking.
|
||||
|
||||
use core::component::{Attributes, Name, WithAttributes, AddPrefix};
|
||||
use core::component::{Attributes, WithAttributes, Naming};
|
||||
use core::name::Name;
|
||||
use core::input::{Kind, Input, InputScope, InputDyn, InputMetric};
|
||||
use core::{Value, Flush};
|
||||
use core::metrics;
|
||||
|
@ -120,7 +121,7 @@ impl WithAttributes for InputQueueScope {
|
|||
|
||||
impl InputScope for InputQueueScope {
|
||||
fn new_metric(&self, name: Name, kind:Kind) -> InputMetric {
|
||||
let name = self.qualified_name(name);
|
||||
let name = self.qualify(name);
|
||||
let target_metric = self.target.new_metric(name, kind);
|
||||
let sender = self.sender.clone();
|
||||
InputMetric::new(move |value| {
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
//! RawMetrics definitions are still synchronous.
|
||||
//! If queue size is exceeded, calling code reverts to blocking.
|
||||
//!
|
||||
use core::component::{Attributes, Name, WithAttributes, AddPrefix};
|
||||
use core::component::{Attributes, WithAttributes, Naming};
|
||||
use core::name::Name;
|
||||
use core::input::{Kind, Input, InputScope, InputMetric};
|
||||
use core::output::{OutputDyn, OutputScope, OutputMetric, Output};
|
||||
use core::{Value, Flush};
|
||||
|
@ -114,7 +115,7 @@ impl WithAttributes for OutputQueueScope {
|
|||
|
||||
impl InputScope for OutputQueueScope {
|
||||
fn new_metric(&self, name: Name, kind:Kind) -> InputMetric {
|
||||
let name = self.qualified_name(name);
|
||||
let name = self.qualify(name);
|
||||
let target_metric = Arc::new(self.target.new_metric(name, kind));
|
||||
let sender = self.sender.clone();
|
||||
InputMetric::new(move |value| {
|
||||
|
|
Loading…
Reference in New Issue