Fix scope namespace concat

This commit is contained in:
Francis Lalonde 2018-05-28 22:58:58 -04:00
parent d764cb5826
commit 09baab8c42
26 changed files with 195 additions and 106 deletions

View File

@ -135,7 +135,7 @@ timer.interval_us(123_456);
Related metrics can share a namespace:
```rust,skt-run
let app_metrics = metric_scope(to_stdout());
let db_metrics = app_metrics.with_suffix("database");
let db_metrics = app_metrics.with_prefix("database");
let _db_timer = db_metrics.timer("db_timer");
let _db_counter = db_metrics.counter("db_counter");
```

39
examples/aggregate2graphite.rs Executable file
View File

@ -0,0 +1,39 @@
//! A sample application continuously aggregating metrics,
//! printing the summary stats every three seconds
extern crate dipstick;
use std::time::Duration;
use dipstick::*;
fn main() {
let metrics = MetricAggregator::new().with_prefix("test");
// MetricAggregator::set_default_output(to_stdout());
metrics.set_output(to_graphite("localhost:2003").expect("Graphite host name and port")
.with_prefix("machine1").with_prefix("application"));
metrics.flush_every(Duration::from_secs(3));
let counter = metrics.counter("counter_a");
let timer = metrics.timer("timer_a");
let gauge = metrics.gauge("gauge_a");
let marker = metrics.marker("marker_a");
loop {
// add counts forever, non-stop
counter.count(11);
counter.count(12);
counter.count(13);
timer.interval_us(11_000_000);
timer.interval_us(12_000_000);
timer.interval_us(13_000_000);
gauge.value(11);
gauge.value(12);
gauge.value(13);
marker.mark();
}
}

View File

