diff --git a/HANDBOOK.md b/HANDBOOK.md index 8b9a226..482100c 100755 --- a/HANDBOOK.md +++ b/HANDBOOK.md @@ -57,48 +57,94 @@ Timer's internal precision is microseconds but can be scaled down on output. extern crate dipstick; use dipstick::*; fn main() { - let app_metrics = Stream::to_stdout().metrics(); - let timer = app_metrics.timer("my_timer"); - time!(timer, {/* slow code here */} ); - timer.time(|| {/* slow code here */} ); + let metrics = Stream::to_stdout().metrics(); + let timer = metrics.timer("my_timer"); - let start = timer.start(); - /* slow code here */ - timer.stop(start); + // using macro + time!(timer, {/* timed code here ... */} ); + // using closure + timer.time(|| {/* timed code here ... */} ); + + // using start/stop + let handle = timer.start(); + /* timed code here ... */ + timer.stop(handle); + + // directly reporting microseconds timer.interval_us(123_456); } ``` ### Level -Relative quantity counter. Accepts positive and negative cumulative values. -If aggregated, observed minimum and maximum track the sum of values rather than individual values as for `Counter`. +A relative, cumulative quantity counter. Accepts positive and negative values. +If aggregated, observed minimum and maximum track the _sum_ of values (as opposed to `Counter` min and max _individual_ values). ### Gauge An instant observation of a resource's value (positive or negative, but non-cumulative). -The observation of Gauges is not automatic and must be performed programmatically as with other metric types. +The observation of Gauges can be performed programmatically as with other metric types or +it can be triggered automatically, either on schedule or upon flushing the scope: + +````rust +extern crate dipstick; +use dipstick::*; +use std::time::Duration; + +fn main() { + let metrics = Stream::to_stdout().metrics(); + let uptime = metrics.gauge("uptime"); + + // report gauge value programmatically + uptime.value(2); + + // observe a constant value before each flush + let uptime = metrics.gauge("uptime"); + metrics.observe(uptime, || 6).on_flush(); + + // observe a function-provided value periodically + metrics + .observe(metrics.gauge("threads"), thread_count) + .every(Duration::from_secs(1)); +} + +fn thread_count() -> MetricValue { + 6 +} +```` ### Names Each metric must be given a name upon creation. Names are opaque to the application and are used only to identify the metrics upon output. -Names may be prepended with a namespace by each configured backend. -Aggregated statistics may also append identifiers to the metric's name. - -Names should exclude characters that can interfere with namespaces, separator and output protocols. -A good convention is to stick with lowercase alphanumeric identifiers of less than 12 characters. +Names may be prepended with a application-namespace shared across all backends. ```rust extern crate dipstick; use dipstick::*; fn main() { - let app_metrics = Stream::to_stdout().metrics(); - let db_metrics = app_metrics.named("database"); - let _db_timer = db_metrics.timer("db_timer"); - let _db_counter = db_metrics.counter("db_counter"); + let metrics = Stream::to_stdout().metrics(); + + // plainly name "timer" + let _timer = metrics.timer("timer"); + + // prepend namespace + let db_metrics = metrics.named("database"); + + // qualified name will be "database.counter" + let _db_counter = db_metrics.counter("counter"); } ``` +Names may be prepended with a namespace by each configured backend. +For example, the same metric `request.success` could appear under different qualified names: +- logging as `app_module.request.success` +- statsd as `environment.hostname.pid.module.request.success` + +Aggregation statistics may also append identifiers to the metric's name, such as `counter_mean` or `marker_rate`. + +Names should exclude characters that can interfere with namespaces, separator and output protocols. +A good convention is to stick with lowercase alphanumeric identifiers of less than 12 characters. + ### Labels diff --git a/examples/observer.rs b/examples/observer.rs index 7ca87ec..506aacf 100644 --- a/examples/observer.rs +++ b/examples/observer.rs @@ -20,16 +20,15 @@ use std::time::Duration; use dipstick::*; fn main() { - let mut metrics = AtomicBucket::new().named("process"); + let metrics = AtomicBucket::new().named("process"); metrics.drain(Stream::to_stdout()); metrics.flush_every(Duration::from_secs(3)); let uptime = metrics.gauge("uptime"); metrics.observe(uptime, || 6).on_flush(); - let threads = metrics.gauge("threads"); metrics - .observe(threads, thread_count) + .observe(metrics.gauge("threads"), thread_count) .every(Duration::from_secs(1)); loop { diff --git a/src/core/attributes.rs b/src/core/attributes.rs index 2afcd5e..927ee55 100755 --- a/src/core/attributes.rs +++ b/src/core/attributes.rs @@ -113,7 +113,7 @@ where } pub struct ObserveWhen<'a, T, F> { - target: &'a mut T, + target: &'a T, gauge: Gauge, operation: Arc, } @@ -123,34 +123,35 @@ where F: Fn() -> MetricValue + Send + Sync + 'static, T: InputScope + WithAttributes + Send + Sync, { + /// Observe the metric's value upon flushing the scope. pub fn on_flush(self) { let gauge = self.gauge; let op = self.operation; - write_lock!(self.target.mut_attributes().flush_listeners) + write_lock!(self.target.get_attributes().flush_listeners) .push(Arc::new(move || gauge.value(op()))); } + /// Observe the metric's value periodically. pub fn every(self, period: Duration) -> CancelHandle { let gauge = self.gauge; let op = self.operation; let handle = SCHEDULER.schedule(period, move || gauge.value(op())); - write_lock!(self.target.mut_attributes().tasks).push(handle.clone()); + write_lock!(self.target.get_attributes().tasks).push(handle.clone()); handle } } /// Schedule a recurring task pub trait Observe { - /// Schedule a recurring task. - /// The returned handle can be used to cancel the task. - fn observe(&mut self, gauge: Gauge, operation: F) -> ObserveWhen + /// Provide a source for a metric's values. + fn observe(&self, gauge: Gauge, operation: F) -> ObserveWhen where F: Fn() -> MetricValue + Send + Sync + 'static, Self: Sized; } impl Observe for T { - fn observe(&mut self, gauge: Gauge, operation: F) -> ObserveWhen + fn observe(&self, gauge: Gauge, operation: F) -> ObserveWhen where F: Fn() -> MetricValue + Send + Sync + 'static, Self: Sized, @@ -284,7 +285,7 @@ mod test { #[test] fn on_flush() { - let mut metrics: StatsMapScope = StatsMap::default().metrics(); + let metrics: StatsMapScope = StatsMap::default().metrics(); let gauge = metrics.gauge("my_gauge"); metrics.observe(gauge, || 4).on_flush(); metrics.flush().unwrap();