Fix format + naming + a few tests

This commit is contained in:
Francis Lalonde 2018-03-13 09:54:12 -04:00
parent 9b84a1ac42
commit d4274cf49c
27 changed files with 227 additions and 268 deletions

View File

@ -98,12 +98,12 @@ For speed and easier maintenance, metrics are usually defined statically:
#[macro_use] extern crate lazy_static;
use dipstick::*;
app_metrics!(String, APP_METRICS = to_stdout());
app_counter!(String, APP_METRICS, {
COUNTER_A: "counter_a",
app_metrics!("my_app" => {
@Counter COUNTER_A: "counter_a";
});
fn main() {
send_delegated_metrics(to_stdout());
COUNTER_A.count(11);
}
```

View File

@ -3,4 +3,4 @@ extern crate skeptic;
fn main() {
// generates doc tests for `README.md`.
skeptic::generate_doc_tests(&["README.md"]);
}
}

View File

@ -7,11 +7,13 @@ use dipstick::*;
use std::time::Duration;
fn main() {
// badlog::init(Some("info"));
// badlog::init(Some("info"));
let metrics = app_metrics(
to_graphite("localhost:2003").expect("Connecting")
.with_namespace(&["my", "app"][..]));
to_graphite("localhost:2003")
.expect("Connecting")
.with_namespace(&["my", "app"][..]),
);
loop {
metrics.counter("counter_a").count(123);

View File

@ -1,7 +1,8 @@
//! A sample application sending ad-hoc counter values both to statsd _and_ to stdout.
extern crate dipstick;
#[macro_use] extern crate lazy_static;
#[macro_use]
extern crate lazy_static;
use dipstick::*;
use std::time::Duration;
@ -41,11 +42,11 @@ app_metrics!(LIB_METRICS => {
});
fn main() {
set_global_metrics_receiver(to_stdout());
send_delegated_metrics(to_stdout());
loop {
ROOT_COUNTER.count(123);
ANOTHER_COUNTER.count(456);
ROOT_TIMER.interval_us(2000000);
ROOT_GAUGE.value(34534);
std::thread::sleep(Duration::from_millis(40));

View File

@ -1,28 +1,28 @@
//! A sample application sending ad-hoc counter values both to statsd _and_ to stdout.
extern crate dipstick;
#[macro_use] extern crate lazy_static;
#[macro_use]
extern crate lazy_static;
use dipstick::*;
use std::time::Duration;
app_metrics!((Statsd, String), DIFFERENT_TYPES = (
app_metrics!(<(Statsd, String)> DIFFERENT_TYPES = (
// combine outputs of different types by using a tuple
to_statsd("localhost:8125").expect("Connecting"),
to_stdout(),
););
app_metrics!(Vec<String>, SAME_TYPE = [
app_metrics!(<Vec<String>> SAME_TYPE = [
// combine multiple outputs of the same type by using an array
to_stdout().with_prefix("yeah"),
to_stdout().with_prefix("ouch"),
to_stdout().with_sampling_rate(0.5),
][..];);
app_metrics!(Vec<String>, MUTANT_CHILD = SAME_TYPE.with_prefix("super").with_prefix("duper"););
app_metrics!(<Vec<String>> MUTANT_CHILD = SAME_TYPE.with_prefix("super").with_prefix("duper"););
fn main() {
loop {
DIFFERENT_TYPES.counter("counter_a").count(123);
SAME_TYPE.timer("timer_a").interval_us(2000000);

View File

@ -6,7 +6,6 @@ use dipstick::*;
use std::time::Duration;
fn main() {
// note that this can also be done using the app_metrics! macro
let different_type_metrics = app_metrics((
// combine metrics of different types in a tuple

View File

@ -15,7 +15,6 @@ pub mod metric {
// and is even more work because IDE's such as IntelliJ can not yet see through macro blocks :(
lazy_static! {
pub static ref METRICS: AppMetrics<String> = app_metrics(to_stdout());
pub static ref COUNTER_A: AppCounter<String> = METRICS.counter("counter_a");
pub static ref TIMER_B: AppTimer<String> = METRICS.timer("timer_b");
}

View File

@ -18,8 +18,7 @@ use std::sync::{Arc, RwLock};
/// Needs to be connected to a publish to be useful.
/// ```
/// use dipstick::*;
/// let sink = aggregate(4, summary, to_stdout());
/// let metrics = global_metrics(sink);
/// let metrics: AppMetrics<_> = aggregate(summary, to_stdout()).into();
/// metrics.marker("my_event").mark();
/// metrics.marker("my_event").mark();
/// ```
@ -30,7 +29,7 @@ where
{
Aggregator {
metrics: Arc::new(RwLock::new(HashMap::new())),
publish: Arc::new(Publisher::new(stat_fn, to_chain))
publish: Arc::new(Publisher::new(stat_fn, to_chain)),
}
}
@ -43,11 +42,9 @@ impl From<Aggregator> for AppMetrics<Aggregate> {
ScopeCmd::Write(metric, value) => {
let metric: &Aggregate = metric;
metric.update(value)
},
ScopeCmd::Flush => {
agg_1.flush()
}
})
ScopeCmd::Flush => agg_1.flush(),
}),
)
}
}
@ -67,7 +64,6 @@ pub struct Aggregator {
publish: Arc<Publish>,
}
impl Aggregator {
/// Build a new metric aggregation point with specified initial capacity of metrics to aggregate.
pub fn with_capacity(size: usize, publish: Arc<Publish>) -> Aggregator {
@ -95,7 +91,9 @@ impl Aggregator {
/// Lookup or create a scoreboard for the requested metric.
pub fn define_metric(&self, kind: Kind, name: &str, _rate: Rate) -> Aggregate {
self.metrics.write().expect("Locking aggregator")
self.metrics
.write()
.expect("Locking aggregator")
.entry(name.to_string())
.or_insert_with(|| Arc::new(Scoreboard::new(kind, name.to_string())))
.clone()

View File

@ -36,7 +36,8 @@ where
#[derivative(Debug)]
pub struct AppMarker<M> {
metric: M,
#[derivative(Debug = "ignore")] scope: ControlScopeFn<M>,
#[derivative(Debug = "ignore")]
scope: ControlScopeFn<M>,
}
impl<M> AppMarker<M> {
@ -51,7 +52,8 @@ impl<M> AppMarker<M> {
#[derivative(Debug)]
pub struct AppCounter<M> {
metric: M,
#[derivative(Debug = "ignore")] scope: ControlScopeFn<M>,
#[derivative(Debug = "ignore")]
scope: ControlScopeFn<M>,
}
impl<M> AppCounter<M> {
@ -69,7 +71,8 @@ impl<M> AppCounter<M> {
#[derivative(Debug)]
pub struct AppGauge<M> {
metric: M,
#[derivative(Debug = "ignore")] scope: ControlScopeFn<M>,
#[derivative(Debug = "ignore")]
scope: ControlScopeFn<M>,
}
impl<M> AppGauge<M> {
@ -92,7 +95,8 @@ impl<M> AppGauge<M> {
#[derivative(Debug)]
pub struct AppTimer<M> {
metric: M,
#[derivative(Debug = "ignore")] scope: ControlScopeFn<M>,
#[derivative(Debug = "ignore")]
scope: ControlScopeFn<M>,
}
impl<M> AppTimer<M> {
@ -102,7 +106,8 @@ impl<M> AppTimer<M> {
where
V: ToPrimitive,
{
self.scope.write(&self.metric, interval_us.to_u64().unwrap());
self.scope
.write(&self.metric, interval_us.to_u64().unwrap());
interval_us
}
@ -143,26 +148,31 @@ impl<M> AppTimer<M> {
#[derive(Derivative, Clone)]
#[derivative(Debug)]
pub struct AppMetrics<M> {
#[derivative(Debug = "ignore")] define_metric_fn: DefineMetricFn<M>,
#[derivative(Debug = "ignore")] single_scope: ControlScopeFn<M>,
#[derivative(Debug = "ignore")]
define_metric_fn: DefineMetricFn<M>,
#[derivative(Debug = "ignore")]
single_scope: ControlScopeFn<M>,
}
impl<M> AppMetrics<M> {
/// Create new application metrics instance.
pub fn new(define_metric_fn: DefineMetricFn<M>, scope: ControlScopeFn<M>, ) -> Self {
AppMetrics { define_metric_fn, single_scope: scope }
pub fn new(define_metric_fn: DefineMetricFn<M>, scope: ControlScopeFn<M>) -> Self {
AppMetrics {
define_metric_fn,
single_scope: scope,
}
}
}
impl<M> AppMetrics<M>
where
M: Clone + Send + Sync + 'static,
where
M: Clone + Send + Sync + 'static,
{
#[inline]
fn define_metric(&self, kind: Kind, name: &str, rate: Rate) -> M {
(self.define_metric_fn)(kind, name, rate)
}
/// Get an event counter of the provided name.
pub fn marker<AS: AsRef<str>>(&self, name: AS) -> AppMarker<M> {
let metric = self.define_metric(Marker, name.as_ref(), 1.0);
@ -226,10 +236,7 @@ impl<M: Send + Sync + Clone + 'static> Receiver for AppMetrics<M> {
let scope: ControlScopeFn<M> = self.single_scope.clone();
let metric: M = self.define_metric(kind, name, rate);
Box::new(AppReceiverMetric {
metric,
scope,
})
Box::new(AppReceiverMetric { metric, scope })
}
fn flush(&self) {
@ -247,7 +254,7 @@ impl<M> ReceiverMetric for AppReceiverMetric<M> {
impl<M: Send + Sync + Clone + 'static> WithNamespace for AppMetrics<M> {
fn with_name<IN: Into<Namespace>>(&self, names: IN) -> Self {
let ref ns = names.into();
let ns = &names.into();
AppMetrics {
define_metric_fn: add_namespace(ns, self.define_metric_fn.clone()),
single_scope: self.single_scope.clone(),

View File

@ -10,9 +10,10 @@ use std::sync::Arc;
use std::sync::mpsc;
use std::thread;
mod_metrics!{
Aggregate, DIPSTICK_METRICS.with_prefix("async_queue");
@Marker SEND_FAILED: "send_failed";
app_metrics!{
<Aggregate> DIPSTICK_METRICS.with_prefix("async_queue") => {
@Marker SEND_FAILED: "send_failed";
}
}
/// Enqueue collected metrics for dispatch on background thread.
@ -57,7 +58,7 @@ impl<M: Send + Sync + Clone + 'static> WithAsyncQueue for ScopeMetrics<M> {
ScopeCmd::Write(metric, value) => {
let metric: &M = metric;
Some((metric.clone(), value))
},
}
ScopeCmd::Flush => None,
};
sender

View File

@ -20,7 +20,7 @@ where
/// Add a caching decorator to a metric definition function.
pub fn add_cache<M>(cache_size: usize, next: DefineMetricFn<M>) -> DefineMetricFn<M>
where
M: Clone + Send + Sync + 'static
M: Clone + Send + Sync + 'static,
{
let cache: RwLock<LRUCache<String, M>> = RwLock::new(LRUCache::with_capacity(cache_size));
Arc::new(move |kind, name, rate| {

View File

@ -99,16 +99,16 @@ pub enum ScopeCmd<'a, M: 'a> {
/// Create a new metric scope based on the provided scope function.
pub fn control_scope<M, F>(scope_fn: F) -> ControlScopeFn<M>
where F: Fn(ScopeCmd<M>) + 'static
where
F: Fn(ScopeCmd<M>) + 'static,
{
Arc::new(InnerControlScopeFn {
flush_on_drop: true,
scope_fn: Box::new(scope_fn)
scope_fn: Box::new(scope_fn),
})
}
impl<M> InnerControlScopeFn<M> {
/// Write a value to this scope.
///
/// ```rust
@ -132,7 +132,6 @@ impl<M> InnerControlScopeFn<M> {
pub fn flush(&self) {
(self.scope_fn)(Flush)
}
}
impl<M> Drop for InnerControlScopeFn<M> {
@ -142,4 +141,3 @@ impl<M> Drop for InnerControlScopeFn<M> {
}
}
}

View File

@ -12,13 +12,15 @@ use atomic_refcell::*;
/// The registry contains a list of every metrics dispatch point in the app.
lazy_static! {
static ref DISPATCH_REGISTRY: RwLock<Vec<DelegationPoint>> = RwLock::new(vec![]);
static ref DELEGATE_REGISTRY: RwLock<Vec<DelegationPoint>> = RwLock::new(vec![]);
}
/// Install a new receiver for all dispatched metrics, replacing any previous receiver.
pub fn set_global_metrics_receiver<IS: Into<AppMetrics<T>>, T: Send + Sync + Clone + 'static>(receiver: IS) {
pub fn send_delegated_metrics<IS: Into<AppMetrics<T>>, T: Send + Sync + Clone + 'static>(
receiver: IS,
) {
let rec = receiver.into();
for d in DISPATCH_REGISTRY.read().unwrap().iter() {
for d in DELEGATE_REGISTRY.read().unwrap().iter() {
d.set_receiver(rec.clone());
}
}
@ -30,9 +32,12 @@ pub fn delegate() -> DelegationPoint {
inner: Arc::new(RwLock::new(InnerDelegationPoint {
metrics: HashMap::new(),
receiver: Box::new(app_metrics(to_void())),
}))
})),
};
DISPATCH_REGISTRY.write().unwrap().push(delegation_point.clone());
DELEGATE_REGISTRY
.write()
.unwrap()
.push(delegation_point.clone());
delegation_point
}
@ -107,32 +112,40 @@ impl From<DelegationPoint> for AppMetrics<Delegate> {
AppMetrics::new(
// define metric
Arc::new(move |kind, name, rate| dispatcher.define_metric(kind, name, rate)),
// write / flush metric
control_scope(move |cmd| match cmd {
ScopeCmd::Write(metric, value) => {
let dispatch: &Arc<DelegatingMetric> = metric;
let receiver_metric: AtomicRef<Box<ReceiverMetric + Send + Sync>> = dispatch.receiver.borrow();
let receiver_metric: AtomicRef<
Box<ReceiverMetric + Send + Sync>,
> = dispatch.receiver.borrow();
receiver_metric.write(value)
},
ScopeCmd::Flush => {
dispatcher_1.inner.write().expect("Locking dispatcher").receiver.flush()
},
})
}
ScopeCmd::Flush => dispatcher_1
.inner
.write()
.expect("Locking dispatcher")
.receiver
.flush(),
}),
)
}
}
impl DelegationPoint {
/// Install a new metric receiver, replacing the previous one.
pub fn set_receiver<IS: Into<AppMetrics<T>>, T: Send + Sync + Clone + 'static>(&self, receiver: IS) {
pub fn set_receiver<IS: Into<AppMetrics<T>>, T: Send + Sync + Clone + 'static>(
&self,
receiver: IS,
) {
let receiver: Box<Receiver + Send + Sync> = Box::new(receiver.into());
let inner: &mut InnerDelegationPoint = &mut *self.inner.write().expect("Locking dispatcher");
let inner: &mut InnerDelegationPoint =
&mut *self.inner.write().expect("Locking dispatcher");
for mut metric in inner.metrics.values() {
if let Some(metric) = metric.upgrade() {
let receiver_metric = receiver.box_metric(metric.kind, metric.name.as_ref(), metric.rate);
let receiver_metric =
receiver.box_metric(metric.kind, metric.name.as_ref(), metric.rate);
*metric.receiver.borrow_mut() = receiver_metric;
}
}
@ -147,7 +160,7 @@ impl DelegationPoint {
let receiver_metric = inner.receiver.box_metric(kind, name, rate);
let dispatcher_metric = Arc::new(DelegatingMetric {
let delegating_metric = Arc::new(DelegatingMetric {
kind,
name: name.to_string(),
rate,
@ -155,17 +168,19 @@ impl DelegationPoint {
dispatcher: self.clone(),
});
inner.metrics.insert(dispatcher_metric.name.clone(), Arc::downgrade(&dispatcher_metric));
dispatcher_metric
inner.metrics.insert(
delegating_metric.name.clone(),
Arc::downgrade(&delegating_metric),
);
delegating_metric
}
fn drop_metric(&self, metric: &DelegatingMetric) {
let mut inner = self.inner.write().expect("Locking dispatcher");
if let None = inner.metrics.remove(&metric.name) {
panic!("Could not remove DispatchMetric weak ref from Dispatcher")
let mut inner = self.inner.write().expect("Locking delegation point");
if inner.metrics.remove(&metric.name).is_none() {
panic!("Could not remove DelegatingMetric weak ref from delegation point")
}
}
}
#[cfg(feature = "bench")]

View File

@ -15,8 +15,7 @@ use std::fmt::Debug;
use socket::RetrySocket;
app_metrics!{
Aggregate,
DIPSTICK_METRICS.with_prefix("graphite") => {
<Aggregate> DIPSTICK_METRICS.with_prefix("graphite") => {
@Marker SEND_ERR: "send_failed";
@Marker TRESHOLD_EXCEEDED: "bufsize_exceeded";
@Counter SENT_BYTES: "sent_bytes";
@ -50,7 +49,7 @@ where
by a factor of {} when sent to graphite.",
kind, name, rate, upsample
);
scale = scale * upsample;
scale *= upsample;
}
Graphite { prefix, scale }

View File

@ -0,0 +1 @@

View File

@ -1,14 +1,8 @@
//! A quick, modular metrics toolkit for Rust applications.
#![cfg_attr(feature = "bench", feature(test))]
#![warn(
missing_docs,
trivial_casts,
trivial_numeric_casts,
unused_extern_crates,
unused_import_braces,
unused_qualifications,
)]
#![warn(missing_docs, trivial_casts, trivial_numeric_casts, unused_extern_crates,
unused_import_braces, unused_qualifications)]
#[cfg(feature = "bench")]
extern crate test;
@ -20,9 +14,9 @@ extern crate log;
extern crate derivative;
#[macro_use]
extern crate lazy_static;
extern crate atomic_refcell;
extern crate num;
extern crate time;
extern crate atomic_refcell;
mod pcg32;
mod lru_cache;

View File

@ -121,7 +121,7 @@ impl<K: Clone + Hash + Eq, V> LRUCache<K, V> {
/// Removes an item from the linked list.
fn remove_from_list(&mut self, i: usize) {
let (prev, next) = {
let entry = self.entries.get_mut(i).unwrap();
let entry = &mut self.entries[i];
(entry.prev, entry.next)
};
match (prev, next) {

View File

@ -14,46 +14,48 @@ macro_rules! time {
let value = $body;
$timer.stop(start_time);
value
}}
}};
}
/// AppMetrics can be used from anywhere (public), does not need to declare metrics in this block.
#[macro_export]
#[doc(hidden)]
macro_rules! app_metrics {
// TYPED
// typed, public, no metrics
($METRIC_TYPE:ty, pub $METRIC_ID:ident = $e:expr;) => {
(<$METRIC_TYPE:ty> pub $METRIC_ID:ident = $e:expr;) => {
lazy_static! { pub static ref $METRIC_ID: AppMetrics<$METRIC_TYPE> = $e.into(); }
};
// typed, public, some metrics
($METRIC_TYPE:ty, pub $METRIC_ID:ident = $e:expr => { $($REMAINING:tt)+ }) => {
(<$METRIC_TYPE:ty> pub $METRIC_ID:ident = $e:expr => { $($REMAINING:tt)+ }) => {
lazy_static! { pub static ref $METRIC_ID: AppMetrics<$METRIC_TYPE> = $e.into(); }
__metrics_block!($METRIC_ID: $METRIC_TYPE; $($REMAINING)*);
};
// typed, module, no metrics
($METRIC_TYPE:ty, $METRIC_ID:ident = $e:expr;) => {
(<$METRIC_TYPE:ty> $METRIC_ID:ident = $e:expr;) => {
lazy_static! { pub static ref $METRIC_ID: AppMetrics<$METRIC_TYPE> = $e.into(); }
};
// typed, module, some metrics
($METRIC_TYPE:ty, $METRIC_ID:ident = $e:expr => { $($REMAINING:tt)+ }) => {
(<$METRIC_TYPE:ty> $METRIC_ID:ident = $e:expr => { $($REMAINING:tt)+ }) => {
lazy_static! { pub static ref $METRIC_ID: AppMetrics<$METRIC_TYPE> = $e.into(); }
__metrics_block!($METRIC_ID: $METRIC_TYPE; $($REMAINING)*);
};
// typed, reuse predeclared
($METRIC_TYPE:ty, $METRIC_ID:ident => { $($REMAINING:tt)+ }) => {
(<$METRIC_TYPE:ty> $METRIC_ID:ident => { $($REMAINING:tt)+ }) => {
__metrics_block!($METRIC_ID: $METRIC_TYPE; $($REMAINING)*);
};
// typed, unidentified, some metrics
($METRIC_TYPE:ty, $e:expr => { $($REMAINING:tt)+ }) => {
(<$METRIC_TYPE:ty> $e:expr => { $($REMAINING:tt)+ }) => {
lazy_static! { pub static ref UNIDENT_METRIC: AppMetrics<$METRIC_TYPE> = $e.into(); }
__metrics_block!(UNIDENT_METRIC: $METRIC_TYPE; $($REMAINING)*);
};
// typed, root, some metrics
($METRIC_TYPE:ty, { $($REMAINING:tt)+ }) => {
(<$METRIC_TYPE:ty> { $($REMAINING:tt)+ }) => {
lazy_static! { pub static ref ROOT_METRICS: AppMetrics<$METRIC_TYPE> = "".into(); }
__metrics_block!(ROOT_METRICS: $METRIC_TYPE; $($REMAINING)*);
};
// DELEGATED
// delegated, public, no metrics
(pub $METRIC_ID:ident = $e:expr;) => {
lazy_static! { pub static ref $METRIC_ID: AppMetrics<Delegate> = $e.into(); }
@ -76,7 +78,6 @@ macro_rules! app_metrics {
($METRIC_ID:ident => { $($REMAINING:tt)+ }) => {
__metrics_block!($METRIC_ID: Delegate; $($REMAINING)*);
};
// delegated, unidentified, some metrics
($e:expr => { $($REMAINING:tt)+ }) => {
lazy_static! { pub static ref UNIDENT_METRIC: AppMetrics<Delegate> = $e.into(); }
@ -89,188 +90,131 @@ macro_rules! app_metrics {
};
}
// ModMetrics be used from declaring module, does not need to declare metrics in this block.
#[macro_export]
#[deprecated]
macro_rules! mod_metrics {
($METRIC_TYPE:ty, $METRIC_ID:ident = $e:expr; $($REMAINING:tt)*) => {
lazy_static! { static ref $METRIC_ID: AppMetrics<$METRIC_TYPE> = $e.into(); }
__metrics_block!($METRIC_ID: $METRIC_TYPE; $($REMAINING)*);
};
// Anonymous Mod Metrics
// Can't be used outside macro, any metrics must be declared in same block.
($METRIC_TYPE:ty, $e:expr; $($REMAINING:tt)*) => {
lazy_static! { static ref __LOCAL_METRICS: AppMetrics<$METRIC_TYPE> = $e.into(); }
__metrics_block!(__LOCAL_METRICS: $METRIC_TYPE; $($REMAINING)*);
};
}
/// Internal macro required to abstract over pub/non-pub versions of the macro
#[macro_export]
#[doc(hidden)]
macro_rules! __metrics_block {
($APP_METRICS:ident : $METRIC_TYPE:ty; $(#[$attr:meta])* pub @Counter $METRIC_ID:ident : $METRIC_NAME:expr; $($REMAINING:tt)*) => {
lazy_static! { $(#[$attr])* pub static ref $METRIC_ID: AppCounter<$METRIC_TYPE> = $APP_METRICS.counter($METRIC_NAME); }
($APP_METRICS:ident : $METRIC_TYPE:ty;
$(#[$attr:meta])* pub @Counter $METRIC_ID:ident : $METRIC_NAME:expr; $($REMAINING:tt)*) => {
lazy_static! { $(#[$attr])* pub static ref $METRIC_ID:
AppCounter<$METRIC_TYPE> = $APP_METRICS.counter($METRIC_NAME); }
__metrics_block!($APP_METRICS: $METRIC_TYPE; $($REMAINING)*);
};
($APP_METRICS:ident : $METRIC_TYPE:ty; $(#[$attr:meta])* @Counter $METRIC_ID:ident : $METRIC_NAME:expr; $($REMAINING:tt)*) => {
lazy_static! { $(#[$attr])* static ref $METRIC_ID: AppCounter<$METRIC_TYPE> = $APP_METRICS.counter($METRIC_NAME); }
($APP_METRICS:ident : $METRIC_TYPE:ty;
$(#[$attr:meta])* @Counter $METRIC_ID:ident : $METRIC_NAME:expr; $($REMAINING:tt)*) => {
lazy_static! { $(#[$attr])* static ref $METRIC_ID:
AppCounter<$METRIC_TYPE> = $APP_METRICS.counter($METRIC_NAME); }
__metrics_block!($APP_METRICS: $METRIC_TYPE; $($REMAINING)*);
};
($APP_METRICS:ident : $METRIC_TYPE:ty; $(#[$attr:meta])* pub @Marker $METRIC_ID:ident : $METRIC_NAME:expr; $($REMAINING:tt)*) => {
lazy_static! { $(#[$attr])* pub static ref $METRIC_ID: AppMarker<$METRIC_TYPE> = $APP_METRICS.marker($METRIC_NAME); }
($APP_METRICS:ident : $METRIC_TYPE:ty;
$(#[$attr:meta])* pub @Marker $METRIC_ID:ident : $METRIC_NAME:expr; $($REMAINING:tt)*) => {
lazy_static! { $(#[$attr])* pub static ref $METRIC_ID:
AppMarker<$METRIC_TYPE> = $APP_METRICS.marker($METRIC_NAME); }
__metrics_block!($APP_METRICS: $METRIC_TYPE; $($REMAINING)*);
};
($APP_METRICS:ident : $METRIC_TYPE:ty; $(#[$attr:meta])* @Marker $METRIC_ID:ident : $METRIC_NAME:expr; $($REMAINING:tt)*) => {
lazy_static! { $(#[$attr])* static ref $METRIC_ID: AppMarker<$METRIC_TYPE> = $APP_METRICS.marker($METRIC_NAME); }
($APP_METRICS:ident : $METRIC_TYPE:ty;
$(#[$attr:meta])* @Marker $METRIC_ID:ident : $METRIC_NAME:expr; $($REMAINING:tt)*) => {
lazy_static! { $(#[$attr])* static ref $METRIC_ID:
AppMarker<$METRIC_TYPE> = $APP_METRICS.marker($METRIC_NAME); }
__metrics_block!($APP_METRICS: $METRIC_TYPE; $($REMAINING)*);
};
($APP_METRICS:ident : $METRIC_TYPE:ty; $(#[$attr:meta])* pub @Gauge $METRIC_ID:ident : $METRIC_NAME:expr; $($REMAINING:tt)*) => {
lazy_static! { $(#[$attr])* pub static ref $METRIC_ID: AppGauge<$METRIC_TYPE> = $APP_METRICS.gauge($METRIC_NAME); }
($APP_METRICS:ident : $METRIC_TYPE:ty;
$(#[$attr:meta])* pub @Gauge $METRIC_ID:ident : $METRIC_NAME:expr; $($REMAINING:tt)*) => {
lazy_static! { $(#[$attr])* pub static ref $METRIC_ID:
AppGauge<$METRIC_TYPE> = $APP_METRICS.gauge($METRIC_NAME); }
__metrics_block!($APP_METRICS: $METRIC_TYPE; $($REMAINING)*);
};
($APP_METRICS:ident : $METRIC_TYPE:ty; $(#[$attr:meta])* @Gauge $METRIC_ID:ident : $METRIC_NAME:expr; $($REMAINING:tt)*) => {
lazy_static! { $(#[$attr])* static ref $METRIC_ID: AppGauge<$METRIC_TYPE> = $APP_METRICS.gauge($METRIC_NAME); }
($APP_METRICS:ident : $METRIC_TYPE:ty;
$(#[$attr:meta])* @Gauge $METRIC_ID:ident : $METRIC_NAME:expr; $($REMAINING:tt)*) => {
lazy_static! { $(#[$attr])* static ref $METRIC_ID:
AppGauge<$METRIC_TYPE> = $APP_METRICS.gauge($METRIC_NAME); }
__metrics_block!($APP_METRICS: $METRIC_TYPE; $($REMAINING)*);
};
($APP_METRICS:ident : $METRIC_TYPE:ty; $(#[$attr:meta])* pub @Timer $METRIC_ID:ident : $METRIC_NAME:expr; $($REMAINING:tt)*) => {
lazy_static! { $(#[$attr])* pub static ref $METRIC_ID: AppTimer<$METRIC_TYPE> = $APP_METRICS.timer($METRIC_NAME); }
($APP_METRICS:ident : $METRIC_TYPE:ty;
$(#[$attr:meta])* pub @Timer $METRIC_ID:ident : $METRIC_NAME:expr; $($REMAINING:tt)*) => {
lazy_static! { $(#[$attr])* pub static ref $METRIC_ID:
AppTimer<$METRIC_TYPE> = $APP_METRICS.timer($METRIC_NAME); }
__metrics_block!($APP_METRICS: $METRIC_TYPE; $($REMAINING)*);
};
($APP_METRICS:ident : $METRIC_TYPE:ty; $(#[$attr:meta])* @Timer $METRIC_ID:ident : $METRIC_NAME:expr; $($REMAINING:tt)*) => {
lazy_static! { $(#[$attr])* static ref $METRIC_ID: AppTimer<$METRIC_TYPE> = $APP_METRICS.timer($METRIC_NAME); }
($APP_METRICS:ident : $METRIC_TYPE:ty;
$(#[$attr:meta])* @Timer $METRIC_ID:ident : $METRIC_NAME:expr; $($REMAINING:tt)*) => {
lazy_static! { $(#[$attr])* static ref $METRIC_ID:
AppTimer<$METRIC_TYPE> = $APP_METRICS.timer($METRIC_NAME); }
__metrics_block!($APP_METRICS: $METRIC_TYPE; $($REMAINING)*);
};
($METRIC_ID:ident : $METRIC_TYPE:ty;) => ()
}
/// Define application-scoped markers.
#[macro_export]
#[deprecated]
macro_rules! marker {
($type_param: ty, $app_metrics: expr, { $($metric_id: ident: $metric_name: expr),* $(,)* } ) => {
lazy_static! { $(pub static ref $metric_id: AppMarker<$type_param> = $app_metrics.marker( $metric_name );)* }
macro_rules! app_marker {
(<$type_param: ty> $app_metrics: expr =>
{ $($metric_id: ident: $metric_name: expr),* $(,)* } ) => {
lazy_static! { $(pub static ref $metric_id:
AppMarker<$type_param> = $app_metrics.marker( $metric_name );)* }
};
}
/// Define application-scoped counters.
#[macro_export]
#[deprecated]
macro_rules! counter {
($type_param: ty, $app_metrics: expr, { $($metric_id: ident: $metric_name: expr),* $(,)* } ) => {
lazy_static! { $(pub static ref $metric_id: AppCounter<$type_param> = $app_metrics.counter( $metric_name );)* }
macro_rules! app_counter {
(<$type_param: ty> $app_metrics: expr =>
{ $($metric_id: ident: $metric_name: expr),* $(,)* } ) => {
lazy_static! { $(pub static ref $metric_id:
AppCounter<$type_param> = $app_metrics.counter( $metric_name );)* }
};
}
/// Define application-scoped gauges.
#[macro_export]
#[deprecated]
macro_rules! gauge {
($type_param: ty, $app_metrics: expr, { $($metric_id: ident: $metric_name: expr),* $(,)* } ) => {
lazy_static! { $(pub static ref $metric_id: AppGauge<$type_param> = $app_metrics.gauge( $metric_name );)* }
macro_rules! app_gauge {
(<$type_param: ty> $app_metrics: expr =>
{ $($metric_id: ident: $metric_name: expr),* $(,)* } ) => {
lazy_static! { $(pub static ref $metric_id:
AppGauge<$type_param> = $app_metrics.gauge( $metric_name );)* }
};
}
/// Define application-scoped timers.
#[macro_export]
#[deprecated]
macro_rules! timer {
($type_param: ty, $app_metrics: expr, { $($metric_id: ident: $metric_name: expr),* $(,)* } ) => {
lazy_static! { $(pub static ref $metric_id: AppTimer<$type_param> = $app_metrics.timer( $metric_name );)* }
macro_rules! app_timer {
(<$type_param: ty> $app_metrics: expr =>
{ $($metric_id: ident: $metric_name: expr),* $(,)* } ) => {
lazy_static! { $(pub static ref $metric_id:
AppTimer<$type_param> = $app_metrics.timer( $metric_name );)* }
};
}
///// Define delegated metrics.
//#[macro_export]
//macro_rules! delegated_metrics {
// // Public delegation point
// ($(#[$attr:meta])* pub $METRIC_ID:ident = $e:expr;) => {
// lazy_static! { $(#[$attr])* pub static ref $METRIC_ID: AppMetrics<Delegate> = $e.into(); }
// };
// // Local delegation point
// ($(#[$attr:meta])* $METRIC_ID:ident = $e:expr;) => {
// lazy_static! { $(#[$attr])* pub static ref $METRIC_ID: AppMetrics<Delegate> = $e.into(); }
// };
//
//
// // Public delegation point and some metrics
// ($(#[$attr:meta])* pub $METRIC_ID:ident = $e:expr => {$($REMAINING:tt)+}) => {
// lazy_static! { $(#[$attr])* pub static ref $METRIC_ID: AppMetrics<Delegate> = $e.into(); }
// __metrics_block!($METRIC_ID: Delegate ; $($REMAINING)*);
// };
// // Local delegation point and some metrics
// ($(#[$attr:meta])* $METRIC_ID:ident = $e:expr => {$($REMAINING:tt)+}) => {
// lazy_static! { $(#[$attr])* pub static ref $METRIC_ID: AppMetrics<Delegate> = $e.into(); }
// __metrics_block!($METRIC_ID: Delegate ; $($REMAINING)*);
// };
// // Anonymous delegation point and some metrics
// ($(#[$attr:meta])* $e:expr => {$($REMAINING:tt)+}) => {
// lazy_static! { $(#[$attr])* static ref __LOCAL_METRICS: AppMetrics<Delegate> = $e.into(); }
// __metrics_block!(__LOCAL_METRICS: Delegate ; $($REMAINING)*);
// };
//}
//
///// Define delegated metrics.
//#[macro_export]
//macro_rules! aggregated_metrics {
// // Public delegation point
// ($(#[$attr:meta])* pub $METRIC_ID:ident = $e:expr;) => {
// lazy_static! { $(#[$attr])* pub static ref $METRIC_ID: AppMetrics<Aggregate> = $e.into(); }
// };
// // Local delegation point
// ($(#[$attr:meta])* $METRIC_ID:ident = $e:expr;) => {
// lazy_static! { $(#[$attr])* pub static ref $METRIC_ID: AppMetrics<Aggregate> = $e.into(); }
// };
//
//
// // Public delegation point and some metrics
// ($(#[$attr:meta])* pub $METRIC_ID:ident = $e:expr => {$($REMAINING:tt)+}) => {
// lazy_static! { $(#[$attr])* pub static ref $METRIC_ID: AppMetrics<Aggregate> = $e.into(); }
// __metrics_block!($METRIC_ID: Aggregate ; $($REMAINING)*);
// };
// // Local delegation point and some metrics
// ($(#[$attr:meta])* $METRIC_ID:ident = $e:expr => {$($REMAINING:tt)+}) => {
// lazy_static! { $(#[$attr])* pub static ref $METRIC_ID: AppMetrics<Aggregate> = $e.into(); }
// __metrics_block!($METRIC_ID: Aggregate ; $($REMAINING)*);
// };
// // Anonymous delegation point and some metrics
// ($(#[$attr:meta])* $e:expr => {$($REMAINING:tt)+}) => {
// lazy_static! { $(#[$attr])* static ref __LOCAL_METRICS: AppMetrics<Aggregate> = $e.into(); }
// __metrics_block!(__LOCAL_METRICS: Aggregate ; $($REMAINING)*);
// };
//}
#[cfg(test)]
mod test_app {
use self_metrics::*;
app_metrics!(TEST_METRICS <Aggregate> = DIPSTICK_METRICS.with_prefix("test_prefix"));
app_metrics!(<Aggregate> TEST_METRICS = DIPSTICK_METRICS.with_prefix("test_prefix"););
app_marker!(Aggregate, TEST_METRICS, {
app_marker!(<Aggregate> TEST_METRICS => {
M1: "failed",
M2: "success",
});
app_counter!(Aggregate, TEST_METRICS, {
app_counter!(<Aggregate> TEST_METRICS => {
C1: "failed",
C2: "success",
});
app_gauge!(Aggregate, TEST_METRICS, {
app_gauge!(<Aggregate> TEST_METRICS => {
G1: "failed",
G2: "success",
});
app_timer!(Aggregate, TEST_METRICS, {
app_timer!(<Aggregate> TEST_METRICS => {
T1: "failed",
T2: "success",
});
#[test]
fn call_macro_defined_metrics() {
M1.mark();
@ -286,4 +230,3 @@ mod test_app {
T2.interval_us(2);
}
}

View File

@ -20,7 +20,7 @@ where
move |kind, name, rate| {
(
combo.0.define_metric(kind, name, rate),
combo.1.define_metric(kind, &name, rate),
combo.1.define_metric(kind, name, rate),
)
},
move |buffered| {
@ -44,9 +44,9 @@ where
}
impl<M1, M2> From<(ScopeMetrics<M1>, ScopeMetrics<M2>)> for AppMetrics<(M1, M2)>
where
M1: 'static + Clone + Send + Sync,
M2: 'static + Clone + Send + Sync,
where
M1: 'static + Clone + Send + Sync,
M2: 'static + Clone + Send + Sync,
{
fn from(combo: (ScopeMetrics<M1>, ScopeMetrics<M2>)) -> AppMetrics<(M1, M2)> {
let chain: ScopeMetrics<(M1, M2)> = combo.into();
@ -84,7 +84,7 @@ where
for (i, scope) in scopes.iter().enumerate() {
scope.write(&metric[i], value)
}
},
}
ScopeCmd::Flush => for scope in &scopes {
scope.flush()
},
@ -95,11 +95,11 @@ where
}
impl<'a, M> From<&'a [ScopeMetrics<M>]> for AppMetrics<Vec<M>>
where
M: 'static + Clone + Send + Sync,
where
M: 'static + Clone + Send + Sync,
{
fn from(chains: &'a [ScopeMetrics<M>]) -> AppMetrics<Vec<M>> {
let chain: ScopeMetrics<Vec<M>> = chains.into();
app_metrics(chain)
}
}
}

View File

@ -7,7 +7,7 @@ const DEFAULT_SEPARATOR: &'static str = ".";
/// A list of parts of a metric's name.
#[derive(Debug, Clone)]
pub struct Namespace (Vec<String>);
pub struct Namespace(Vec<String>);
impl Namespace {
/// Make this namespace a subspace of the parent.
@ -45,24 +45,23 @@ where
Self: Sized,
{
/// Insert prefix in newly defined metrics.
// #[deprecated(since = "0.6.3", note = "Use `with_name` instead.")]
// #[deprecated(since = "0.6.3", note = "Use `with_name` instead.")]
fn with_prefix<AS: AsRef<str>>(&self, prefix: AS) -> Self {
self.with_namespace(&[prefix.as_ref()])
}
/// Join namespace and prepend in newly defined metrics.
// #[deprecated(since = "0.6.3", note = "Use `with_name` instead.")]
// #[deprecated(since = "0.6.3", note = "Use `with_name` instead.")]
fn with_namespace(&self, names: &[&str]) -> Self {
self.with_name(names)
}
/// Join namespace and prepend in newly defined metrics.
fn with_name<IN: Into<Namespace>>(&self, names: IN) -> Self;
}
/// Add a namespace decorator to a metric definition function.
pub fn add_namespace<M: 'static>(names: &Namespace, next: DefineMetricFn<M>) -> DefineMetricFn<M> {
pub fn add_namespace<M: 'static>(names: &Namespace, next: DefineMetricFn<M>) -> DefineMetricFn<M> {
let nspace = names.join(DEFAULT_SEPARATOR);
Arc::new(move |kind, name, rate| {
let name = [nspace.as_ref(), name].join(DEFAULT_SEPARATOR);

View File

@ -20,7 +20,9 @@ pub fn to_stdout() -> ScopeMetrics<String> {
control_scope(move |cmd| {
let mut buf = buf.write().expect("Locking stdout buffer");
match cmd {
ScopeCmd::Write(metric, value) => buf.push_str(format!("{}: {}\n", metric, value).as_ref()),
ScopeCmd::Write(metric, value) => {
buf.push_str(format!("{}: {}\n", metric, value).as_ref())
}
ScopeCmd::Flush => {
println!("{}", buf);
buf.clear();
@ -49,7 +51,9 @@ pub fn to_log() -> ScopeMetrics<String> {
control_scope(move |cmd| {
let mut buf = buf.write().expect("Locking string buffer");
match cmd {
ScopeCmd::Write(metric, value) => buf.push_str(format!("{}: {}\n", metric, value).as_ref()),
ScopeCmd::Write(metric, value) => {
buf.push_str(format!("{}: {}\n", metric, value).as_ref())
}
ScopeCmd::Flush => {
info!("{}", buf);
buf.clear();

View File

@ -4,7 +4,7 @@
//! ```
//! use dipstick::*;
//!
//! let (sink, source) = aggregate();
//! let app_metrics = aggregate(summary, to_stdout());
//! publish(&source, &log("aggregated"), publish::all_stats);
//! ```
//!
@ -13,8 +13,8 @@
//! use dipstick::*;
//! use std::time::Duration;
//!
//! let (sink, source) = aggregate();
//! let job = publish_every(Duration::from_millis(100), &source, &log("aggregated"), publish::all_stats);
//! let (sink, source) = aggregate(summary, to_stdout());
//! let job = publish_every(Duration::from_millis(100), &source, &log("aggregated"), all_stats);
//! // publish will go on until cancelled
//! job.cancel();
//! ```
@ -38,7 +38,8 @@ pub trait Publish: Send + Sync + Debug {
#[derive(Derivative, Clone)]
#[derivative(Debug)]
pub struct Publisher<E, M> {
#[derivative(Debug = "ignore")] statistics: Box<E>,
#[derivative(Debug = "ignore")]
statistics: Box<E>,
target_chain: ScopeMetrics<M>,
}

View File

@ -36,15 +36,13 @@ impl<M: Send + Sync + 'static + Clone> WithSamplingRate for ScopeMetrics<M> {
}),
Arc::new(move |buffered| {
let next_scope = scope_fn(buffered);
control_scope(move |cmd| {
match cmd {
ScopeCmd::Write(metric, value) => {
if pcg32::accept_sample(int_sampling_rate) {
next_scope.write(metric, value)
}
},
ScopeCmd::Flush => next_scope.flush()
control_scope(move |cmd| match cmd {
ScopeCmd::Write(metric, value) => {
if pcg32::accept_sample(int_sampling_rate) {
next_scope.write(metric, value)
}
}
ScopeCmd::Flush => next_scope.flush(),
})
}),
)

View File

@ -9,15 +9,16 @@ use std::sync::Arc;
use cache::*;
use namespace::*;
/// A pair of functions composing a twin "chain of command".
/// This is the building block for the metrics backend.
#[derive(Derivative, Clone)]
#[derivative(Debug)]
pub struct ScopeMetrics<M> {
#[derivative(Debug = "ignore")] define_metric_fn: DefineMetricFn<M>,
#[derivative(Debug = "ignore")]
define_metric_fn: DefineMetricFn<M>,
#[derivative(Debug = "ignore")] scope_metric_fn: OpenScopeFn<M>,
#[derivative(Debug = "ignore")]
scope_metric_fn: OpenScopeFn<M>,
}
impl<M> ScopeMetrics<M> {
@ -64,9 +65,9 @@ impl<M> ScopeMetrics<M> {
impl<M: Send + Sync + Clone + 'static> ScopeMetrics<M> {
/// Create a new metric chain with the provided metric definition and scope creation functions.
pub fn new<MF, WF>(make_metric: MF, make_scope: WF) -> Self
where
MF: Fn(Kind, &str, Rate) -> M + Send + Sync + 'static,
WF: Fn(bool) -> ControlScopeFn<M> + Send + Sync + 'static,
where
MF: Fn(Kind, &str, Rate) -> M + Send + Sync + 'static,
WF: Fn(bool) -> ControlScopeFn<M> + Send + Sync + 'static,
{
ScopeMetrics {
// capture the provided closures in Arc to provide cheap clones
@ -101,9 +102,9 @@ impl<M: Send + Sync + Clone + 'static> ScopeMetrics<M> {
/// Intercept both metric definition and scope creation, possibly changing the metric type.
pub fn mod_both<MF, N>(&self, mod_fn: MF) -> ScopeMetrics<N>
where
MF: Fn(DefineMetricFn<M>, OpenScopeFn<M>) -> (DefineMetricFn<N>, OpenScopeFn<N>),
N: Clone + Send + Sync,
where
MF: Fn(DefineMetricFn<M>, OpenScopeFn<M>) -> (DefineMetricFn<N>, OpenScopeFn<N>),
N: Clone + Send + Sync,
{
let (metric_fn, scope_fn) =
mod_fn(self.define_metric_fn.clone(), self.scope_metric_fn.clone());
@ -115,8 +116,8 @@ impl<M: Send + Sync + Clone + 'static> ScopeMetrics<M> {
/// Intercept scope creation.
pub fn mod_scope<MF>(&self, mod_fn: MF) -> Self
where
MF: Fn(OpenScopeFn<M>) -> OpenScopeFn<M>,
where
MF: Fn(OpenScopeFn<M>) -> OpenScopeFn<M>,
{
ScopeMetrics {
define_metric_fn: self.define_metric_fn.clone(),
@ -140,7 +141,6 @@ impl<M: Send + Sync + Clone + 'static> WithCache for ScopeMetrics<M> {
}
}
impl<M: Send + Sync + Clone + 'static> WithNamespace for ScopeMetrics<M> {
fn with_name<IN: Into<Namespace>>(&self, names: IN) -> Self {
let ref ninto = names.into();
@ -179,8 +179,8 @@ impl<M> ScopeCounter<M> {
/// Record a value count.
#[inline]
pub fn count<V>(&self, scope: &mut ControlScopeFn<M>, count: V)
where
V: ToPrimitive,
where
V: ToPrimitive,
{
scope.write(&self.metric, count.to_u64().unwrap());
}
@ -197,8 +197,8 @@ impl<M: Clone> ScopeGauge<M> {
/// Record a value point for this gauge.
#[inline]
pub fn value<V>(&self, scope: &mut ControlScopeFn<M>, value: V)
where
V: ToPrimitive,
where
V: ToPrimitive,
{
scope.write(&self.metric, value.to_u64().unwrap());
}
@ -221,8 +221,8 @@ impl<M: Clone> ScopeTimer<M> {
/// Can be used in place of start()/stop() if an external time interval source is used
#[inline]
pub fn interval_us<V>(&self, scope: &mut ControlScopeFn<M>, interval_us: V) -> V
where
V: ToPrimitive,
where
V: ToPrimitive,
{
scope.write(&self.metric, interval_us.to_u64().unwrap());
interval_us
@ -252,8 +252,8 @@ impl<M: Clone> ScopeTimer<M> {
/// Record the time taken to execute the provided closure
#[inline]
pub fn time<F, R>(&self, scope: &mut ControlScopeFn<M>, operations: F) -> R
where
F: FnOnce() -> R,
where
F: FnOnce() -> R,
{
let start_time = self.start();
let value: R = operations();

View File

@ -18,7 +18,7 @@ lazy_static! {
/// Application metrics are collected to the aggregator
app_metrics!(Aggregate, DIPSTICK_METRICS = build_self_metrics(););
app_metrics!(<Aggregate> DIPSTICK_METRICS = build_self_metrics(););
fn build_aggregator() -> Aggregator {
// TODO make publishable
@ -35,4 +35,3 @@ fn build_self_metrics() -> AppMetrics<Aggregate> {
let am: AppMetrics<Aggregate> = mug.clone().into();
am.with_prefix("dipstick")
}

View File

@ -10,10 +10,11 @@ use std::sync::{Arc, RwLock};
pub use std::net::ToSocketAddrs;
mod_metrics! {
Aggregate, DIPSTICK_METRICS.with_prefix("statsd");
@Marker SEND_ERR: "send_failed";
@Counter SENT_BYTES: "sent_bytes";
app_metrics! {
<Aggregate> DIPSTICK_METRICS.with_prefix("statsd") => {
@Marker SEND_ERR: "send_failed";
@Counter SENT_BYTES: "sent_bytes";
}
}
/// Send metrics to a statsd server at the address and port provided.

View File

@ -1 +1 @@
include!(concat!(env!("OUT_DIR"), "/skeptic-tests.rs"));
include!(concat!(env!("OUT_DIR"), "/skeptic-tests.rs"));