@ -7,7 +7,7 @@ use std::time::Duration;
use dipstick::*;
fn main() {
let metrics = MetricAggregator::new();
let metrics = MetricAggregator::new().with_prefix("test");
// MetricAggregator::set_default_output(to_stdout());
metrics.set_output(to_stdout());

View File

@ -13,7 +13,7 @@ fn main() {
let counter = metrics.counter("counter_a");
let timer = metrics.timer("timer_b");
let subsystem_metrics = metrics.with_suffix("subsystem");
let subsystem_metrics = metrics.with_prefix("subsystem");
let event = subsystem_metrics.marker("event_c");
let gauge = subsystem_metrics.gauge("gauge_d");

View File

@ -19,7 +19,7 @@ fn main() {
app_metrics.counter("just_once").count(4);
// metric names can be prepended with a common prefix
let prefixed_metrics = app_metrics.with_suffix("subsystem");
let prefixed_metrics = app_metrics.with_prefix("subsystem");
let event = prefixed_metrics.marker("event_c");
let gauge = prefixed_metrics.gauge("gauge_d");

View File

@ -32,7 +32,7 @@ fn main() {
},
// scaling the score value and appending unit to name
(kind, ScoreType::Sum(sum)) => Some((kind, name.with_suffix("per_thousand"), sum / 1000)),
(kind, ScoreType::Sum(sum)) => Some((kind, name.with_prefix("per_thousand"), sum / 1000)),
// using the unmodified metric name
(kind, ScoreType::Mean(avg)) => Some((kind, name, avg.round() as u64)),

View File

@ -12,7 +12,7 @@ fn main() {
let metrics =
to_graphite("localhost:2003")
.expect("Connecting")
.with_suffix("my_app")
.with_prefix("my_app")
.open_scope();
loop {

View File

@ -18,7 +18,7 @@ metrics!(<Aggregate> pub AGGREGATE = () => {
});
metrics!(<Aggregate> AGGREGATE.with_suffix("module_prefix") => {
metrics!(<Aggregate> AGGREGATE.with_prefix("module_prefix") => {
// create counter "module_prefix.module_counter"
Counter MOD_COUNTER: "module_counter";
});

View File

@ -22,8 +22,8 @@ app_metrics!(
Vec<String>,
SAME_TYPE = [
// combine multiple outputs of the same type by using an array
to_stdout().with_suffix("yeah"),
to_stdout().with_suffix("ouch"),
to_stdout().with_prefix("yeah"),
to_stdout().with_prefix("ouch"),
to_stdout().with_sampling_rate(0.5),
]
);
@ -31,7 +31,7 @@ app_metrics!(
#[ignore(deprecated)]
app_metrics!(
Vec<String>,
MUTANT_CHILD = SAME_TYPE.with_suffix("super").with_suffix("duper")
MUTANT_CHILD = SAME_TYPE.with_prefix("super").with_prefix("duper")
);
fn main() {

View File

@ -15,12 +15,12 @@ metrics!(<(Statsd, String)> DIFFERENT_TYPES = (
metrics!(<Vec<String>> SAME_TYPE = [
// combine multiple outputs of the same type by using an array
to_stdout().with_suffix("yeah"),
to_stdout().with_suffix("ouch"),
to_stdout().with_prefix("yeah"),
to_stdout().with_prefix("ouch"),
to_stdout().with_sampling_rate(0.5),
][..]);
metrics!(<Vec<String>> MUTANT_CHILD = SAME_TYPE.with_suffix("super").with_suffix("duper"));
metrics!(<Vec<String>> MUTANT_CHILD = SAME_TYPE.with_prefix("super").with_prefix("duper"));
fn main() {
loop {

View File

@ -17,8 +17,8 @@ fn main() {
let same_type_metrics = metric_scope(
&[
// use slices to combine multiple metrics of the same type
to_stdout().with_suffix("yeah"),
to_stdout().with_suffix("ouch"),
to_stdout().with_prefix("yeah"),
to_stdout().with_prefix("ouch"),
to_stdout().with_sampling_rate(0.5),
][..],
);

View File

@ -1,10 +1,10 @@
//! Maintain aggregated metrics for deferred reporting,
//!
use core::{command_fn, Kind, Sampling, Command, Value, Namespace};
use core::{command_fn, Kind, Sampling, Command, Value, Namespace, WithNamespace};
use clock::TimeHandle;
use core::Kind::*;
use output::{OpenScope, NO_METRIC_OUTPUT, MetricOutput};
use scope::{MetricScope, MetricInput, Flush, ScheduleFlush, DefineMetric};
use input::{MetricScope, MetricInput, Flush, ScheduleFlush, DefineMetric};
use scores::{ScoreType, Scoreboard};
use scores::ScoreType::*;
@ -39,7 +39,7 @@ impl From<&'static str> for MetricScope<Aggregate> {
fn from(prefix: &'static str) -> MetricScope<Aggregate> {
let scope: MetricScope<Aggregate> = MetricAggregator::new().into();
if !prefix.is_empty() {
scope.with_suffix(prefix)
scope.with_prefix(prefix)
} else {
scope
}
@ -69,6 +69,7 @@ struct InnerAggregator {
stats: Option<Arc<Fn(Kind, Namespace, ScoreType)
-> Option<(Kind, Namespace, Value)> + Send + Sync + 'static>>,
output: Option<Arc<OpenScope + Sync + Send>>,
publish_metadata: bool,
}
lazy_static! {
@ -98,7 +99,10 @@ impl InnerAggregator {
// TODO repeat previous frame min/max ?
// TODO update some canary metric ?
} else {
snapshot.push((&PERIOD_LENGTH, Timer, vec![Sum((duration_seconds * 1000.0) as u64)]));
// TODO add switch for metadata such as PERIOD_LENGTH
if self.publish_metadata {
snapshot.push((&PERIOD_LENGTH, Timer, vec![Sum((duration_seconds * 1000.0) as u64)]));
}
for metric in snapshot {
for score in metric.2 {
let filtered = (stats_fn)(metric.1, metric.0.clone(), score);
@ -122,6 +126,7 @@ impl MetricAggregator {
period_start: TimeHandle::now(),
stats: None,
output: None,
publish_metadata: false,
}))
}
}
@ -219,7 +224,6 @@ impl MetricAggregator {
}
impl MetricInput<Aggregate> for MetricAggregator {
/// Lookup or create a scoreboard for the requested metric.
fn define_metric(&self, name: &Namespace, kind: Kind, _rate: Sampling) -> Aggregate {
let mut zname = self.namespace.clone();
@ -237,10 +241,16 @@ impl MetricInput<Aggregate> for MetricAggregator {
fn write(&self, metric: &Aggregate, value: Value) {
metric.update(value)
}
}
fn with_suffix(&self, name: &str) -> Self {
impl WithNamespace for MetricAggregator {
fn with_namespace(&self, namespace: &Namespace) -> Self {
if namespace.is_empty() {
return self.clone()
}
MetricAggregator {
namespace: self.namespace.with_suffix(name),
namespace: self.namespace.with_namespace(namespace),
inner: self.inner.clone(),
}
}
@ -295,12 +305,12 @@ pub type Aggregate = Arc<Scoreboard>;
#[allow(dead_code)]
pub fn all_stats(kind: Kind, name: Namespace, score: ScoreType) -> Option<(Kind, Namespace, Value)> {
match score {
Count(hit) => Some((Counter, name.with_suffix("count"), hit)),
Sum(sum) => Some((kind, name.with_suffix("sum"), sum)),
Mean(mean) => Some((kind, name.with_suffix("mean"), mean.round() as Value)),
Max(max) => Some((Gauge, name.with_suffix("max"), max)),
Min(min) => Some((Gauge, name.with_suffix("min"), min)),
Rate(rate) => Some((Gauge, name.with_suffix("rate"), rate.round() as Value)),
Count(hit) => Some((Counter, name.with_prefix("count"), hit)),
Sum(sum) => Some((kind, name.with_prefix("sum"), sum)),
Mean(mean) => Some((kind, name.with_prefix("mean"), mean.round() as Value)),
Max(max) => Some((Gauge, name.with_prefix("max"), max)),
Min(min) => Some((Gauge, name.with_prefix("min"), min)),
Rate(rate) => Some((Gauge, name.with_prefix("rate"), rate.round() as Value)),
}
}
@ -352,7 +362,7 @@ mod bench {
use test;
use core::Kind::{Counter, Marker};
use aggregate::MetricAggregator;
use scope::MetricInput;
use input::MetricInput;
#[bench]
fn aggregate_marker(b: &mut test::Bencher) {
@ -390,14 +400,15 @@ mod test {
use std::time::Duration;
use std::collections::BTreeMap;
use aggregate::{MetricAggregator, all_stats, summary, average, StatsFn};
use scope::MetricInput;
use input::MetricInput;
use clock::{mock_clock_advance, mock_clock_reset};
use local::StatsMap;
use core::WithNamespace;
fn make_stats(stats_fn: &StatsFn) -> BTreeMap<String, Value> {
mock_clock_reset();
let metrics = MetricAggregator::new().with_suffix("test");
let metrics = MetricAggregator::new().with_prefix("test");
let counter = metrics.counter("counter_a");
let timer = metrics.timer("timer_a");

View File

@ -11,7 +11,7 @@ use std::sync::mpsc;
use std::thread;
metrics!{
<Aggregate> DIPSTICK_METRICS.with_suffix("async_queue") => {
<Aggregate> DIPSTICK_METRICS.with_prefix("async_queue") => {
/// Maybe queue was full?
Marker SEND_FAILED: "send_failed";
}

View File

@ -71,11 +71,9 @@ lazy_static! {
impl Namespace {
/// Append name to the namespace, returning a modified copy.
pub fn with_suffix(&self, name: impl Into<String>) -> Self {
let mut new = self.clone();
new.push(name.into());
new
/// Returns true if this namespace contains no elements.
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
/// Append a component to the name.
@ -86,7 +84,7 @@ impl Namespace {
/// Returns a copy of this namespace with the second namespace appended.
/// Both original namespaces stay untouched.
pub fn extend(&mut self, name: &Namespace) {
self.inner.extend_from_slice(&name.inner)
self.inner.extend_from_slice(&name.inner);
}
/// Returns true if the specified namespace is a subset or is equal to this namespace.
@ -122,6 +120,15 @@ impl Namespace {
}
}
impl WithNamespace for Namespace {
fn with_namespace(&self, namespace: &Namespace) -> Self {
let mut new = self.clone();
new.extend(namespace);
new
}
}
impl From<()> for Namespace {
fn from(_name: ()) -> Namespace {
ROOT_NS.clone()
@ -130,19 +137,23 @@ impl From<()> for Namespace {
impl<'a> From<&'a str> for Namespace {
fn from(name: &'a str) -> Namespace {
if name.is_empty() {
ROOT_NS.clone()
} else {
ROOT_NS.with_suffix(name)
let mut ns = ROOT_NS.clone();
if !name.is_empty() {
ns.push(name)
}
ns
}
}
impl<'a, 'b: 'a> From<&'b [&'a str]> for Namespace {
fn from(names: &'a [&'a str]) -> Namespace {
Namespace {
inner: names.iter().map(|n| n.to_string()).collect()
fn from(names: &'b [&'a str]) -> Namespace {
let mut ns = ROOT_NS.clone();
for name in names {
if !name.is_empty() {
ns.push(*name)
}
}
ns
}
}
@ -151,11 +162,25 @@ impl From<String> for Namespace {
if name.is_empty() {
ROOT_NS.clone()
} else {
ROOT_NS.with_suffix(name.as_ref())
ROOT_NS.with_prefix(name.as_ref())
}
}
}
/// Common methods of elements that hold a mutable namespace.
pub trait WithNamespace: Sized {
/// Return a copy of this object with the specified namespace appended to the existing one.
fn with_namespace(&self, namespace: &Namespace) -> Self;
/// Join namespace and prepend in newly defined metrics.
// #[deprecated(since = "0.7.0", note = "Misleading terminology, use with_namespace() instead.")]
fn with_prefix(&self, name: &str) -> Self {
self.with_namespace(&name.into())
}
}
/// Dynamic metric definition function.
/// Metrics can be defined from any thread, concurrently (Fn is Sync).
/// The resulting metrics themselves can be also be safely shared across threads (<M> is Send + Sync).
@ -170,11 +195,19 @@ pub type OpenScopeFn<M> = Arc<Fn() -> CommandFn<M> + Send + Sync>;
pub type WriteFn = Arc<Fn(Value) + Send + Sync + 'static>;
/// A function trait that writes to or flushes a certain scope.
#[derive(Clone)]
//#[derive(Clone)]
pub struct CommandFn<M> {
inner: Arc<Fn(Command<M>) + Send + Sync + 'static>
}
impl<M> Clone for CommandFn<M> {
fn clone(&self) -> CommandFn<M> {
CommandFn {
inner: self.inner.clone()
}
}
}
/// An method dispatching command enum to manipulate metric scopes.
/// Replaces a potential `Writer` trait that would have methods `write` and `flush`.
/// Using a command pattern allows buffering, async queuing and inline definition of writers.

View File

@ -1,4 +1,4 @@
use scope::{Marker, Counter, Gauge, Timer, MetricScope};
use input::{Marker, Counter, Gauge, Timer, MetricScope};
use output::MetricOutput;
use core::{Sampling, Namespace, Kind, Value};
use aggregate::MetricAggregator;
@ -211,7 +211,7 @@ macro_rules! mod_timer {
mod legacy_test {
use self_metrics::*;
metrics!(<Aggregate> TEST_METRICS = DIPSTICK_METRICS.with_suffix("test_prefix"));
metrics!(<Aggregate> TEST_METRICS = DIPSTICK_METRICS.with_prefix("test_prefix"));
app_marker!(<Aggregate> TEST_METRICS => {
M1: "failed",

View File

@ -1,7 +1,7 @@
//! Decouple metric definition from configuration with trait objects.
use core::*;
use scope::{DefineMetric, MetricScope, MetricInput, Flush, ScheduleFlush, NO_METRIC_SCOPE};
use input::{DefineMetric, MetricScope, MetricInput, Flush, ScheduleFlush, NO_METRIC_SCOPE};
use std::collections::{HashMap, BTreeMap};
use std::sync::{Arc, RwLock, Weak};
@ -68,7 +68,7 @@ struct InnerDispatch {
/// Allow turning a 'static str into a Delegate, where str is the prefix.
impl From<&'static str> for MetricScope<Dispatch> {
fn from(name: &'static str) -> MetricScope<Dispatch> {
metric_dispatch().into_scope().with_suffix(name)
metric_dispatch().into_scope().with_prefix(name)
}
}
@ -212,7 +212,6 @@ impl MetricDispatch {
}
impl MetricInput<Dispatch> for MetricDispatch {
/// Lookup or create a dispatch stub for the requested metric.
fn define_metric(&self, name: &Namespace, kind: Kind, rate: Sampling) -> Dispatch {
let mut zname = self.namespace.clone();
@ -245,13 +244,16 @@ impl MetricInput<Dispatch> for MetricDispatch {
fn write(&self, metric: &Dispatch, value: Value) {
metric.write_metric.borrow().0(value);
}
}
fn with_suffix(&self, name: &str) -> Self {
if name.is_empty() {
impl WithNamespace for MetricDispatch {
fn with_namespace(&self, namespace: &Namespace) -> Self {
if namespace.is_empty() {
return self.clone()
}
MetricDispatch {
namespace: self.namespace.with_suffix(name),
namespace: self.namespace.with_namespace(namespace),
inner: self.inner.clone()
}
}
@ -279,7 +281,7 @@ mod bench {
use dispatch::metric_dispatch;
use test;
use aggregate::MetricAggregator;
use scope::MetricInput;
use input::MetricInput;
#[bench]
fn dispatch_marker_to_aggregate(b: &mut test::Bencher) {

View File

@ -15,13 +15,21 @@ use std::fmt::Debug;
use socket::RetrySocket;
metrics!{
<Aggregate> DIPSTICK_METRICS.with_suffix("graphite") => {
<Aggregate> DIPSTICK_METRICS.with_prefix("graphite") => {
Marker SEND_ERR: "send_failed";
Marker TRESHOLD_EXCEEDED: "bufsize_exceeded";
Counter SENT_BYTES: "sent_bytes";
}
}
//pub struct GraphiteOutput {
// socket: Arc<RwLock<RetrySocket>>,
//}
//
//impl MetricOutput for GraphiteOutput {
//
//}
// TODO enable fine config
//struct GraphiteConfig<ADDR = ToSocketAddrs + Debug + Clone> {
// to_socket_address: ADDR,

View File

@ -7,7 +7,7 @@
//!
//! If multiple [AppMetrics] are defined, they'll each have their scope.
//!
use core::{Value, Sampling, WriteFn, Namespace, Kind, DefineMetricFn, CommandFn};
use core::{Value, Sampling, WriteFn, Namespace, Kind, DefineMetricFn, CommandFn, WithNamespace};
use core::Kind::*;
use clock::TimeHandle;
use cache::{add_cache, WithCache};
@ -31,7 +31,8 @@ pub trait DefineMetric: Flush {
/// 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_object(&self, namespace: &Namespace, kind: Kind, rate: Sampling) -> WriteFn;
fn define_metric_object(&self, name: &Namespace, kind: Kind, rate: Sampling) -> WriteFn;
}
///// Dynamic counterpart of the `DispatcherMetric`.
@ -177,13 +178,13 @@ fn scope_write_fn<M, D>(scope: &D, kind: Kind, name: &str) -> WriteFn
M: Clone + Send + Sync + 'static,
D: MetricInput<M> + Clone + Send + Sync + 'static
{
let scope = scope.clone();
let scope1 = scope.clone();
let metric = scope.define_metric(&name.into(), kind, 1.0);
Arc::new(move |value| scope.write(&metric, value))
Arc::new(move |value| scope1.write(&metric, value))
}
/// Define metrics, write values and flush them.
pub trait MetricInput<M>: Clone + Send + Sync + 'static + Flush
pub trait MetricInput<M>: Clone + Send + Sync + 'static + Flush + WithNamespace
where
M: Clone + Send + Sync + 'static,
{
@ -213,15 +214,6 @@ pub trait MetricInput<M>: Clone + Send + Sync + 'static + Flush
/// Record or send a value for a previously defined metric.
fn write(&self, metric: &M, value: Value);
/// Join namespace and prepend in newly defined metrics.
#[deprecated(since = "0.7.0", note = "Misleading terminology, use with_suffix() instead.")]
fn with_prefix(&self, name: &str) -> Self {
self.with_suffix(name)
}
/// Join namespace and prepend in newly defined metrics.
fn with_suffix(&self, name: &str) -> Self;
}
/// Scopes can implement buffering, requiring flush operations to commit metric values.
@ -236,18 +228,21 @@ impl<M> MetricInput<M> for MetricScope<M>
where
M: Clone + Send + Sync + 'static,
{
fn define_metric(&self, namespace: &Namespace, kind: Kind, rate: Sampling) -> M {
(self.define_fn)(namespace, kind, rate)
let name = self.namespace.with_namespace(namespace);
(self.define_fn)(&name, kind, rate)
}
fn write(&self, metric: &M, value: Value) {
self.command_fn.write(metric, value);
}
}
fn with_suffix(&self, name: &str) -> Self {
impl<M> WithNamespace for MetricScope<M> {
fn with_namespace(&self, namespace: &Namespace) -> Self {
MetricScope {
namespace: self.namespace.with_suffix(name),
namespace: self.namespace.with_namespace(namespace),
define_fn: self.define_fn.clone(),
command_fn: self.command_fn.clone(),
}

View File

@ -25,7 +25,7 @@ pub use error::{Error, Result};
pub mod macros;
pub mod core;
pub use core::{Value, Sampling, FULL_SAMPLING_RATE, Kind, ROOT_NS, Namespace};
pub use core::{Value, Sampling, FULL_SAMPLING_RATE, Kind, ROOT_NS, Namespace, WithNamespace};
pub mod output;
pub use output::{MetricOutput, NO_METRIC_OUTPUT, OpenScope};
@ -39,8 +39,8 @@ pub use aggregate::{MetricAggregator, Aggregate, summary, all_stats, average};
mod local;
pub use local::{StatsMap, to_buffered_log, to_buffered_stdout, to_log, to_stdout, to_void};
mod scope;
pub use scope::{Marker, Timer, Counter, Gauge, MetricInput, MetricScope, Flush, ScheduleFlush, DefineMetric, metric_scope};
mod input;
pub use input::{Marker, Timer, Counter, Gauge, MetricInput, MetricScope, Flush, ScheduleFlush, DefineMetric, metric_scope};
mod sample;
pub use sample::WithSamplingRate;

View File

@ -2,9 +2,9 @@
// TODO parameterize templates
// TODO define backing structs that can flush() on Drop
use core::{ROOT_NS, Namespace, Sampling, Value, WriteFn, Kind, command_fn, Command};
use core::{ROOT_NS, Namespace, Sampling, Value, WriteFn, Kind, command_fn, Command, WithNamespace};
use output::{MetricOutput, metric_output};
use scope::{MetricInput, DefineMetric, Flush};
use input::{MetricInput, DefineMetric, Flush};
use std::sync::RwLock;
use std::collections::BTreeMap;
use std::sync::Arc;
@ -50,7 +50,6 @@ impl Flush for StatsMap {}
impl MetricInput<Namespace> for StatsMap {
fn define_metric(&self, name: &Namespace, _kind: Kind, _rate: Sampling) -> Namespace {
name.clone()
}
@ -58,10 +57,16 @@ impl MetricInput<Namespace> for StatsMap {
fn write(&self, metric: &Namespace, value: Value) {
self.map.write().expect("StatsMap").insert(metric.clone(), value);
}
}
fn with_suffix(&self, name: &str) -> Self {
impl WithNamespace for StatsMap {
fn with_namespace(&self, namespace: &Namespace) -> Self {
if namespace.is_empty() {
return self.clone()
}
Self {
namespace: self.namespace.with_suffix(name),
namespace: self.namespace.with_namespace(namespace),
map: self.map.clone(),
}
}
@ -168,7 +173,7 @@ pub fn to_void() -> MetricOutput<()> {
#[cfg(test)]
mod test {
use core::*;
use scope::MetricInput;
use input::MetricInput;
#[test]
fn sink_print() {

View File

@ -135,7 +135,7 @@ macro_rules! __metrics_block {
mod test {
use self_metrics::*;
metrics!(<Aggregate> DIPSTICK_METRICS.with_suffix("test_prefix") => {
metrics!(<Aggregate> DIPSTICK_METRICS.with_prefix("test_prefix") => {
Marker M1: "failed";
Marker M2: "success";
Counter C1: "failed";

View File

@ -2,7 +2,7 @@
use core::*;
use output::*;
use scope::*;
use input::*;
use std::sync::Arc;

View File

@ -1,12 +1,12 @@
//! Chain of command for unscoped metrics.
use core::*;
use scope::MetricScope;
use input::MetricScope;
use std::sync::Arc;
use std::fmt::Debug;
use scope::DefineMetric;
use input::DefineMetric;
use local;
lazy_static! {
@ -66,9 +66,9 @@ where
impl<M: Send + Sync + Clone + 'static> MetricOutput<M> {
/// Intercept both metric definition and scope creation, possibly changing the metric type.
pub fn wrap_all<MF, N>(&self, mod_fn: MF) -> MetricOutput<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 (define_metric_fn, open_scope_fn) =
mod_fn(self.define_metric_fn.clone(), self.open_scope_fn.clone());
@ -81,8 +81,8 @@ impl<M: Send + Sync + Clone + 'static> MetricOutput<M> {
/// Intercept scope creation.
pub fn wrap_scope<MF>(&self, mod_fn: MF) -> Self
where
MF: Fn(OpenScopeFn<M>) -> OpenScopeFn<M>,
where
MF: Fn(OpenScopeFn<M>) -> OpenScopeFn<M>,
{
MetricOutput {
namespace: self.namespace.clone(),
@ -90,23 +90,19 @@ impl<M: Send + Sync + Clone + 'static> MetricOutput<M> {
open_scope_fn: mod_fn(self.open_scope_fn.clone()),
}
}
}
impl<M> WithNamespace for MetricOutput<M> {
/// Return cloned output with appended namespace.
pub fn with_namespace(&self, names: impl Into<Namespace>) -> Self {
let mut namespace = self.namespace.clone();
namespace.extend(&names.into());
fn with_namespace(&self, namespace: &Namespace) -> Self {
MetricOutput {
namespace,
namespace: self.namespace.with_namespace(namespace),
define_metric_fn: self.define_metric_fn.clone(),
open_scope_fn: self.open_scope_fn.clone(),
}
}
/// Return a copy of this output with the specified name appended to the namespace.
pub fn with_suffix(&self, name: &str) -> Self {
self.with_namespace(name)
}
}
//impl<'a, M: Send + Sync + Clone + 'static> Index<&'a str> for MetricOutput<M> {
@ -125,7 +121,7 @@ impl<M: Send + Sync + Clone + 'static> OpenScope for MetricOutput<M> {
impl<M> From<MetricOutput<M>> for MetricScope<M> {
fn from(metrics: MetricOutput<M>) -> MetricScope<M> {
metrics.open_scope()
metrics.open_scope().with_namespace(&metrics.namespace)
}
}

View File

@ -16,7 +16,7 @@ use std::fmt::Debug;
use socket::RetrySocket;
metrics!{
<Aggregate> DIPSTICK_METRICS.with_suffix("prometheus") => {
<Aggregate> DIPSTICK_METRICS.with_prefix("prometheus") => {
Marker SEND_ERR: "send_failed";
Marker TRESHOLD_EXCEEDED: "bufsize_exceeded";
Counter SENT_BYTES: "sent_bytes";

View File

@ -4,7 +4,7 @@
pub use core::*;
pub use scope::*;
pub use input::*;
pub use aggregate::*;
metrics!(

View File

@ -11,7 +11,7 @@ use std::sync::{Arc, RwLock};
pub use std::net::ToSocketAddrs;
metrics! {
<Aggregate> DIPSTICK_METRICS.with_suffix("statsd") => {
<Aggregate> DIPSTICK_METRICS.with_prefix("statsd") => {
Marker SEND_ERR: "send_failed";
Counter SENT_BYTES: "sent_bytes";
}