AppMetrics -> Metrics, fix send_metrics()

This commit is contained in:
Francis Lalonde 2018-03-26 16:44:04 -04:00
parent 0143cea743
commit 2681c7b342
29 changed files with 389 additions and 273 deletions

View File

@ -38,7 +38,7 @@ dipstick = "0.6.5"
Then add it to your code:
```rust,skt-fail,no_run
let metrics = app_metrics(to_graphite("host.com:2003")?);
let metrics = metrics(to_graphite("host.com:2003")?);
let counter = metrics.counter("my_counter");
counter.count(3);
```
@ -46,7 +46,7 @@ counter.count(3);
Send metrics to multiple outputs:
```rust,skt-fail,no_run
let _app_metrics = app_metrics((
let _app_metrics = metrics((
to_stdout(),
to_statsd("localhost:8125")?.with_namespace(&["my", "app"])
));
@ -57,7 +57,7 @@ Aggregate metrics and schedule to be periodical publication in the background:
```rust,skt-run
use std::time::Duration;
let app_metrics = app_metrics(aggregate(all_stats, to_stdout()));
let app_metrics = metrics(aggregate(all_stats, to_stdout()));
app_metrics.flush_every(Duration::from_secs(3));
```
@ -68,7 +68,7 @@ Published statistics can be selected with presets such as `all_stats` (see previ
For more control over published statistics, provide your own strategy:
```rust,skt-run
app_metrics(aggregate(
metrics(aggregate(
|_kind, name, score|
match score {
ScoreType::Count(count) =>
@ -80,14 +80,14 @@ app_metrics(aggregate(
Apply statistical sampling to metrics:
```rust,skt-fail
let _app_metrics = app_metrics(to_statsd("server:8125")?.with_sampling_rate(0.01));
let _app_metrics = metrics(to_statsd("server:8125")?.with_sampling_rate(0.01));
```
A fast random algorithm is used to pick samples.
Outputs can use sample rate to expand or format published data.
Metrics can be recorded asynchronously:
```rust,skt-run
let _app_metrics = app_metrics(to_stdout().with_async_queue(64));
let _app_metrics = metrics(to_stdout().with_async_queue(64));
```
The async queue uses a Rust channel and a standalone thread.
The current behavior is to block when full.
@ -98,12 +98,12 @@ For speed and easier maintenance, metrics are usually defined statically:
#[macro_use] extern crate lazy_static;
use dipstick::*;
app_metrics!("my_app" => {
metrics!("my_app" => {
@Counter COUNTER_A: "counter_a";
});
fn main() {
send_app_metrics(to_stdout());
send_metrics(to_stdout());
COUNTER_A.count(11);
}
```
@ -113,14 +113,14 @@ Metric definition macros are just `lazy_static!` wrappers.
Where necessary, metrics can be defined _ad-hoc_:
```rust,skt-run
let user_name = "john_day";
let app_metrics = app_metrics(to_log()).with_cache(512);
let app_metrics = metrics(to_log()).with_cache(512);
app_metrics.gauge(format!("gauge_for_user_{}", user_name)).value(44);
```
Defining a cache is optional but will speed up re-definition of common ad-hoc metrics.
Timers can be used multiple ways:
```rust,skt-run
let app_metrics = app_metrics(to_stdout());
let app_metrics = metrics(to_stdout());
let timer = app_metrics.timer("my_timer");
time!(timer, {/* slow code here */} );
timer.time(|| {/* slow code here */} );
@ -134,7 +134,7 @@ timer.interval_us(123_456);
Related metrics can share a namespace:
```rust,skt-run
let app_metrics = app_metrics(to_stdout());
let app_metrics = metrics(to_stdout());
let db_metrics = app_metrics.with_prefix("database");
let _db_timer = db_metrics.timer("db_timer");
let _db_counter = db_metrics.counter("db_counter");

View File

@ -9,7 +9,7 @@ use dipstick::*;
fn main() {
let to_aggregate = aggregate(all_stats, to_stdout());
let app_metrics = app_metrics(to_aggregate);
let app_metrics = metrics(to_aggregate);
app_metrics.flush_every(Duration::from_secs(3));

View File

@ -8,7 +8,7 @@ use std::time::Duration;
use dipstick::*;
fn main() {
let metrics = app_metrics(to_stdout().with_async_queue(0));
let metrics = metrics(to_stdout().with_async_queue(0));
let counter = metrics.counter("counter_a");
let timer = metrics.timer("timer_b");

View File

@ -9,7 +9,7 @@ use dipstick::*;
fn main() {
// for this demo, print metric values to the console
let app_metrics = app_metrics(to_stdout());
let app_metrics = metrics(to_stdout());
// metrics can be predefined by type and name
let counter = app_metrics.counter("counter_a");

View File

@ -37,7 +37,7 @@ fn main() {
// send application metrics to aggregator
let to_aggregate = aggregate(custom_statistics, to_stdout());
let app_metrics = app_metrics(to_aggregate);
let app_metrics = metrics(to_aggregate);
// schedule aggregated metrics to be printed every 3 seconds
app_metrics.flush_every(Duration::from_secs(3));

View File

@ -9,7 +9,7 @@ use std::time::Duration;
fn main() {
// badlog::init(Some("info"));
let metrics = app_metrics(
let metrics = metrics(
to_graphite("localhost:2003")
.expect("Connecting")
.with_namespace(&["my", "app"][..]),

View File

@ -8,7 +8,7 @@ use dipstick::*;
use std::time::Duration;
// undeclared root (un-prefixed) metrics
app_metrics!( => {
metrics!( => {
// create counter "some_counter"
pub @Counter ROOT_COUNTER: "root_counter";
// create counter "root_counter"
@ -18,7 +18,7 @@ app_metrics!( => {
});
// public source
app_metrics!(pub PUB_METRICS ="pub_lib_prefix" => {
metrics!(pub PUB_METRICS ="pub_lib_prefix" => {
// create counter "lib_prefix.some_counter"
pub @Counter PUB_COUNTER: "some_counter";
});
@ -30,19 +30,19 @@ app_metrics!(pub PUB_METRICS ="pub_lib_prefix" => {
//});
// declare mod source
app_metrics!(LIB_METRICS ="mod_lib_prefix" => {
metrics!(LIB_METRICS ="mod_lib_prefix" => {
// create counter "mod_lib_prefix.some_counter"
pub @Counter SOME_COUNTER: "some_counter";
});
// reuse declared source
app_metrics!(LIB_METRICS => {
metrics!(LIB_METRICS => {
// create counter "mod_lib_prefix.another_counter"
@Counter ANOTHER_COUNTER: "another_counter";
});
fn main() {
send_app_metrics(to_stdout());
send_metrics(to_stdout());
loop {
ROOT_COUNTER.count(123);

View File

@ -0,0 +1,37 @@
//! A sample application sending ad-hoc counter values both to statsd _and_ to stdout.
extern crate dipstick;
#[macro_use] extern crate lazy_static;
use dipstick::*;
use std::time::Duration;
#[ignore(deprecated)]
app_metrics!((Statsd, String), DIFFERENT_TYPES = (
// combine outputs of different types by using a tuple
to_statsd("localhost:8125").expect("Connecting"),
to_stdout(),
));
#[ignore(deprecated)]
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),
]);
#[ignore(deprecated)]
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);
MUTANT_CHILD.gauge("gauge_z").value(34534);
std::thread::sleep(Duration::from_millis(40));
}
}

View File

@ -7,20 +7,20 @@ extern crate lazy_static;
use dipstick::*;
use std::time::Duration;
app_metrics!(<(Statsd, String)> DIFFERENT_TYPES = (
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 = [
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"););
metrics!(<Vec<String>> MUTANT_CHILD = SAME_TYPE.with_prefix("super").with_prefix("duper"););
fn main() {
loop {

View File

@ -7,14 +7,14 @@ use std::time::Duration;
fn main() {
// note that this can also be done using the app_metrics! macro
let different_type_metrics = app_metrics((
let different_type_metrics = metrics((
// combine metrics of different types in a tuple
to_statsd("localhost:8125").expect("Connecting"),
to_stdout(),
));
// note that this can also be done using the app_metrics! macro
let same_type_metrics = app_metrics(
let same_type_metrics = metrics(
&[
// use slices to combine multiple metrics of the same type
to_stdout().with_name("yeah"),

View File

@ -7,7 +7,7 @@ use dipstick::*;
fn main() {
// print only 1 out of every 10000 metrics recorded
let app_metrics: AppMetrics<String> = app_metrics(to_stdout().with_sampling_rate(0.0001));
let app_metrics: Metrics<String> = metrics(to_stdout().with_sampling_rate(0.0001));
let marker = app_metrics.marker("marker_a");

View File

@ -1,27 +0,0 @@
//! Use statically defined app metrics & backend.
//! This pattern is likely to emerge
extern crate dipstick;
#[macro_use]
extern crate lazy_static;
/// The `metric` module should be shared across the crate and contain metrics from all modules.
/// Conventions are easier to uphold and document when all metrics are defined in the same place.
pub mod metric {
use dipstick::*;
// Unfortunately, Rust's `static`s assignments still force us to explicitly declare types.
// This makes it uglier than it should be when working with generics...
// 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");
}
}
fn main() {
// The resulting application code is lean and clean
metric::COUNTER_A.count(11);
metric::TIMER_B.interval_us(654654);
}

View File

@ -9,7 +9,7 @@ use dipstick::*;
fn main() {
let to_aggregate = aggregate(summary, to_stdout());
let app_metrics = app_metrics(to_aggregate);
let app_metrics = metrics(to_aggregate);
app_metrics.flush_every(Duration::from_secs(3));

View File

@ -1,8 +1,8 @@
//! Maintain aggregated metrics for deferred reporting,
//!
use core::*;
use local_metrics::*;
use app_metrics::*;
use context::*;
use metrics::*;
use namespace::*;
use output::to_void;
@ -22,7 +22,7 @@ use std::sync::{Arc, RwLock};
/// metrics.marker("my_event").mark();
/// metrics.marker("my_event").mark();
/// ```
pub fn aggregate<E, M>(stat_fn: E, to_chain: LocalMetrics<M>) -> Aggregator
pub fn aggregate<E, M>(stat_fn: E, to_chain: MetricContext<M>) -> Aggregator
where
E: Fn(Kind, &str, ScoreType) -> Option<(Kind, Vec<&str>, Value)> + Send + Sync + 'static,
M: Clone + Send + Sync + Debug + 'static,
@ -33,10 +33,10 @@ where
}
}
impl From<Aggregator> for AppMetrics<Aggregate> {
fn from(agg: Aggregator) -> AppMetrics<Aggregate> {
impl From<Aggregator> for Metrics<Aggregate> {
fn from(agg: Aggregator) -> Metrics<Aggregate> {
let agg_1 = agg.clone();
AppMetrics::new(
Metrics::new(
Arc::new(move |kind, name, rate| agg.define_metric(kind, name, rate)),
control_scope(move |cmd| match cmd {
ScopeCmd::Write(metric, value) => {
@ -49,9 +49,9 @@ impl From<Aggregator> for AppMetrics<Aggregate> {
}
}
impl From<&'static str> for AppMetrics<Aggregate> {
fn from(prefix: &'static str) -> AppMetrics<Aggregate> {
let app_metrics: AppMetrics<Aggregate> = aggregate(summary, to_void()).into();
impl From<&'static str> for Metrics<Aggregate> {
fn from(prefix: &'static str) -> Metrics<Aggregate> {
let app_metrics: Metrics<Aggregate> = aggregate(summary, to_void()).into();
app_metrics.with_prefix(prefix)
}
}
@ -120,28 +120,28 @@ mod bench {
#[bench]
fn aggregate_marker(b: &mut test::Bencher) {
let sink: AppMetrics<Aggregate> = aggregate(summary, to_void()).into();
let sink: Metrics<Aggregate> = aggregate(summary, to_void()).into();
let metric = sink.define_metric(Marker, "event_a", 1.0);
b.iter(|| test::black_box(sink.write(&metric, 1)));
}
#[bench]
fn aggregate_counter(b: &mut test::Bencher) {
let sink: AppMetrics<Aggregate> = aggregate(summary, to_void()).into();
let sink: Metrics<Aggregate> = aggregate(summary, to_void()).into();
let metric = sink.define_metric(Counter, "count_a", 1.0);
b.iter(|| test::black_box(sink.write(&metric, 1)));
}
#[bench]
fn reset_marker(b: &mut test::Bencher) {
let sink: AppMetrics<Aggregate> = aggregate(summary, to_void()).into();
let sink: Metrics<Aggregate> = aggregate(summary, to_void()).into();
let metric = sink.define_metric(Marker, "marker_a", 1.0);
b.iter(|| test::black_box(metric.reset()));
}
#[bench]
fn reset_counter(b: &mut test::Bencher) {
let sink: AppMetrics<Aggregate> = aggregate(summary, to_void()).into();
let sink: Metrics<Aggregate> = aggregate(summary, to_void()).into();
let metric = sink.define_metric(Counter, "count_a", 1.0);
b.iter(|| test::black_box(metric.reset()));
}

View File

@ -3,14 +3,14 @@
//! If queue size is exceeded, calling code reverts to blocking.
//!
use core::*;
use local_metrics::*;
use context::*;
use self_metrics::*;
use std::sync::Arc;
use std::sync::mpsc;
use std::thread;
app_metrics!{
metrics!{
<Aggregate> DIPSTICK_METRICS.with_prefix("async_queue") => {
@Marker SEND_FAILED: "send_failed";
}
@ -25,7 +25,7 @@ where
fn with_async_queue(&self, queue_size: usize) -> Self;
}
impl<M: Send + Sync + Clone + 'static> WithAsyncQueue for LocalMetrics<M> {
impl<M: Send + Sync + Clone + 'static> WithAsyncQueue for MetricContext<M> {
fn with_async_queue(&self, queue_size: usize) -> Self {
self.mod_scope(|next| {
// setup channel
@ -49,7 +49,7 @@ impl<M: Send + Sync + Clone + 'static> WithAsyncQueue for LocalMetrics<M> {
Arc::new(move || {
// open next scope, make it Arc to move across queue
let next_scope: ControlScopeFn<M> = next();
let next_scope: WriteFn<M> = next();
let sender = sender.clone();
// forward any scope command through the channel
@ -78,10 +78,10 @@ impl<M: Send + Sync + Clone + 'static> WithAsyncQueue for LocalMetrics<M> {
/// Enqueue collected metrics for dispatch on background thread.
#[deprecated(since = "0.5.0", note = "Use `with_async_queue` instead.")]
pub fn async<M, IC>(queue_size: usize, chain: IC) -> LocalMetrics<M>
pub fn async<M, IC>(queue_size: usize, chain: IC) -> MetricContext<M>
where
M: Clone + Send + Sync + 'static,
IC: Into<LocalMetrics<M>>,
IC: Into<MetricContext<M>>,
{
let chain = chain.into();
chain.with_async_queue(queue_size)
@ -96,5 +96,5 @@ pub struct QueueCommand<M> {
cmd: Option<(M, Value)>,
/// The scope to write the metric to
#[derivative(Debug = "ignore")]
next_scope: ControlScopeFn<M>,
next_scope: WriteFn<M>,
}

View File

@ -1,7 +1,7 @@
//! Chain of command for unscoped metrics.
use core::*;
use app_metrics::AppMetrics;
use metrics::Metrics;
use std::sync::Arc;
@ -11,7 +11,7 @@ use namespace::*;
/// This is the building block for the metrics backend.
#[derive(Derivative, Clone)]
#[derivative(Debug)]
pub struct LocalMetrics<M> {
pub struct MetricContext<M> {
#[derivative(Debug = "ignore")]
define_metric_fn: DefineMetricFn<M>,
@ -19,7 +19,7 @@ pub struct LocalMetrics<M> {
scope_metric_fn: OpenScopeFn<M>,
}
impl<M> LocalMetrics<M> {
impl<M> MetricContext<M> {
/// Open a new metric scope.
/// Scope metrics allow an application to emit per-operation statistics,
/// For example, producing a per-request performance log.
@ -33,35 +33,35 @@ impl<M> LocalMetrics<M> {
/// let request_counter = scope_metrics.counter("scope_counter");
/// ```
///
pub fn open_scope(&self) -> AppMetrics<M> {
AppMetrics::new(self.define_metric_fn.clone(), (self.scope_metric_fn)())
pub fn open_scope(&self) -> Metrics<M> {
Metrics::new(self.define_metric_fn.clone(), (self.scope_metric_fn)())
}
}
/// Create a new metric chain with the provided metric definition and scope creation functions.
pub fn metrics_context<MF, WF, M>(make_metric: MF, make_scope: WF) -> LocalMetrics<M>
pub fn metrics_context<MF, WF, M>(make_metric: MF, make_scope: WF) -> MetricContext<M>
where
MF: Fn(Kind, &str, Rate) -> M + Send + Sync + 'static,
WF: Fn() -> ControlScopeFn<M> + Send + Sync + 'static,
WF: Fn() -> WriteFn<M> + Send + Sync + 'static,
{
LocalMetrics {
MetricContext {
define_metric_fn: Arc::new(make_metric),
scope_metric_fn: Arc::new(make_scope),
}
}
impl<M: Send + Sync + Clone + 'static> LocalMetrics<M> {
impl<M: Send + Sync + Clone + 'static> MetricContext<M> {
/// Intercept both metric definition and scope creation, possibly changing the metric type.
pub fn mod_both<MF, N>(&self, mod_fn: MF) -> LocalMetrics<N>
pub fn mod_both<MF, N>(&self, mod_fn: MF) -> MetricContext<N>
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());
LocalMetrics {
MetricContext {
define_metric_fn: metric_fn,
scope_metric_fn: scope_fn,
}
@ -72,7 +72,7 @@ impl<M: Send + Sync + Clone + 'static> LocalMetrics<M> {
where
MF: Fn(OpenScopeFn<M>) -> OpenScopeFn<M>,
{
LocalMetrics {
MetricContext {
define_metric_fn: self.define_metric_fn.clone(),
scope_metric_fn: mod_fn(self.scope_metric_fn.clone()),
}
@ -80,16 +80,16 @@ impl<M: Send + Sync + Clone + 'static> LocalMetrics<M> {
}
impl<M> From<LocalMetrics<M>> for AppMetrics<M> {
fn from(metrics: LocalMetrics<M>) -> AppMetrics<M> {
impl<M> From<MetricContext<M>> for Metrics<M> {
fn from(metrics: MetricContext<M>) -> Metrics<M> {
metrics.open_scope()
}
}
impl<M: Send + Sync + Clone + 'static> WithNamespace for LocalMetrics<M> {
impl<M: Send + Sync + Clone + 'static> WithNamespace for MetricContext<M> {
fn with_name<IN: Into<Namespace>>(&self, names: IN) -> Self {
let ref ninto = names.into();
LocalMetrics {
MetricContext {
define_metric_fn: add_namespace(ninto, self.define_metric_fn.clone()),
scope_metric_fn: self.scope_metric_fn.clone(),
}

View File

@ -63,10 +63,10 @@ pub enum Kind {
pub type DefineMetricFn<M> = Arc<Fn(Kind, &str, Rate) -> M + Send + Sync>;
/// A function trait that opens a new metric capture scope.
pub type OpenScopeFn<M> = Arc<Fn() -> ControlScopeFn<M> + Send + Sync>;
pub type OpenScopeFn<M> = Arc<Fn() -> WriteFn<M> + Send + Sync>;
/// A function trait that writes to or flushes a certain scope.
pub type ControlScopeFn<M> = Arc<InnerControlScopeFn<M>>;
pub type WriteFn<M> = Arc<InnerControlScopeFn<M>>;
/// Returns a callback function to send commands to the metric scope.
/// Writes can be performed by passing Some((&Metric, Value))
@ -98,7 +98,7 @@ 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>
pub fn control_scope<M, F>(scope_fn: F) -> WriteFn<M>
where
F: Fn(ScopeCmd<M>) + 'static,
{

View File

@ -1,7 +1,7 @@
//! Decouple metric definition from configuration with trait objects.
use core::*;
use app_metrics::*;
use metrics::*;
use namespace::*;
use registry;
@ -13,24 +13,24 @@ use atomic_refcell::*;
/// Create a new dispatch point for metrics.
/// All dispatch points are automatically entered in the dispatch registry.
pub fn app_delegate() -> AppSend {
let send = AppSend {
inner: Arc::new(RwLock::new(InnerAppSend {
pub fn delegate_metrics() -> MetricsSend {
let send = MetricsSend {
inner: Arc::new(RwLock::new(InnerMetricsSend {
metrics: HashMap::new(),
recv: registry::get_default_app_recv(),
recv: registry::get_default_metrics_recv(),
})),
};
registry::add_app_send(send.clone());
registry::add_metrics_send(send.clone());
send
}
/// Dynamic counterpart of a `Dispatcher`.
/// Adapter to AppMetrics<_> of unknown type.
pub trait AppRecv {
pub trait MetricsRecv {
/// Register a new metric.
/// Only one metric of a certain name will be defined.
/// Observer must return a MetricHandle that uniquely identifies the metric.
fn define_metric(&self, kind: Kind, name: &str, rate: Rate) -> Box<AppRecvMetric + Send + Sync>;
fn define_metric(&self, kind: Kind, name: &str, rate: Rate) -> Box<RecvMetric + Send + Sync>;
/// Flush the receiver's scope.
fn flush(&self);
@ -38,7 +38,7 @@ pub trait AppRecv {
/// Dynamic counterpart of the `DispatcherMetric`.
/// Adapter to a metric of unknown type.
pub trait AppRecvMetric {
pub trait RecvMetric {
/// Write metric value to a scope.
/// Observers only receive previously registered handles.
fn write(&self, value: Value);
@ -46,23 +46,23 @@ pub trait AppRecvMetric {
/// Shortcut name because `AppMetrics<Dispatch>`
/// looks better than `AppMetrics<Arc<DispatcherMetric>>`.
pub type Delegate = Arc<AppSendMetric>;
pub type Delegate = Arc<SendMetric>;
/// A dynamically dispatched metric.
#[derive(Derivative)]
#[derivative(Debug)]
pub struct AppSendMetric {
pub struct SendMetric {
kind: Kind,
name: String,
rate: Rate,
#[derivative(Debug = "ignore")]
recv_metric: AtomicRefCell<Box<AppRecvMetric + Send + Sync>>,
recv_metric: AtomicRefCell<Box<RecvMetric + Send + Sync>>,
#[derivative(Debug = "ignore")]
send: AppSend,
send: MetricsSend,
}
/// Dispatcher weak ref does not prevent dropping but still needs to be cleaned out.
impl Drop for AppSendMetric {
impl Drop for SendMetric {
fn drop(&mut self) {
self.send.drop_metric(self)
}
@ -73,36 +73,44 @@ impl Drop for AppSendMetric {
/// Allows defining metrics before a concrete type has been selected.
/// Allows replacing metrics backend on the fly at runtime.
#[derive(Clone)]
pub struct AppSend {
inner: Arc<RwLock<InnerAppSend>>,
pub struct MetricsSend {
inner: Arc<RwLock<InnerMetricsSend>>,
}
struct InnerAppSend {
metrics: HashMap<String, Weak<AppSendMetric>>,
recv: Arc<AppRecv + Send + Sync>,
struct InnerMetricsSend {
metrics: HashMap<String, Weak<SendMetric>>,
recv: Arc<MetricsRecv + Send + Sync>,
}
impl From<&'static str> for AppMetrics<Delegate> {
fn from(prefix: &'static str) -> AppMetrics<Delegate> {
let app_metrics: AppMetrics<Delegate> = app_delegate().into();
/// Allow turning a 'static str into a Delegate, where str is the prefix.
impl From<&'static str> for Metrics<Delegate> {
fn from(prefix: &'static str) -> Metrics<Delegate> {
let app_metrics: Metrics<Delegate> = delegate_metrics().into();
app_metrics.with_prefix(prefix)
}
}
impl From<AppSend> for AppMetrics<Delegate> {
fn from(send: AppSend) -> AppMetrics<Delegate> {
/// Allow turning a 'static str into a Delegate, where str is the prefix.
impl From<()> for Metrics<Delegate> {
fn from(_: ()) -> Metrics<Delegate> {
let app_metrics: Metrics<Delegate> = delegate_metrics().into();
app_metrics
}
}
impl From<MetricsSend> for Metrics<Delegate> {
fn from(send: MetricsSend) -> Metrics<Delegate> {
let send_cmd = send.clone();
AppMetrics::new(
Metrics::new(
// define metric
Arc::new(move |kind, name, rate| send.define_metric(kind, name, rate)),
// write / flush metric
control_scope(move |cmd| match cmd {
ScopeCmd::Write(metric, value) => {
let dispatch: &Arc<AppSendMetric> = metric;
let dispatch: &Arc<SendMetric> = metric;
dispatch.recv_metric.borrow().write(value);
// let recv_metric: AtomicRef<Box<AppRecvMetric + Send + Sync>> = dispatch.recv_metric.borrow();
// recv_metric.write(value)
}
ScopeCmd::Flush => send_cmd.inner.write().expect("Locking Delegate").recv.flush(),
}),
@ -110,25 +118,19 @@ impl From<AppSend> for AppMetrics<Delegate> {
}
}
impl AppSend {
impl MetricsSend {
/// 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,
) {
let receiver: Arc<AppRecv + Send + Sync> = Arc::new(receiver.into());
let inner: &mut InnerAppSend =
&mut *self.inner.write().expect("Lock Metrics Send");
pub fn set_receiver<R: MetricsRecv + Send + Sync + 'static>(&self, recv: Arc<R>) {
let inner = &mut self.inner.write().expect("Lock Metrics Send");
for mut metric in inner.metrics.values() {
if let Some(metric) = metric.upgrade() {
let receiver_metric =
receiver.define_metric(metric.kind, metric.name.as_ref(), metric.rate);
*metric.recv_metric.borrow_mut() = receiver_metric;
let recv_metric = recv.define_metric(metric.kind, metric.name.as_ref(), metric.rate);
*metric.recv_metric.borrow_mut() = recv_metric;
}
}
// TODO return old receiver (swap, how?)
inner.recv = receiver;
inner.recv = recv.clone()
}
fn define_metric(&self, kind: Kind, name: &str, rate: Rate) -> Delegate {
@ -137,7 +139,7 @@ impl AppSend {
.and_then(|metric_ref| Weak::upgrade(metric_ref))
.unwrap_or_else(|| {
let recv_metric = inner.recv.define_metric(kind, name, rate);
let new_metric = Arc::new(AppSendMetric {
let new_metric = Arc::new(SendMetric {
kind,
name: name.to_string(),
rate,
@ -152,7 +154,7 @@ impl AppSend {
})
}
fn drop_metric(&self, metric: &AppSendMetric) {
fn drop_metric(&self, metric: &SendMetric) {
let mut inner = self.inner.write().expect("Lock Metrics Send");
if inner.metrics.remove(&metric.name).is_none() {
panic!("Could not remove DelegatingMetric weak ref from delegation point")
@ -171,8 +173,8 @@ mod bench {
#[bench]
fn dispatch_marker_to_aggregate(b: &mut test::Bencher) {
let dispatch = app_delegate();
let sink: AppMetrics<Delegate> = dispatch.clone().into();
let dispatch = delegate_metrics();
let sink: Metrics<Delegate> = dispatch.clone().into();
dispatch.set_receiver(aggregate(summary, to_void()));
let metric = sink.marker("event_a");
b.iter(|| test::black_box(metric.mark()));
@ -180,8 +182,8 @@ mod bench {
#[bench]
fn dispatch_marker_to_void(b: &mut test::Bencher) {
let dispatch = app_delegate();
let sink: AppMetrics<Delegate> = dispatch.into();
let dispatch = delegate_metrics();
let sink: Metrics<Delegate> = dispatch.into();
let metric = sink.marker("event_a");
b.iter(|| test::black_box(metric.mark()));
}

View File

@ -1,7 +1,7 @@
//! Send metrics to a graphite server.
use core::*;
use local_metrics::*;
use context::*;
use error;
use self_metrics::*;
@ -14,7 +14,7 @@ use std::fmt::Debug;
use socket::RetrySocket;
app_metrics!{
metrics!{
<Aggregate> DIPSTICK_METRICS.with_prefix("graphite") => {
@Marker SEND_ERR: "send_failed";
@Marker TRESHOLD_EXCEEDED: "bufsize_exceeded";
@ -38,7 +38,7 @@ app_metrics!{
//}
/// Send metrics to a graphite server at the address and port provided.
pub fn to_graphite<ADDR>(address: ADDR) -> error::Result<LocalMetrics<Graphite>>
pub fn to_graphite<ADDR>(address: ADDR) -> error::Result<MetricContext<Graphite>>
where
ADDR: ToSocketAddrs + Debug + Clone,
{
@ -52,7 +52,7 @@ where
}
/// Send metrics to a graphite server at the address and port provided.
pub fn to_buffered_graphite<ADDR>(address: ADDR) -> error::Result<LocalMetrics<Graphite>>
pub fn to_buffered_graphite<ADDR>(address: ADDR) -> error::Result<MetricContext<Graphite>>
where
ADDR: ToSocketAddrs + Debug + Clone,
{
@ -90,7 +90,7 @@ fn graphite_metric(kind: Kind, name: &str, rate: Rate) -> Graphite {
Graphite { prefix, scale }
}
fn graphite_scope(socket: &Arc<RwLock<RetrySocket>>, buffered: bool) -> ControlScopeFn<Graphite> {
fn graphite_scope(socket: &Arc<RwLock<RetrySocket>>, buffered: bool) -> WriteFn<Graphite> {
let buf = ScopeBuffer {
buffer: Arc::new(RwLock::new(String::new())),
socket: socket.clone(),

View File

@ -30,20 +30,20 @@ pub mod macros;
pub mod core;
pub use core::*;
pub mod local_metrics;
pub use local_metrics::*;
pub mod context;
pub use context::*;
//pub mod local_delegate;
//pub use local_delegate::*;
pub mod app_delegate;
pub use app_delegate::*;
pub mod delegate;
pub use delegate::*;
mod output;
pub use output::*;
mod app_metrics;
pub use app_metrics::*;
mod metrics;
pub use metrics::*;
mod sample;
pub use sample::*;

View File

@ -17,27 +17,27 @@ macro_rules! time {
}};
}
/// AppMetrics can be used from anywhere (public), does not need to declare metrics in this block.
/// Metrics can be used from anywhere (public), does not need to declare metrics in this block.
#[macro_export]
#[doc(hidden)]
macro_rules! app_metrics {
macro_rules! metrics {
// TYPED
// typed, public, no metrics
(<$METRIC_TYPE:ty> pub $METRIC_ID:ident = $e:expr;) => {
lazy_static! { pub static ref $METRIC_ID: AppMetrics<$METRIC_TYPE> = $e.into(); }
lazy_static! { pub static ref $METRIC_ID: Metrics<$METRIC_TYPE> = $e.into(); }
};
// typed, public, some metrics
(<$METRIC_TYPE:ty> pub $METRIC_ID:ident = $e:expr => { $($REMAINING:tt)+ }) => {
lazy_static! { pub static ref $METRIC_ID: AppMetrics<$METRIC_TYPE> = $e.into(); }
lazy_static! { pub static ref $METRIC_ID: Metrics<$METRIC_TYPE> = $e.into(); }
__metrics_block!($METRIC_ID: $METRIC_TYPE; $($REMAINING)*);
};
// typed, module, no metrics
(<$METRIC_TYPE:ty> $METRIC_ID:ident = $e:expr;) => {
lazy_static! { pub static ref $METRIC_ID: AppMetrics<$METRIC_TYPE> = $e.into(); }
lazy_static! { pub static ref $METRIC_ID: Metrics<$METRIC_TYPE> = $e.into(); }
};
// typed, module, some metrics
(<$METRIC_TYPE:ty> $METRIC_ID:ident = $e:expr => { $($REMAINING:tt)+ }) => {
lazy_static! { pub static ref $METRIC_ID: AppMetrics<$METRIC_TYPE> = $e.into(); }
lazy_static! { pub static ref $METRIC_ID: Metrics<$METRIC_TYPE> = $e.into(); }
__metrics_block!($METRIC_ID: $METRIC_TYPE; $($REMAINING)*);
};
// typed, reuse predeclared
@ -46,32 +46,32 @@ macro_rules! app_metrics {
};
// typed, unidentified, some metrics
(<$METRIC_TYPE:ty> $e:expr => { $($REMAINING:tt)+ }) => {
lazy_static! { pub static ref UNIDENT_METRIC: AppMetrics<$METRIC_TYPE> = $e.into(); }
lazy_static! { pub static ref UNIDENT_METRIC: Metrics<$METRIC_TYPE> = $e.into(); }
__metrics_block!(UNIDENT_METRIC: $METRIC_TYPE; $($REMAINING)*);
};
// typed, root, some metrics
(<$METRIC_TYPE:ty> { $($REMAINING:tt)+ }) => {
lazy_static! { pub static ref ROOT_METRICS: AppMetrics<$METRIC_TYPE> = "".into(); }
lazy_static! { pub static ref ROOT_METRICS: Metrics<$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(); }
lazy_static! { pub static ref $METRIC_ID: Metrics<Delegate> = $e.into(); }
};
// delegated, public, some metrics
(pub $METRIC_ID:ident = $e:expr => { $($REMAINING:tt)+ }) => {
lazy_static! { pub static ref $METRIC_ID: AppMetrics<Delegate> = $e.into(); }
lazy_static! { pub static ref $METRIC_ID: Metrics<Delegate> = $e.into(); }
__metrics_block!($METRIC_ID: Delegate; $($REMAINING)*);
};
// delegated, module, no metrics
($METRIC_ID:ident = $e:expr;) => {
lazy_static! { pub static ref $METRIC_ID: AppMetrics<Delegate> = $e.into(); }
lazy_static! { pub static ref $METRIC_ID: Metrics<Delegate> = $e.into(); }
};
// delegated, module, some metrics
($METRIC_ID:ident = $e:expr => { $($REMAINING:tt)+ }) => {
lazy_static! { pub static ref $METRIC_ID: AppMetrics<Delegate> = $e.into(); }
lazy_static! { pub static ref $METRIC_ID: Metrics<Delegate> = $e.into(); }
__metrics_block!($METRIC_ID: Delegate; $($REMAINING)*);
};
// delegated,reuse predeclared
@ -80,12 +80,12 @@ macro_rules! app_metrics {
};
// delegated, unidentified, some metrics
($e:expr => { $($REMAINING:tt)+ }) => {
lazy_static! { pub static ref UNIDENT_METRIC: AppMetrics<Delegate> = $e.into(); }
lazy_static! { pub static ref UNIDENT_METRIC: Metrics<Delegate> = $e.into(); }
__metrics_block!(UNIDENT_METRIC: Delegate; $($REMAINING)*);
};
// delegated, root, some metrics
( => { $($REMAINING:tt)+ }) => {
lazy_static! { pub static ref ROOT_METRICS: AppMetrics<Delegate> = "".into(); }
lazy_static! { pub static ref ROOT_METRICS: Metrics<Delegate> = ().into(); }
__metrics_block!(ROOT_METRICS: Delegate; $($REMAINING)*);
};
}
@ -97,103 +97,177 @@ 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); }
Counter<$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); }
Counter<$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); }
Marker<$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); }
Marker<$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); }
Gauge<$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); }
Gauge<$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); }
Timer<$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); }
Timer<$METRIC_TYPE> = $APP_METRICS.timer($METRIC_NAME); }
__metrics_block!($APP_METRICS: $METRIC_TYPE; $($REMAINING)*);
};
($METRIC_ID:ident : $METRIC_TYPE:ty;) => ()
}
/// Define application-scoped metrics.
#[macro_export]
#[deprecated(since="0.7.0", note="Use metrics!() instead")]
macro_rules! app_metrics {
($type_param: ty, $metric_id: ident = ($($app_metrics: expr),+ $(,)*)) => {
lazy_static! { pub static ref $metric_id: Metrics<$type_param> = metrics(($($app_metrics),*)); }
};
($type_param: ty, $metric_id: ident = [$($app_metrics: expr),+ $(,)*]) => {
lazy_static! { pub static ref $metric_id: Metrics<$type_param> = metrics(&[$($app_metrics),*][..],); }
};
($type_param: ty, $metric_id: ident = $app_metrics: expr) => {
lazy_static! { pub static ref $metric_id: Metrics<$type_param> = $app_metrics.into(); }
};
}
/// Define application-scoped markers.
#[macro_export]
#[deprecated]
#[deprecated(since="0.7.0", note="Use metrics!() instead")]
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 );)* }
Marker<$type_param> = $app_metrics.marker( $metric_name );)* }
};
}
/// Define application-scoped counters.
#[macro_export]
#[deprecated]
#[deprecated(since="0.7.0", note="Use metrics!() instead")]
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 );)* }
Counter<$type_param> = $app_metrics.counter( $metric_name );)* }
};
}
/// Define application-scoped gauges.
#[macro_export]
#[deprecated]
#[deprecated(since="0.7.0", note="Use metrics!() instead")]
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 );)* }
Gauge<$type_param> = $app_metrics.gauge( $metric_name );)* }
};
}
/// Define application-scoped timers.
#[macro_export]
#[deprecated]
#[deprecated(since="0.7.0", note="Use metrics!() instead")]
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 );)* }
Timer<$type_param> = $app_metrics.timer( $metric_name );)* }
};
}
/////////////
// MOD SCOPE
/// Define module-scoped metrics.
#[macro_export]
#[deprecated(since="0.7.0", note="Use metrics!() instead")]
macro_rules! mod_metrics {
($type_param: ty, $metric_id: ident = ($($app_metrics: expr),+ $(,)*)) => {
lazy_static! { static ref $metric_id: Metrics<$type_param> = metrics(($($app_metrics),*)); }
};
($type_param: ty, $metric_id: ident = [$($app_metrics: expr),+ $(,)*]) => {
lazy_static! { static ref $metric_id: Metrics<$type_param> = metrics(&[$($app_metrics),*][..],); }
};
($type_param: ty, $metric_id: ident = $mod_metrics: expr) => {
lazy_static! { static ref $metric_id: Metrics<$type_param> = $mod_metrics.into(); }
};
}
/// Define module-scoped markers.
#[macro_export]
#[deprecated(since="0.7.0", note="Use metrics!() instead")]
macro_rules! mod_marker {
($type_param: ty, $mod_metrics: expr, { $($metric_id: ident: $metric_name: expr),* $(,)* } ) => {
lazy_static! { $(static ref $metric_id: Marker<$type_param> = $mod_metrics.marker( $metric_name );)* }
};
}
/// Define module-scoped counters.
#[macro_export]
#[deprecated(since="0.7.0", note="Use metrics!() instead")]
macro_rules! mod_counter {
($type_param: ty, $mod_metrics: expr, { $($metric_id: ident: $metric_name: expr),* $(,)* } ) => {
lazy_static! { $(static ref $metric_id: Counter<$type_param> = $mod_metrics.counter( $metric_name );)* }
};
}
/// Define module-scoped gauges.
#[macro_export]
#[deprecated(since="0.7.0", note="Use metrics!() instead")]
macro_rules! mod_gauge {
($type_param: ty, $mod_metrics: expr, { $($metric_id: ident: $metric_name: expr),* $(,)* } ) => {
lazy_static! { $(static ref $metric_id: Gauge<$type_param> = $mod_metrics.gauge( $metric_name );)* }
};
($type_param: ty, $mod_metrics: expr, $metric_id: ident: $metric_name: expr) => {
lazy_static! { static ref $metric_id: Gauge<$type_param> = $mod_metrics.gauge( $metric_name ); }
}
}
/// Define module-scoped timers.
#[macro_export]
#[deprecated(since="0.7.0", note="Use metrics!() instead")]
macro_rules! mod_timer {
($type_param: ty, $mod_metrics: expr, { $($metric_id: ident: $metric_name: expr),* $(,)* } ) => {
lazy_static! { $(static ref $metric_id: Timer<$type_param> = $mod_metrics.timer( $metric_name );)* }
};
}
#[cfg(test)]
mod test_app {
use self_metrics::*;
app_metrics!(<Aggregate> TEST_METRICS = DIPSTICK_METRICS.with_prefix("test_prefix"););
metrics!(<Aggregate> TEST_METRICS = DIPSTICK_METRICS.with_prefix("test_prefix"););
app_marker!(<Aggregate> TEST_METRICS => {
M1: "failed",

View File

@ -12,7 +12,7 @@ use core::Kind::*;
use namespace::*;
use cache::*;
use schedule::*;
use app_delegate::*;
use delegate::*;
use std::time::Duration;
@ -21,12 +21,23 @@ pub use num::ToPrimitive;
/// Wrap the metrics backend to provide an application-friendly interface.
/// Open a metric scope to share across the application.
pub fn app_metrics<M, AM>(app_metrics: AM) -> AppMetrics<M>
#[deprecated(since="0.7.0", note="Use metrics() instead")]
pub fn app_metrics<M, AM>(scope: AM) -> Metrics<M>
where
M: Clone + Send + Sync + 'static,
AM: Into<AppMetrics<M>>,
AM: Into<Metrics<M>>,
{
app_metrics.into()
scope.into()
}
/// Wrap the metrics backend to provide an application-friendly interface.
/// Open a metric scope to share across the application.
pub fn metrics<M, AM>(scope: AM) -> Metrics<M>
where
M: Clone + Send + Sync + 'static,
AM: Into<Metrics<M>>,
{
scope.into()
}
/// A monotonic counter metric.
@ -34,13 +45,13 @@ where
/// preventing programming errors.
#[derive(Derivative)]
#[derivative(Debug)]
pub struct AppMarker<M> {
pub struct Marker<M> {
metric: M,
#[derivative(Debug = "ignore")]
scope: ControlScopeFn<M>,
scope: WriteFn<M>,
}
impl<M> AppMarker<M> {
impl<M> Marker<M> {
/// Record a single event occurence.
pub fn mark(&self) {
self.scope.write(&self.metric, 1);
@ -50,13 +61,13 @@ impl<M> AppMarker<M> {
/// A counter that sends values to the metrics backend
#[derive(Derivative)]
#[derivative(Debug)]
pub struct AppCounter<M> {
pub struct Counter<M> {
metric: M,
#[derivative(Debug = "ignore")]
scope: ControlScopeFn<M>,
scope: WriteFn<M>,
}
impl<M> AppCounter<M> {
impl<M> Counter<M> {
/// Record a value count.
pub fn count<V: ToPrimitive>(&self, count: V) {
self.scope.write(&self.metric, count.to_u64().unwrap());
@ -66,13 +77,13 @@ impl<M> AppCounter<M> {
/// A gauge that sends values to the metrics backend
#[derive(Derivative)]
#[derivative(Debug)]
pub struct AppGauge<M> {
pub struct Gauge<M> {
metric: M,
#[derivative(Debug = "ignore")]
scope: ControlScopeFn<M>,
scope: WriteFn<M>,
}
impl<M> AppGauge<M> {
impl<M> Gauge<M> {
/// Record a value point for this gauge.
pub fn value<V: ToPrimitive>(&self, value: V) {
self.scope.write(&self.metric, value.to_u64().unwrap());
@ -87,13 +98,13 @@ impl<M> AppGauge<M> {
/// - with the interval_us() method, providing an externally determined microsecond interval
#[derive(Derivative)]
#[derivative(Debug)]
pub struct AppTimer<M> {
pub struct Timer<M> {
metric: M,
#[derivative(Debug = "ignore")]
scope: ControlScopeFn<M>,
scope: WriteFn<M>,
}
impl<M> AppTimer<M> {
impl<M> Timer<M> {
/// Record a microsecond interval for this timer
/// Can be used in place of start()/stop() if an external time interval source is used
pub fn interval_us<V: ToPrimitive>(&self, interval_us: V) -> V {
@ -132,29 +143,47 @@ impl<M> AppTimer<M> {
}
}
//// AppMetrics proper
/// Help transition to new syntax
#[deprecated(since="0.7.0", note="Use Metrics instead")]
pub type AppMetrics<M> = Metrics<M>;
/// Help transition to new syntax
#[deprecated(since="0.7.0", note="Use Marker instead")]
pub type AppMarker<M> = Marker<M>;
/// Help transition to new syntax
#[deprecated(since="0.7.0", note="Use Counter instead")]
pub type AppCounter<M> = Counter<M>;
/// Help transition to new syntax
#[deprecated(since="0.7.0", note="Use Gauge instead")]
pub type AppGauge<M> = Gauge<M>;
/// Help transition to new syntax
#[deprecated(since="0.7.0", note="Use Timer instead")]
pub type AppTimer<M> = Timer<M>;
/// Variations of this should also provide control of the metric recording scope.
#[derive(Derivative, Clone)]
#[derivative(Debug)]
pub struct AppMetrics<M> {
pub struct Metrics<M> {
#[derivative(Debug = "ignore")]
define_metric_fn: DefineMetricFn<M>,
#[derivative(Debug = "ignore")]
single_scope: ControlScopeFn<M>,
single_scope: WriteFn<M>,
}
impl<M> AppMetrics<M> {
impl<M> Metrics<M> {
/// Create new application metrics instance.
pub fn new(define_metric_fn: DefineMetricFn<M>, scope: ControlScopeFn<M>) -> Self {
AppMetrics {
pub fn new(define_metric_fn: DefineMetricFn<M>, scope: WriteFn<M>) -> Self {
Metrics {
define_metric_fn,
single_scope: scope,
}
}
}
impl<M> AppMetrics<M>
impl<M> Metrics<M>
where
M: Clone + Send + Sync + 'static,
{
@ -164,44 +193,43 @@ where
(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> {
/// Define an event counter of the provided name.
pub fn marker<AS: AsRef<str>>(&self, name: AS) -> Marker<M> {
let metric = self.define_metric(Marker, name.as_ref(), 1.0);
AppMarker {
Marker {
metric,
scope: self.single_scope.clone(),
}
}
/// Get a counter of the provided name.
pub fn counter<AS: AsRef<str>>(&self, name: AS) -> AppCounter<M> {
/// Define a counter of the provided name.
pub fn counter<AS: AsRef<str>>(&self, name: AS) -> Counter<M> {
let metric = self.define_metric(Counter, name.as_ref(), 1.0);
AppCounter {
Counter {
metric,
scope: self.single_scope.clone(),
}
}
/// Get a timer of the provided name.
pub fn timer<AS: AsRef<str>>(&self, name: AS) -> AppTimer<M> {
/// Define a timer of the provided name.
pub fn timer<AS: AsRef<str>>(&self, name: AS) -> Timer<M> {
let metric = self.define_metric(Timer, name.as_ref(), 1.0);
AppTimer {
Timer {
metric,
scope: self.single_scope.clone(),
}
}
/// Get a gauge of the provided name.
pub fn gauge<AS: AsRef<str>>(&self, name: AS) -> AppGauge<M> {
/// Define a gauge of the provided name.
pub fn gauge<AS: AsRef<str>>(&self, name: AS) -> Gauge<M> {
let metric = self.define_metric(Gauge, name.as_ref(), 1.0);
AppGauge {
Gauge {
metric,
scope: self.single_scope.clone(),
}
}
/// Forcefully flush the backing metrics scope.
/// This is usually not required since static metrics use auto flushing scopes.
/// Flush the backing metrics buffer.
/// The effect, if any, of this method depends on the selected metrics backend.
pub fn flush(&self) {
self.single_scope.flush();
@ -223,17 +251,17 @@ where
//// Dispatch / Receiver impl
struct AppRecvMetricImpl<M> {
struct RecvMetricImpl<M> {
metric: M,
scope: ControlScopeFn<M>,
scope: WriteFn<M>,
}
impl<M: Send + Sync + Clone + 'static> AppRecv for AppMetrics<M> {
fn define_metric(&self, kind: Kind, name: &str, rate: Rate) -> Box<AppRecvMetric + Send + Sync> {
let scope: ControlScopeFn<M> = self.single_scope.clone();
impl<M: Send + Sync + Clone + 'static> MetricsRecv for Metrics<M> {
fn define_metric(&self, kind: Kind, name: &str, rate: Rate) -> Box<RecvMetric + Send + Sync> {
let scope: WriteFn<M> = self.single_scope.clone();
let metric: M = self.define_metric(kind, name, rate);
Box::new(AppRecvMetricImpl { metric, scope })
Box::new(RecvMetricImpl { metric, scope })
}
fn flush(&self) {
@ -241,7 +269,7 @@ impl<M: Send + Sync + Clone + 'static> AppRecv for AppMetrics<M> {
}
}
impl<M> AppRecvMetric for AppRecvMetricImpl<M> {
impl<M> RecvMetric for RecvMetricImpl<M> {
fn write(&self, value: Value) {
self.scope.write(&self.metric, value);
}
@ -249,19 +277,19 @@ impl<M> AppRecvMetric for AppRecvMetricImpl<M> {
//// Mutators impl
impl<M: Send + Sync + Clone + 'static> WithNamespace for AppMetrics<M> {
impl<M: Send + Sync + Clone + 'static> WithNamespace for Metrics<M> {
fn with_name<IN: Into<Namespace>>(&self, names: IN) -> Self {
let ns = &names.into();
AppMetrics {
Metrics {
define_metric_fn: add_namespace(ns, self.define_metric_fn.clone()),
single_scope: self.single_scope.clone(),
}
}
}
impl<M: Send + Sync + Clone + 'static> WithCache for AppMetrics<M> {
impl<M: Send + Sync + Clone + 'static> WithCache for Metrics<M> {
fn with_cache(&self, cache_size: usize) -> Self {
AppMetrics {
Metrics {
define_metric_fn: add_cache(cache_size, self.define_metric_fn.clone()),
single_scope: self.single_scope.clone(),
}
@ -277,7 +305,7 @@ mod bench {
#[bench]
fn time_bench_direct_dispatch_event(b: &mut test::Bencher) {
let sink = aggregate(summary, to_void());
let metrics = app_metrics(sink);
let metrics = metrics(sink);
let marker = metrics.marker("aaa");
b.iter(|| test::black_box(marker.mark()));
}

View File

@ -1,27 +1,27 @@
//! Dispatch metrics to multiple sinks.
use core::*;
use local_metrics::*;
use app_metrics::*;
use context::*;
use metrics::*;
use std::sync::Arc;
/// Two chains of different types can be combined in a tuple.
/// The chains will act as one, each receiving calls in the order the appear in the tuple.
/// For more than two types, make tuples of tuples, "Yo Dawg" style.
impl<M1, M2> From<(LocalMetrics<M1>, LocalMetrics<M2>)> for AppMetrics<(M1, M2)>
impl<M1, M2> From<(MetricContext<M1>, MetricContext<M2>)> for Metrics<(M1, M2)>
where
M1: 'static + Clone + Send + Sync,
M2: 'static + Clone + Send + Sync,
{
fn from(combo: (LocalMetrics<M1>, LocalMetrics<M2>)) -> AppMetrics<(M1, M2)> {
fn from(combo: (MetricContext<M1>, MetricContext<M2>)) -> Metrics<(M1, M2)> {
let scope0 = combo.0.open_scope();
let scope1 = combo.1.open_scope();
let scope0a = scope0.clone();
let scope1a = scope1.clone();
AppMetrics::new(
Metrics::new(
Arc::new(move |kind, name, rate| (
scope0.define_metric(kind, name, rate),
scope1.define_metric(kind, name, rate),
@ -41,15 +41,15 @@ where
}
}
impl<'a, M> From<&'a [LocalMetrics<M>]> for AppMetrics<Vec<M>>
impl<'a, M> From<&'a [MetricContext<M>]> for Metrics<Vec<M>>
where
M: 'static + Clone + Send + Sync,
{
fn from(chains: &'a [LocalMetrics<M>]) -> AppMetrics<Vec<M>> {
let scopes: Vec<AppMetrics<M>> = chains.iter().map(|x| x.open_scope()).collect();
fn from(chains: &'a [MetricContext<M>]) -> Metrics<Vec<M>> {
let scopes: Vec<Metrics<M>> = chains.iter().map(|x| x.open_scope()).collect();
let scopes2 = scopes.clone();
AppMetrics::new(
Metrics::new(
Arc::new(move |kind, name, rate| {
scopes.iter().map(|m| m.define_metric(kind, name, rate)).collect()
}),

View File

@ -1,11 +1,11 @@
//! Standard stateless metric outputs.
// TODO parameterize templates
use core::*;
use local_metrics::*;
use context::*;
use std::sync::RwLock;
/// Write metric values to stdout using `println!`.
pub fn to_stdout() -> LocalMetrics<String> {
pub fn to_stdout() -> MetricContext<String> {
metrics_context(
|_kind, name, _rate| String::from(name),
|| control_scope(|cmd|
@ -19,7 +19,7 @@ pub fn to_stdout() -> LocalMetrics<String> {
/// Values are buffered until #flush is called
/// Buffered operation requires locking.
/// If thread latency is a concern you may wish to also use #with_async_queue.
pub fn to_buffered_stdout() -> LocalMetrics<String> {
pub fn to_buffered_stdout() -> MetricContext<String> {
metrics_context(
|_kind, name, _rate| String::from(name),
|| {
@ -42,7 +42,7 @@ pub fn to_buffered_stdout() -> LocalMetrics<String> {
/// Write metric values to the standard log using `info!`.
// TODO parameterize log level
pub fn to_log() -> LocalMetrics<String> {
pub fn to_log() -> MetricContext<String> {
metrics_context(
|_kind, name, _rate| String::from(name),
|| control_scope(|cmd|
@ -57,7 +57,7 @@ pub fn to_log() -> LocalMetrics<String> {
/// Buffered operation requires locking.
/// If thread latency is a concern you may wish to also use #with_async_queue.
// TODO parameterize log level
pub fn to_buffered_log() -> LocalMetrics<String> {
pub fn to_buffered_log() -> MetricContext<String> {
metrics_context(
|_kind, name, _rate| String::from(name),
|| {
@ -80,7 +80,7 @@ pub fn to_buffered_log() -> LocalMetrics<String> {
/// Discard all metric values sent to it.
pub fn to_void() -> LocalMetrics<()> {
pub fn to_void() -> MetricContext<()> {
metrics_context(
move |_kind, _name, _rate| (),
|| control_scope(|_cmd| {}),

View File

@ -20,7 +20,7 @@
//! ```
use core::*;
use local_metrics::*;
use context::*;
use core::Kind::*;
use scores::{ScoreSnapshot, ScoreType};
use scores::ScoreType::*;
@ -40,7 +40,7 @@ pub trait Publish: Send + Sync + Debug {
pub struct Publisher<E, M> {
#[derivative(Debug = "ignore")]
statistics: Box<E>,
output: LocalMetrics<M>,
output: MetricContext<M>,
}
impl<E, M> Publisher<E, M>
@ -50,7 +50,7 @@ where
{
/// Define a new metrics publishing strategy, from a transformation
/// function and a target metric chain.
pub fn new(stat_fn: E, output: LocalMetrics<M>) -> Self {
pub fn new(stat_fn: E, output: MetricContext<M>) -> Self {
Publisher {
statistics: Box::new(stat_fn),
output,

View File

@ -1,39 +1,41 @@
use app_metrics::AppMetrics;
use metrics::Metrics;
use output;
use app_delegate::{AppRecv, AppSend};
use delegate::{MetricsRecv, MetricsSend};
use std::sync::{Arc, RwLock};
fn no_app_metrics() -> Arc<AppRecv + Send + Sync> {
let void_metrics: AppMetrics<_> = output::to_void().into();
fn no_metrics() -> Arc<MetricsRecv + Send + Sync> {
let void_metrics: Metrics<_> = output::to_void().into();
Arc::new(void_metrics)
}
/// The registry contains a list of every metrics dispatch point in the app.
lazy_static! {
static ref NO_APP_METRICS: Arc<AppRecv + Sync + Send> = no_app_metrics();
static ref NO_RECV: Arc<MetricsRecv + Sync + Send> = no_metrics();
static ref DEFAULT_APP_RECEIVER: RwLock<Arc<AppRecv + Sync + Send>> = RwLock::new(NO_APP_METRICS.clone());
static ref DEFAULT_RECV: RwLock<Arc<MetricsRecv + Sync + Send>> = RwLock::new(NO_RECV.clone());
static ref DELEGATE_REGISTRY: RwLock<Vec<AppSend>> = RwLock::new(vec![]);
static ref DELEGATE_REGISTRY: RwLock<Vec<MetricsSend>> = RwLock::new(vec![]);
}
/// Register a new app send.
pub fn add_app_send(send: AppSend) {
pub fn add_metrics_send(send: MetricsSend) {
DELEGATE_REGISTRY.write().unwrap().push(send.clone());
}
/// Get the default app recv.
pub fn get_default_app_recv() -> Arc<AppRecv + Send + Sync> {
DEFAULT_APP_RECEIVER.read().unwrap().clone()
pub fn get_default_metrics_recv() -> Arc<MetricsRecv + Send + Sync> {
DEFAULT_RECV.read().unwrap().clone()
}
/// Install a new receiver for all dispatched metrics, replacing any previous receiver.
pub fn send_app_metrics<IS: Into<AppMetrics<T>>, T: Send + Sync + Clone + 'static>(
pub fn send_metrics<IS: Into<Metrics<T>>, T: Send + Sync + Clone + 'static>(
into_recv: IS,
) {
let recv = into_recv.into();
let recv = Arc::new(into_recv.into());
for d in DELEGATE_REGISTRY.read().unwrap().iter() {
d.set_receiver(recv.clone());
}
*DEFAULT_RECV.write().unwrap() = recv;
}

View File

@ -1,7 +1,7 @@
//! Reduce the amount of data to process or transfer by statistically dropping some of it.
use core::*;
use local_metrics::*;
use context::*;
use pcg32;
@ -16,7 +16,7 @@ where
fn with_sampling_rate(&self, sampling_rate: Rate) -> Self;
}
impl<M: Send + Sync + 'static + Clone> WithSamplingRate for LocalMetrics<M> {
impl<M: Send + Sync + 'static + Clone> WithSamplingRate for MetricContext<M> {
fn with_sampling_rate(&self, sampling_rate: Rate) -> Self {
let int_sampling_rate = pcg32::to_int_rate(sampling_rate);
@ -52,10 +52,10 @@ impl<M: Send + Sync + 'static + Clone> WithSamplingRate for LocalMetrics<M> {
/// Perform random sampling of values according to the specified rate.
#[deprecated(since = "0.5.0", note = "Use `with_sampling_rate` instead.")]
pub fn sample<M, IC>(sampling_rate: Rate, chain: IC) -> LocalMetrics<M>
pub fn sample<M, IC>(sampling_rate: Rate, chain: IC) -> MetricContext<M>
where
M: Clone + Send + Sync + 'static,
IC: Into<LocalMetrics<M>>,
IC: Into<MetricContext<M>>,
{
let chain = chain.into();
chain.with_sampling_rate(sampling_rate)

View File

@ -4,7 +4,7 @@
pub use core::*;
pub use app_metrics::*;
pub use metrics::*;
pub use aggregate::*;
pub use publish::*;
pub use scores::*;
@ -18,7 +18,7 @@ lazy_static! {
/// Application metrics are collected to the aggregator
app_metrics!(<Aggregate> DIPSTICK_METRICS = build_self_metrics(););
metrics!(<Aggregate> DIPSTICK_METRICS = build_self_metrics(););
fn build_aggregator() -> Aggregator {
// TODO make publishable
@ -30,8 +30,8 @@ pub fn snapshot() -> Vec<ScoreSnapshot> {
vec![]
}
fn build_self_metrics() -> AppMetrics<Aggregate> {
fn build_self_metrics() -> Metrics<Aggregate> {
let mug: &Aggregator = &DIPSTICK_AGGREGATOR;
let am: AppMetrics<Aggregate> = mug.clone().into();
let am: Metrics<Aggregate> = mug.clone().into();
am.with_prefix("dipstick")
}

View File

@ -1,7 +1,7 @@
//! Send metrics to a statsd server.
use core::*;
use local_metrics::*;
use context::*;
use error;
use self_metrics::*;
@ -10,7 +10,7 @@ use std::sync::{Arc, RwLock};
pub use std::net::ToSocketAddrs;
app_metrics! {
metrics! {
<Aggregate> DIPSTICK_METRICS.with_prefix("statsd") => {
@Marker SEND_ERR: "send_failed";
@Counter SENT_BYTES: "sent_bytes";
@ -18,7 +18,7 @@ app_metrics! {
}
/// Send metrics to a statsd server at the address and port provided.
pub fn to_statsd<ADDR>(address: ADDR) -> error::Result<LocalMetrics<Statsd>>
pub fn to_statsd<ADDR>(address: ADDR) -> error::Result<MetricContext<Statsd>>
where
ADDR: ToSocketAddrs,
{