From 35c90336b7dd65f737a616ded6a5f8eccc2b9ddb Mon Sep 17 00:00:00 2001 From: Francis Lalonde Date: Fri, 14 Sep 2018 06:47:31 -0400 Subject: [PATCH] Move to subs, break core --- README.md | 0 examples/custom_publish.rs | 0 examples/raw_log.rs | 0 src/{ => aggregate}/bucket.rs | 58 +- src/aggregate/mod.rs | 2 + src/{ => aggregate}/scores.rs | 25 +- src/cache/cache_in.rs | 93 + src/cache/cache_out.rs | 96 + src/cache/lru_cache.rs | 170 ++ src/cache/mod.rs | 3 + src/cache_in.rs | 263 --- src/cache_out.rs | 264 --- src/core.rs | 686 -------- src/{ => core}/clock.rs | 3 +- src/core/component.rs | 220 +++ src/{ => core}/error.rs | 4 +- src/core/input.rs | 224 +++ src/{ => core}/metrics.rs | 5 +- src/core/mod.rs | 58 + src/core/out_lock.rs | 69 + src/core/output.rs | 62 + src/{ => core}/pcg32.rs | 2 +- src/{ => core}/proxy.rs | 16 +- src/{ => core}/scheduler.rs | 2 +- src/core/void.rs | 49 + src/lib.rs | 105 +- src/macros.rs | 4 +- src/multi/mod.rs | 3 + src/{ => multi}/multi_in.rs | 7 +- src/{ => multi}/multi_out.rs | 8 +- src/{ => output}/graphite.rs | 16 +- src/{ => output}/logging.rs | 20 +- src/{ => output}/map.rs | 6 +- src/output/mod.rs | 17 + src/{ => output}/prometheus.rs | 7 +- src/output/prometheus_proto.rs | 2533 +++++++++++++++++++++++++++ src/{ => output}/socket.rs | 0 src/{statds.rs => output/statsd.rs} | 19 +- src/{ => output}/text.rs | 20 +- src/queue/mod.rs | 2 + src/{ => queue}/queue_in.rs | 14 +- src/{ => queue}/queue_out.rs | 52 +- 42 files changed, 3812 insertions(+), 1395 deletions(-) mode change 100644 => 100755 README.md mode change 100644 => 100755 examples/custom_publish.rs mode change 100644 => 100755 examples/raw_log.rs rename src/{ => aggregate}/bucket.rs (87%) create mode 100755 src/aggregate/mod.rs rename src/{ => aggregate}/scores.rs (92%) create mode 100755 src/cache/cache_in.rs create mode 100755 src/cache/cache_out.rs create mode 100755 src/cache/lru_cache.rs create mode 100755 src/cache/mod.rs delete mode 100755 src/cache_in.rs delete mode 100755 src/cache_out.rs delete mode 100755 src/core.rs rename src/{ => core}/clock.rs (96%) mode change 100644 => 100755 create mode 100755 src/core/component.rs rename src/{ => core}/error.rs (97%) create mode 100755 src/core/input.rs rename src/{ => core}/metrics.rs (88%) create mode 100755 src/core/mod.rs create mode 100755 src/core/out_lock.rs create mode 100755 src/core/output.rs rename src/{ => core}/pcg32.rs (96%) rename src/{ => core}/proxy.rs (95%) rename src/{ => core}/scheduler.rs (98%) create mode 100755 src/core/void.rs create mode 100755 src/multi/mod.rs rename src/{ => multi}/multi_in.rs (95%) rename src/{ => multi}/multi_out.rs (93%) rename src/{ => output}/graphite.rs (95%) rename src/{ => output}/logging.rs (93%) rename src/{ => output}/map.rs (90%) create mode 100755 src/output/mod.rs rename src/{ => output}/prometheus.rs (83%) create mode 100755 src/output/prometheus_proto.rs rename src/{ => output}/socket.rs (100%) mode change 100644 => 100755 rename src/{statds.rs => output/statsd.rs} (95%) rename src/{ => output}/text.rs (93%) create mode 100755 src/queue/mod.rs rename src/{ => queue}/queue_in.rs (94%) rename src/{ => queue}/queue_out.rs (77%) diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/examples/custom_publish.rs b/examples/custom_publish.rs old mode 100644 new mode 100755 diff --git a/examples/raw_log.rs b/examples/raw_log.rs old mode 100644 new mode 100755 diff --git a/src/bucket.rs b/src/aggregate/bucket.rs similarity index 87% rename from src/bucket.rs rename to src/aggregate/bucket.rs index 07a1472..7896203 100755 --- a/src/bucket.rs +++ b/src/aggregate/bucket.rs @@ -1,13 +1,12 @@ //! Maintain aggregated metrics for deferred reporting, -//! -use core::{Kind, Value, Name, AddPrefix, output_none, InputScope, InputMetric, WithAttributes, Attributes, - OutputScope, OutputMetric, Output, Flush, OutputDyn}; -use clock::TimeHandle; -use core::Kind::*; -use error; -use scores::{ScoreType, Scoreboard}; -use scores::ScoreType::*; +use core::component::{Attributes, Name, WithAttributes, AddPrefix}; +use core::input::{Kind, InputScope, InputMetric}; +use core::output::{OutputDyn, OutputScope, OutputMetric, Output, output_none}; +use core::clock::TimeHandle; +use core::{Value, Flush}; +use aggregate::scores::{Scoreboard, ScoreType}; +use core::error; use std::collections::BTreeMap; use std::sync::{Arc, RwLock}; @@ -112,7 +111,7 @@ impl InnerBucket { } else { // 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)])); + snapshot.push((&PERIOD_LENGTH, Kind::Timer, vec![ScoreType::Sum((duration_seconds * 1000.0) as u64)])); } for metric in snapshot { for score in metric.2 { @@ -237,12 +236,12 @@ impl WithAttributes for Bucket { #[allow(dead_code)] pub fn stats_all(kind: Kind, name: Name, score: ScoreType) -> Option<(Kind, Name, Value)> { match score { - Count(hit) => Some((Counter, name.concat("count"), hit)), - Sum(sum) => Some((kind, name.concat("sum"), sum)), - Mean(mean) => Some((kind, name.concat("mean"), mean.round() as Value)), - Max(max) => Some((Gauge, name.concat("max"), max)), - Min(min) => Some((Gauge, name.concat("min"), min)), - Rate(rate) => Some((Gauge, name.concat("rate"), rate.round() as Value)), + ScoreType::Count(hit) => Some((Kind::Counter, name.concat("count"), hit)), + ScoreType::Sum(sum) => Some((kind, name.concat("sum"), sum)), + ScoreType::Mean(mean) => Some((kind, name.concat("mean"), mean.round() as Value)), + ScoreType::Max(max) => Some((Kind::Gauge, name.concat("max"), max)), + ScoreType::Min(min) => Some((Kind::Gauge, name.concat("min"), min)), + ScoreType::Rate(rate) => Some((Kind::Gauge, name.concat("rate"), rate.round() as Value)), } } @@ -253,12 +252,12 @@ pub fn stats_all(kind: Kind, name: Name, score: ScoreType) -> Option<(Kind, Name #[allow(dead_code)] pub fn stats_average(kind: Kind, name: Name, score: ScoreType) -> Option<(Kind, Name, Value)> { match kind { - Marker => match score { - Count(count) => Some((Counter, name, count)), + Kind::Marker => match score { + ScoreType::Count(count) => Some((Kind::Counter, name, count)), _ => None, }, _ => match score { - Mean(avg) => Some((Gauge, name, avg.round() as Value)), + ScoreType::Mean(avg) => Some((Kind::Gauge, name, avg.round() as Value)), _ => None, }, } @@ -273,16 +272,16 @@ pub fn stats_average(kind: Kind, name: Name, score: ScoreType) -> Option<(Kind, #[allow(dead_code)] pub fn stats_summary(kind: Kind, name: Name, score: ScoreType) -> Option<(Kind, Name, Value)> { match kind { - Marker => match score { - Count(count) => Some((Counter, name, count)), + Kind::Marker => match score { + ScoreType::Count(count) => Some((Kind::Counter, name, count)), _ => None, }, - Counter | Timer => match score { - Sum(sum) => Some((kind, name, sum)), + Kind::Counter | Kind::Timer => match score { + ScoreType::Sum(sum) => Some((kind, name, sum)), _ => None, }, - Gauge => match score { - Mean(mean) => Some((Gauge, name, mean.round() as Value)), + Kind::Gauge => match score { + ScoreType::Mean(mean) => Some((Kind::Gauge, name, mean.round() as Value)), _ => None, }, } @@ -292,8 +291,8 @@ pub fn stats_summary(kind: Kind, name: Name, score: ScoreType) -> Option<(Kind, mod bench { use test; - use core::*; - use bucket::Bucket; + use core::clock::*; + use super::*; #[bench] fn aggregate_marker(b: &mut test::Bencher) { @@ -313,10 +312,9 @@ mod bench { #[cfg(test)] mod test { - use core::*; - use bucket::{Bucket, stats_all, stats_summary, stats_average, StatsFn}; - use clock::{mock_clock_advance, mock_clock_reset}; - use map::StatsMap; + use super::*; + use core::clock::{mock_clock_advance, mock_clock_reset}; + use output::map::StatsMap; use std::time::Duration; use std::collections::BTreeMap; diff --git a/src/aggregate/mod.rs b/src/aggregate/mod.rs new file mode 100755 index 0000000..e4ffd80 --- /dev/null +++ b/src/aggregate/mod.rs @@ -0,0 +1,2 @@ +pub mod bucket; +pub mod scores; diff --git a/src/scores.rs b/src/aggregate/scores.rs similarity index 92% rename from src/scores.rs rename to src/aggregate/scores.rs index b51057f..0e3ac72 100755 --- a/src/scores.rs +++ b/src/aggregate/scores.rs @@ -1,8 +1,7 @@ +use core::input::Kind; +use core::Value; + use std::mem; - -use core::*; -use core::Kind::*; - use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::*; use std::usize; @@ -61,7 +60,7 @@ impl Scoreboard { let value = value as usize; self.scores[0].fetch_add(1, AcqRel); match self.kind { - Marker => {} + Kind::Marker => {} _ => { // optimization - these fields are unused for Marker stats self.scores[1].fetch_add(value, AcqRel); @@ -94,16 +93,16 @@ impl Scoreboard { let mut snapshot = Vec::new(); match self.kind { - Marker => { + Kind::Marker => { snapshot.push(Count(scores[0] as u64)); snapshot.push(Rate(scores[0] as f64 / duration_seconds)) } - Gauge => { + Kind::Gauge => { snapshot.push(Max(scores[2] as u64)); snapshot.push(Min(scores[3] as u64)); snapshot.push(Mean(scores[1] as f64 / scores[0] as f64)); } - Timer => { + Kind::Timer => { snapshot.push(Count(scores[0] as u64)); snapshot.push(Sum(scores[1] as u64)); @@ -113,7 +112,7 @@ impl Scoreboard { // timer rate uses the COUNT of timer calls per second (not SUM) snapshot.push(Rate(scores[0] as f64 / duration_seconds)) } - Counter => { + Kind::Counter => { snapshot.push(Count(scores[0] as u64)); snapshot.push(Sum(scores[1] as u64)); @@ -148,24 +147,26 @@ fn swap_if(counter: &AtomicUsize, new_value: usize, compare: fn(usize, usize) -> #[cfg(feature = "bench")] mod bench { + use core::input::Kind; + use super::*; use test; #[bench] fn update_marker(b: &mut test::Bencher) { - let metric = Scoreboard::new(Marker); + let metric = Scoreboard::new(Kind::Marker); b.iter(|| test::black_box(metric.update(1))); } #[bench] fn update_count(b: &mut test::Bencher) { - let metric = Scoreboard::new(Counter); + let metric = Scoreboard::new(Kind::Counter); b.iter(|| test::black_box(metric.update(4))); } #[bench] fn empty_snapshot(b: &mut test::Bencher) { - let metric = Scoreboard::new(Counter); + let metric = Scoreboard::new(Kind::Counter); let scores = &mut Scoreboard::blank(); b.iter(|| test::black_box(metric.snapshot(scores))); } diff --git a/src/cache/cache_in.rs b/src/cache/cache_in.rs new file mode 100755 index 0000000..4a2af9c --- /dev/null +++ b/src/cache/cache_in.rs @@ -0,0 +1,93 @@ +//! Cache metric definitions. + +use core::Flush; +use core::input::{Kind, Input, InputScope, InputMetric, InputDyn}; +use core::component::{Attributes, WithAttributes, Name, AddPrefix}; +use cache::lru_cache as lru; +use core::error; + +use std::sync::{Arc, RwLock}; + +/// Wrap an output with a metric definition cache. +/// This is useless if all metrics are statically declared but can provide performance +/// benefits if some metrics are dynamically defined at runtime. +pub trait CachedInput: Input + Send + Sync + 'static + Sized { + /// Wrap this output with an asynchronous dispatch queue of specified length. + fn cached(self, max_size: usize) -> InputCache { + InputCache::wrap(self, max_size) + } +} + +/// Output wrapper caching frequently defined metrics +#[derive(Clone)] +pub struct InputCache { + attributes: Attributes, + target: Arc, + cache: Arc>>, +} + +impl InputCache { + /// Wrap scopes with an asynchronous metric write & flush dispatcher. + pub fn wrap(target: OUT, max_size: usize) -> InputCache { + InputCache { + attributes: Attributes::default(), + target: Arc::new(target), + cache: Arc::new(RwLock::new(lru::LRUCache::with_capacity(max_size))) + } + } +} + +impl WithAttributes for InputCache { + fn get_attributes(&self) -> &Attributes { &self.attributes } + fn mut_attributes(&mut self) -> &mut Attributes { &mut self.attributes } +} + +impl Input for InputCache { + type SCOPE = InputScopeCache; + + fn input(&self) -> Self::SCOPE { + let target = self.target.input_dyn(); + InputScopeCache { + attributes: self.attributes.clone(), + target, + cache: self.cache.clone(), + } + } +} + +/// Input wrapper caching frequently defined metrics +#[derive(Clone)] +pub struct InputScopeCache { + attributes: Attributes, + target: Arc, + cache: Arc>>, +} + +impl WithAttributes for InputScopeCache { + fn get_attributes(&self) -> &Attributes { &self.attributes } + fn mut_attributes(&mut self) -> &mut Attributes { &mut self.attributes } +} + +impl InputScope for InputScopeCache { + fn new_metric(&self, name: Name, kind: Kind) -> InputMetric { + let name = self.qualified_name(name); + let lookup = { + let mut cache = self.cache.write().expect("Cache Lock"); + cache.get(&name).map(|found| found.clone()) + }; + lookup.unwrap_or_else(|| { + let new_metric = self.target.new_metric(name.clone(), kind); + // FIXME (perf) having to take another write lock for a cache miss + let mut cache_miss = self.cache.write().expect("Cache Lock"); + cache_miss.insert(name, new_metric.clone()); + new_metric + }) + } +} + +impl Flush for InputScopeCache { + + fn flush(&self) -> error::Result<()> { + self.target.flush() + } +} diff --git a/src/cache/cache_out.rs b/src/cache/cache_out.rs new file mode 100755 index 0000000..7214253 --- /dev/null +++ b/src/cache/cache_out.rs @@ -0,0 +1,96 @@ +//! Cache metric definitions. + +use core::Flush; +use core::component::{Attributes, WithAttributes, Name, AddPrefix}; +use core::output::{Output, OutputMetric, OutputScope, OutputDyn}; +use core::input::Kind; +use cache::lru_cache as lru; +use core::error; + +use std::sync::{Arc, RwLock}; +use std::rc::Rc; + +/// Wrap an output with a metric definition cache. +/// This is useless if all metrics are statically declared but can provide performance +/// benefits if some metrics are dynamically defined at runtime. +pub trait CachedOutput: Output + Send + Sync + 'static + Sized { + /// Wrap this output with an asynchronous dispatch queue of specified length. + fn cached(self, max_size: usize) -> OutputCache { + OutputCache::wrap(self, max_size) + } +} + +/// Output wrapper caching frequently defined metrics +#[derive(Clone)] +pub struct OutputCache { + attributes: Attributes, + target: Arc, + cache: Arc>>, +} + +impl OutputCache { + /// Wrap scopes with an asynchronous metric write & flush dispatcher. + pub fn wrap(target: OUT, max_size: usize) -> OutputCache { + OutputCache { + attributes: Attributes::default(), + target: Arc::new(target), + cache: Arc::new(RwLock::new(lru::LRUCache::with_capacity(max_size))) + } + } +} + +impl WithAttributes for OutputCache { + fn get_attributes(&self) -> &Attributes { &self.attributes } + fn mut_attributes(&mut self) -> &mut Attributes { &mut self.attributes } +} + +impl Output for OutputCache { + type SCOPE = OutputScopeCache; + + fn output(&self) -> Self::SCOPE { + let target = self.target.output_dyn(); + OutputScopeCache { + attributes: self.attributes.clone(), + target, + cache: self.cache.clone(), + } + } +} + +/// Output wrapper caching frequently defined metrics +#[derive(Clone)] +pub struct OutputScopeCache { + attributes: Attributes, + target: Rc, + cache: Arc>>, +} + +impl WithAttributes for OutputScopeCache { + fn get_attributes(&self) -> &Attributes { &self.attributes } + fn mut_attributes(&mut self) -> &mut Attributes { &mut self.attributes } +} + +impl OutputScope for OutputScopeCache { + fn new_metric(&self, name: Name, kind: Kind) -> OutputMetric { + let name = self.qualified_name(name); + let lookup = { + let mut cache = self.cache.write().expect("Cache Lock"); + cache.get(&name).map(|found| found.clone()) + }; + lookup.unwrap_or_else(|| { + let new_metric: OutputMetric = self.target.new_metric(name.clone(), kind); + // FIXME (perf) having to take another write lock for a cache miss + let mut cache_miss = self.cache.write().expect("Cache Lock"); + cache_miss.insert(name, new_metric.clone()); + new_metric + }) + } +} + +impl Flush for OutputScopeCache { + + fn flush(&self) -> error::Result<()> { + self.target.flush() + } +} + diff --git a/src/cache/lru_cache.rs b/src/cache/lru_cache.rs new file mode 100755 index 0000000..b1ef71c --- /dev/null +++ b/src/cache/lru_cache.rs @@ -0,0 +1,170 @@ + //! A fixed-size cache with LRU expiration criteria. + //! Stored values will be held onto as long as there is space. + //! When space runs out, the oldest unused value will get evicted to make room for a new value. + +use std::hash::Hash; +use std::collections::HashMap; + +struct CacheEntry { + key: K, + value: Option, + next: Option, + prev: Option, +} + +/// A fixed-size cache. +pub struct LRUCache { + table: HashMap, + entries: Vec>, + first: Option, + last: Option, + capacity: usize, +} + +impl LRUCache { + /// Creates a new cache that can hold the specified number of elements. + pub fn with_capacity(size: usize) -> Self { + LRUCache { + table: HashMap::with_capacity(size), + entries: Vec::with_capacity(size), + first: None, + last: None, + capacity: size, + } + } + + /// Inserts a key-value pair into the cache and returns the previous value, if any. + /// If there is no room in the cache the oldest item will be removed. + pub fn insert(&mut self, key: K, value: V) -> Option { + if self.table.contains_key(&key) { + self.access(&key); + let entry = &mut self.entries[self.first.unwrap()]; + let old = entry.value.take(); + entry.value = Some(value); + old + } else { + self.ensure_room(); + // Update old head + let idx = self.entries.len(); + self.first.map(|e| { + let prev = Some(idx); + self.entries[e].prev = prev; + }); + // This is the new head + self.entries.push(CacheEntry { + key: key.clone(), + value: Some(value), + next: self.first, + prev: None, + }); + self.first = Some(idx); + self.last = self.last.or(self.first); + self.table.insert(key, idx); + None + } + } + + /// Retrieves a reference to the item associated with `key` from the cache + /// without promoting it. + pub fn peek(&mut self, key: &K) -> Option<&V> { + let entries = &self.entries; + self.table + .get(key) + .and_then(move |i| entries[*i].value.as_ref()) + } + + /// Retrieves a reference to the item associated with `key` from the cache. + pub fn get(&mut self, key: &K) -> Option<&V> { + if self.contains_key(key) { + self.access(key); + } + self.peek(key) + } + + /// Returns the number of elements currently in the cache. + pub fn len(&self) -> usize { + self.table.len() + } + + /// Promotes the specified key to the top of the cache. + fn access(&mut self, key: &K) { + let i = *self.table.get(key).unwrap(); + self.remove_from_list(i); + self.first = Some(i); + } + + pub fn contains_key(&mut self, key: &K) -> bool { + self.table.contains_key(key) + } + + /// Removes an item from the linked list. + fn remove_from_list(&mut self, i: usize) { + let (prev, next) = { + let entry = &mut self.entries[i]; + (entry.prev, entry.next) + }; + match (prev, next) { + // Item was in the middle of the list + (Some(j), Some(k)) => { + { + let first = &mut self.entries[j]; + first.next = next; + } + let second = &mut self.entries[k]; + second.prev = prev; + } + // Item was at the end of the list + (Some(j), None) => { + let first = &mut self.entries[j]; + first.next = None; + self.last = prev; + } + // Item was at front + _ => (), + } + } + + fn ensure_room(&mut self) { + if self.capacity == self.len() { + self.remove_last(); + } + } + + /// Removes the oldest item in the cache. + fn remove_last(&mut self) { + if let Some(idx) = self.last { + self.remove_from_list(idx); + let key = &self.entries[idx].key; + self.table.remove(key); + } + if self.last.is_none() { + self.first = None; + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn get_and_get_mut_promote() { + let mut cache: LRUCache<&str, _> = LRUCache::with_capacity(2); + cache.insert("foo", 1); + cache.insert("bar", 2); + + cache.get(&"foo").unwrap(); + cache.insert("baz", 3); + + assert!(cache.contains_key(&"foo")); + assert!(cache.contains_key(&"baz")); + assert!(!cache.contains_key(&"bar")); + + cache.get(&"foo").unwrap(); + cache.insert("qux", 4); + + assert!(cache.contains_key(&"foo")); + assert!(cache.contains_key(&"qux")); + assert!(!cache.contains_key(&"baz")); + } +} diff --git a/src/cache/mod.rs b/src/cache/mod.rs new file mode 100755 index 0000000..a19958e --- /dev/null +++ b/src/cache/mod.rs @@ -0,0 +1,3 @@ +pub mod lru_cache; +pub mod cache_out; +pub mod cache_in; diff --git a/src/cache_in.rs b/src/cache_in.rs deleted file mode 100755 index fd3c02b..0000000 --- a/src/cache_in.rs +++ /dev/null @@ -1,263 +0,0 @@ -//! Cache metric definitions. - -use core::{Input, InputDyn, WithAttributes, Attributes, InputScope, InputMetric, Name, Flush, Kind, AddPrefix}; -use error; -use std::sync::{Arc, RwLock}; - -/// Wrap an output with a metric definition cache. -/// This is useless if all metrics are statically declared but can provide performance -/// benefits if some metrics are dynamically defined at runtime. -pub trait CachedInput: Input + Send + Sync + 'static + Sized { - /// Wrap this output with an asynchronous dispatch queue of specified length. - fn cached(self, max_size: usize) -> InputCache { - InputCache::wrap(self, max_size) - } -} - -/// Output wrapper caching frequently defined metrics -#[derive(Clone)] -pub struct InputCache { - attributes: Attributes, - target: Arc, - cache: Arc>>, -} - -impl InputCache { - /// Wrap scopes with an asynchronous metric write & flush dispatcher. - pub fn wrap(target: OUT, max_size: usize) -> InputCache { - InputCache { - attributes: Attributes::default(), - target: Arc::new(target), - cache: Arc::new(RwLock::new(lru::LRUCache::with_capacity(max_size))) - } - } -} - -impl WithAttributes for InputCache { - fn get_attributes(&self) -> &Attributes { &self.attributes } - fn mut_attributes(&mut self) -> &mut Attributes { &mut self.attributes } -} - -impl Input for InputCache { - type SCOPE = InputScopeCache; - - fn input(&self) -> Self::SCOPE { - let target = self.target.input_dyn(); - InputScopeCache { - attributes: self.attributes.clone(), - target, - cache: self.cache.clone(), - } - } -} - -/// Input wrapper caching frequently defined metrics -#[derive(Clone)] -pub struct InputScopeCache { - attributes: Attributes, - target: Arc, - cache: Arc>>, -} - -impl WithAttributes for InputScopeCache { - fn get_attributes(&self) -> &Attributes { &self.attributes } - fn mut_attributes(&mut self) -> &mut Attributes { &mut self.attributes } -} - -impl InputScope for InputScopeCache { - fn new_metric(&self, name: Name, kind: Kind) -> InputMetric { - let name = self.qualified_name(name); - let lookup = { - let mut cache = self.cache.write().expect("Cache Lock"); - cache.get(&name).map(|found| found.clone()) - }; - lookup.unwrap_or_else(|| { - let new_metric = self.target.new_metric(name.clone(), kind); - // FIXME (perf) having to take another write lock for a cache miss - let mut cache_miss = self.cache.write().expect("Cache Lock"); - cache_miss.insert(name, new_metric.clone()); - new_metric - }) - } -} - -impl Flush for InputScopeCache { - - fn flush(&self) -> error::Result<()> { - self.target.flush() - } -} - -mod lru { - //! A fixed-size cache with LRU expiration criteria. - //! Stored values will be held onto as long as there is space. - //! When space runs out, the oldest unused value will get evicted to make room for a new value. - - use std::hash::Hash; - use std::collections::HashMap; - - struct CacheEntry { - key: K, - value: Option, - next: Option, - prev: Option, - } - - /// A fixed-size cache. - pub struct LRUCache { - table: HashMap, - entries: Vec>, - first: Option, - last: Option, - capacity: usize, - } - - impl LRUCache { - /// Creates a new cache that can hold the specified number of elements. - pub fn with_capacity(size: usize) -> Self { - LRUCache { - table: HashMap::with_capacity(size), - entries: Vec::with_capacity(size), - first: None, - last: None, - capacity: size, - } - } - - /// Inserts a key-value pair into the cache and returns the previous value, if any. - /// If there is no room in the cache the oldest item will be removed. - pub fn insert(&mut self, key: K, value: V) -> Option { - if self.table.contains_key(&key) { - self.access(&key); - let entry = &mut self.entries[self.first.unwrap()]; - let old = entry.value.take(); - entry.value = Some(value); - old - } else { - self.ensure_room(); - // Update old head - let idx = self.entries.len(); - self.first.map(|e| { - let prev = Some(idx); - self.entries[e].prev = prev; - }); - // This is the new head - self.entries.push(CacheEntry { - key: key.clone(), - value: Some(value), - next: self.first, - prev: None, - }); - self.first = Some(idx); - self.last = self.last.or(self.first); - self.table.insert(key, idx); - None - } - } - - /// Retrieves a reference to the item associated with `key` from the cache - /// without promoting it. - pub fn peek(&mut self, key: &K) -> Option<&V> { - let entries = &self.entries; - self.table - .get(key) - .and_then(move |i| entries[*i].value.as_ref()) - } - - /// Retrieves a reference to the item associated with `key` from the cache. - pub fn get(&mut self, key: &K) -> Option<&V> { - if self.contains_key(key) { - self.access(key); - } - self.peek(key) - } - - /// Returns the number of elements currently in the cache. - pub fn len(&self) -> usize { - self.table.len() - } - - /// Promotes the specified key to the top of the cache. - fn access(&mut self, key: &K) { - let i = *self.table.get(key).unwrap(); - self.remove_from_list(i); - self.first = Some(i); - } - - pub fn contains_key(&mut self, key: &K) -> bool { - self.table.contains_key(key) - } - - /// Removes an item from the linked list. - fn remove_from_list(&mut self, i: usize) { - let (prev, next) = { - let entry = &mut self.entries[i]; - (entry.prev, entry.next) - }; - match (prev, next) { - // Item was in the middle of the list - (Some(j), Some(k)) => { - { - let first = &mut self.entries[j]; - first.next = next; - } - let second = &mut self.entries[k]; - second.prev = prev; - } - // Item was at the end of the list - (Some(j), None) => { - let first = &mut self.entries[j]; - first.next = None; - self.last = prev; - } - // Item was at front - _ => (), - } - } - - fn ensure_room(&mut self) { - if self.capacity == self.len() { - self.remove_last(); - } - } - - /// Removes the oldest item in the cache. - fn remove_last(&mut self) { - if let Some(idx) = self.last { - self.remove_from_list(idx); - let key = &self.entries[idx].key; - self.table.remove(key); - } - if self.last.is_none() { - self.first = None; - } - } - } - - #[cfg(test)] - mod tests { - use super::*; - - #[test] - fn get_and_get_mut_promote() { - let mut cache: LRUCache<&str, _> = LRUCache::with_capacity(2); - cache.insert("foo", 1); - cache.insert("bar", 2); - - cache.get(&"foo").unwrap(); - cache.insert("baz", 3); - - assert!(cache.contains_key(&"foo")); - assert!(cache.contains_key(&"baz")); - assert!(!cache.contains_key(&"bar")); - - cache.get(&"foo").unwrap(); - cache.insert("qux", 4); - - assert!(cache.contains_key(&"foo")); - assert!(cache.contains_key(&"qux")); - assert!(!cache.contains_key(&"baz")); - } - } - -} diff --git a/src/cache_out.rs b/src/cache_out.rs deleted file mode 100755 index 2dea31c..0000000 --- a/src/cache_out.rs +++ /dev/null @@ -1,264 +0,0 @@ -//! Cache metric definitions. - -use core::{Output, OutputDyn, WithAttributes, Attributes, OutputScope, OutputMetric, Name, Flush, Kind, AddPrefix}; -use error; -use std::sync::{Arc, RwLock}; -use std::rc::Rc; - -/// Wrap an output with a metric definition cache. -/// This is useless if all metrics are statically declared but can provide performance -/// benefits if some metrics are dynamically defined at runtime. -pub trait CachedOutput: Output + Send + Sync + 'static + Sized { - /// Wrap this output with an asynchronous dispatch queue of specified length. - fn cached(self, max_size: usize) -> OutputCache { - OutputCache::wrap(self, max_size) - } -} - -/// Output wrapper caching frequently defined metrics -#[derive(Clone)] -pub struct OutputCache { - attributes: Attributes, - target: Arc, - cache: Arc>>, -} - -impl OutputCache { - /// Wrap scopes with an asynchronous metric write & flush dispatcher. - pub fn wrap(target: OUT, max_size: usize) -> OutputCache { - OutputCache { - attributes: Attributes::default(), - target: Arc::new(target), - cache: Arc::new(RwLock::new(lru::LRUCache::with_capacity(max_size))) - } - } -} - -impl WithAttributes for OutputCache { - fn get_attributes(&self) -> &Attributes { &self.attributes } - fn mut_attributes(&mut self) -> &mut Attributes { &mut self.attributes } -} - -impl Output for OutputCache { - type SCOPE = OutputScopeCache; - - fn output(&self) -> Self::SCOPE { - let target = self.target.output_dyn(); - OutputScopeCache { - attributes: self.attributes.clone(), - target, - cache: self.cache.clone(), - } - } -} - -/// Output wrapper caching frequently defined metrics -#[derive(Clone)] -pub struct OutputScopeCache { - attributes: Attributes, - target: Rc, - cache: Arc>>, -} - -impl WithAttributes for OutputScopeCache { - fn get_attributes(&self) -> &Attributes { &self.attributes } - fn mut_attributes(&mut self) -> &mut Attributes { &mut self.attributes } -} - -impl OutputScope for OutputScopeCache { - fn new_metric(&self, name: Name, kind: Kind) -> OutputMetric { - let name = self.qualified_name(name); - let lookup = { - let mut cache = self.cache.write().expect("Cache Lock"); - cache.get(&name).map(|found| found.clone()) - }; - lookup.unwrap_or_else(|| { - let new_metric: OutputMetric = self.target.new_metric(name.clone(), kind); - // FIXME (perf) having to take another write lock for a cache miss - let mut cache_miss = self.cache.write().expect("Cache Lock"); - cache_miss.insert(name, new_metric.clone()); - new_metric - }) - } -} - -impl Flush for OutputScopeCache { - - fn flush(&self) -> error::Result<()> { - self.target.flush() - } -} - -mod lru { - //! A fixed-size cache with LRU expiration criteria. - //! Stored values will be held onto as long as there is space. - //! When space runs out, the oldest unused value will get evicted to make room for a new value. - - use std::hash::Hash; - use std::collections::HashMap; - - struct CacheEntry { - key: K, - value: Option, - next: Option, - prev: Option, - } - - /// A fixed-size cache. - pub struct LRUCache { - table: HashMap, - entries: Vec>, - first: Option, - last: Option, - capacity: usize, - } - - impl LRUCache { - /// Creates a new cache that can hold the specified number of elements. - pub fn with_capacity(size: usize) -> Self { - LRUCache { - table: HashMap::with_capacity(size), - entries: Vec::with_capacity(size), - first: None, - last: None, - capacity: size, - } - } - - /// Inserts a key-value pair into the cache and returns the previous value, if any. - /// If there is no room in the cache the oldest item will be removed. - pub fn insert(&mut self, key: K, value: V) -> Option { - if self.table.contains_key(&key) { - self.access(&key); - let entry = &mut self.entries[self.first.unwrap()]; - let old = entry.value.take(); - entry.value = Some(value); - old - } else { - self.ensure_room(); - // Update old head - let idx = self.entries.len(); - self.first.map(|e| { - let prev = Some(idx); - self.entries[e].prev = prev; - }); - // This is the new head - self.entries.push(CacheEntry { - key: key.clone(), - value: Some(value), - next: self.first, - prev: None, - }); - self.first = Some(idx); - self.last = self.last.or(self.first); - self.table.insert(key, idx); - None - } - } - - /// Retrieves a reference to the item associated with `key` from the cache - /// without promoting it. - pub fn peek(&mut self, key: &K) -> Option<&V> { - let entries = &self.entries; - self.table - .get(key) - .and_then(move |i| entries[*i].value.as_ref()) - } - - /// Retrieves a reference to the item associated with `key` from the cache. - pub fn get(&mut self, key: &K) -> Option<&V> { - if self.contains_key(key) { - self.access(key); - } - self.peek(key) - } - - /// Returns the number of elements currently in the cache. - pub fn len(&self) -> usize { - self.table.len() - } - - /// Promotes the specified key to the top of the cache. - fn access(&mut self, key: &K) { - let i = *self.table.get(key).unwrap(); - self.remove_from_list(i); - self.first = Some(i); - } - - pub fn contains_key(&mut self, key: &K) -> bool { - self.table.contains_key(key) - } - - /// Removes an item from the linked list. - fn remove_from_list(&mut self, i: usize) { - let (prev, next) = { - let entry = &mut self.entries[i]; - (entry.prev, entry.next) - }; - match (prev, next) { - // Item was in the middle of the list - (Some(j), Some(k)) => { - { - let first = &mut self.entries[j]; - first.next = next; - } - let second = &mut self.entries[k]; - second.prev = prev; - } - // Item was at the end of the list - (Some(j), None) => { - let first = &mut self.entries[j]; - first.next = None; - self.last = prev; - } - // Item was at front - _ => (), - } - } - - fn ensure_room(&mut self) { - if self.capacity == self.len() { - self.remove_last(); - } - } - - /// Removes the oldest item in the cache. - fn remove_last(&mut self) { - if let Some(idx) = self.last { - self.remove_from_list(idx); - let key = &self.entries[idx].key; - self.table.remove(key); - } - if self.last.is_none() { - self.first = None; - } - } - } - - #[cfg(test)] - mod tests { - use super::*; - - #[test] - fn get_and_get_mut_promote() { - let mut cache: LRUCache<&str, _> = LRUCache::with_capacity(2); - cache.insert("foo", 1); - cache.insert("bar", 2); - - cache.get(&"foo").unwrap(); - cache.insert("baz", 3); - - assert!(cache.contains_key(&"foo")); - assert!(cache.contains_key(&"baz")); - assert!(!cache.contains_key(&"bar")); - - cache.get(&"foo").unwrap(); - cache.insert("qux", 4); - - assert!(cache.contains_key(&"foo")); - assert!(cache.contains_key(&"qux")); - assert!(!cache.contains_key(&"baz")); - } - } - -} diff --git a/src/core.rs b/src/core.rs deleted file mode 100755 index 1f345ed..0000000 --- a/src/core.rs +++ /dev/null @@ -1,686 +0,0 @@ -//! Dipstick metrics core types and traits. -//! This is mostly centered around the backend. -//! Application-facing types are in the `app` module. - -use clock::TimeHandle; -use error; - -use std::sync::{Arc, Mutex}; -use std::ops; -use std::rc::Rc; -use std::fmt; -use std::collections::HashMap; - -// TODO maybe define an 'AsValue' trait + impl for supported number types, then drop 'num' crate -pub use num::ToPrimitive; - -/// Base type for recorded metric values. -pub type Value = u64; - -/////// ATTRIBUTES - -/// The actual distribution (random, fixed-cycled, etc) depends on selected sampling method. -#[derive(Debug, Clone, Copy)] -pub enum Sampling { - /// Do not sample, use all data. - Full, - - /// Floating point sampling rate - /// - 1.0+ records everything - /// - 0.5 records one of two values - /// - 0.0 records nothing - Random(f64) -} - -impl Default for Sampling { - fn default() -> Self { - Sampling::Full - } -} - -/// A metrics buffering strategy. -/// All strategies other than `Unbuffered` are applied as a best-effort, meaning that the buffer -/// may be flushed at any moment before reaching the limit, for any or no reason in particular. -#[derive(Debug, Clone, Copy)] -pub enum Buffering { - /// No buffering is performed (default). - Unbuffered, - - /// A buffer of maximum specified size is used. - BufferSize(usize), - - /// Buffer as much as possible. - Unlimited, -} - -impl Default for Buffering { - fn default() -> Self { - Buffering::Unbuffered - } -} - -/// One struct to rule them all. -/// Possible attributes of metric outputs and scopes. -/// Private trait used by impls of specific With* traits. -/// Not all attributes are used by all structs! -/// This is a design choice to centralize code at the expense of slight waste of memory. -/// Fields have also not been made `pub` to make it easy to change this mechanism. -/// Field access must go through `is_` and `get_` methods declared in sub-traits. -#[derive(Debug, Clone, Default)] -pub struct Attributes { - namespace: Name, - sampling: Sampling, - buffering: Buffering, -} - -/// The only trait that requires concrete impl by metric components. -/// Default impl of actual attributes use this to clone & mutate the original component. -/// This trait is _not_ exposed by the lib. -pub trait WithAttributes: Clone { - /// Return attributes for evaluation. - // TODO replace with fields-in-traits if ever stabilized (https://github.com/nikomatsakis/fields-in-traits-rfc) - fn get_attributes(&self) -> &Attributes; - - /// Return attributes of component to be mutated after cloning. - // TODO replace with fields-in-traits if ever stabilized (https://github.com/nikomatsakis/fields-in-traits-rfc) - fn mut_attributes(&mut self) -> &mut Attributes; - - /// Clone this component and its attributes before returning it. - /// This means one of the attributes will be cloned only to be replaced immediately. - /// But the benefits of a generic solution means we can live with that for a while. - fn with_attributes(&self, edit: F) -> Self { - let mut cloned = self.clone(); - (edit)(cloned.mut_attributes()); - cloned - } -} - -/// Name operations support. -pub trait AddPrefix { - /// Return the namespace of the component. - fn get_namespace(&self) -> &Name; - - /// Join namespace and prepend in newly defined metrics. - fn add_prefix(&self, name: &str) -> Self; - - /// Append the specified name to the local namespace and return the concatenated result. - fn qualified_name(&self, metric_name: Name) -> Name; -} - -/// Name operations support. -pub trait AddTag { - /// Return the namespace of the component. - fn get_tags(&self) -> &Arc>; - - /// Join namespace and prepend in newly defined metrics. - fn add_tag(&self, name: &str) -> Self; - -} - -impl AddPrefix for T { - fn get_namespace(&self) -> &Name { - &self.get_attributes().namespace - } - - /// Join namespace and prepend in newly defined metrics. - fn add_prefix(&self, name: &str) -> Self { - self.with_attributes(|new_attr| new_attr.namespace = new_attr.namespace.concat(name)) - } - - /// Append the specified name to the local namespace and return the concatenated result. - fn qualified_name(&self, name: Name) -> Name { - // FIXME (perf) store name in reverse to prepend with an actual push() to the vec - self.get_attributes().namespace.concat(name) - } -} - -/// Apply statistical sampling to collected metrics data. -pub trait Sampled: WithAttributes { - /// Perform random sampling of values according to the specified rate. - fn sampled(&self, sampling: Sampling) -> Self { - self.with_attributes(|new_attr| new_attr.sampling = sampling) - } - - /// Get the sampling strategy for this component, if any. - fn get_sampling(&self) -> Sampling { - self.get_attributes().sampling - } -} - -/// Determine scope buffering strategy, if supported by output. -/// Changing this only affects scopes opened afterwards. -/// Buffering is done on best effort, meaning flush will occur if buffer capacity is exceeded. -pub trait Buffered: WithAttributes { - /// Return a clone with the specified buffering set. - fn buffered(&self, buffering: Buffering) -> Self { - self.with_attributes(|new_attr| new_attr.buffering = buffering) - } - - /// Is this component using buffering? - fn is_buffered(&self) -> bool { - match self.get_buffering() { - Buffering::Unbuffered => false, - _ => true - } - } - - /// Return the buffering. - fn get_buffering(&self) -> Buffering { - self.get_attributes().buffering - } -} - -/// A namespace for metrics. -/// Does _not_ include the metric's "short" name itself. -/// Can be empty. -#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Default)] -pub struct Name { - inner: Vec, -} - -impl Name { - - /// Concatenate with another namespace into a new one. - pub fn concat(&self, name: impl Into) -> Self { - let mut cloned = self.clone(); - cloned.inner.extend_from_slice(&name.into().inner); - cloned - } - - /// Returns true if the specified namespace is a subset or is equal to this namespace. - pub fn starts_with(&self, name: &Name) -> bool { - (self.inner.len() >= name.inner.len()) && (name.inner[..] == self.inner[..name.inner.len()]) - } - - /// Combine name parts into a string. - pub fn join(&self, separator: &str) -> String { - - let mut buf = String::with_capacity(64); - let mut i = self.inner.iter(); - if let Some(n) = i.next() { - buf.push_str(n.as_ref()); - } else { - return "".into() - } - for n in i { - buf.push_str(separator); - buf.push_str(n.as_ref()); - } - buf - } -} - -impl ops::Deref for Name { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl ops::DerefMut for Name { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} - -impl> From for Name { - fn from(name: S) -> Name { - let name: String = name.into(); - if name.is_empty() { - Name::default() - } else { - Name { inner: vec![name] } - } - } -} - -////// INPUT - -lazy_static! { - /// The reference instance identifying an uninitialized metric config. - pub static ref NO_METRIC_OUTPUT: Arc = Arc::new(Void::metrics()); - - /// The reference instance identifying an uninitialized metric scope. - pub static ref NO_METRIC_SCOPE: Arc = NO_METRIC_OUTPUT.input_dyn(); -} - -/// A function trait that opens a new metric capture scope. -pub trait Input: Send + Sync + 'static + InputDyn { - /// The type of Scope returned byt this input. - type SCOPE: InputScope + Send + Sync + 'static; - - /// Open a new scope from this output. - fn input(&self) -> Self::SCOPE; -} - -/// A function trait that opens a new metric capture scope. -pub trait InputDyn: Send + Sync + 'static { - /// Open a new scope from this output. - fn input_dyn(&self) -> Arc; -} - -/// Blanket impl of dyn input trait -impl InputDyn for T { - fn input_dyn(&self) -> Arc { - Arc::new(self.input()) - } -} - -/// InputScope -/// Define metrics, write values and flush them. -pub trait InputScope: Flush { - /// Define a generic metric of the specified type. - /// It is preferable to use counter() / marker() / timer() / gauge() methods. - fn new_metric(&self, name: Name, kind: Kind) -> InputMetric; - - /// Define a counter. - fn counter(&self, name: &str) -> Counter { - self.new_metric(name.into(), Kind::Counter).into() - } - - /// Define a marker. - fn marker(&self, name: &str) -> Marker { - self.new_metric(name.into(), Kind::Marker).into() - } - - /// Define a timer. - fn timer(&self, name: &str) -> Timer { - self.new_metric(name.into(), Kind::Timer).into() - } - - /// Define a gauge. - fn gauge(&self, name: &str) -> Gauge { - self.new_metric(name.into(), Kind::Gauge).into() - } - -} - -/// A metric is actually a function that knows to write a metric value to a metric output. -#[derive(Clone)] -pub struct InputMetric { - inner: Arc -} - -impl fmt::Debug for InputMetric { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "InputMetric") - } -} - -impl InputMetric { - /// Utility constructor - pub fn new(metric: F) -> InputMetric { - InputMetric { inner: Arc::new(metric) } - } - - /// Collect a new value for this metric. - #[inline] - pub fn write(&self, value: Value) { - (self.inner)(value) - } -} - - -////// OUTPUT - -/// Define metrics, write values and flush them. -pub trait OutputScope: Flush { - - /// Define a raw metric of the specified type. - fn new_metric(&self, name: Name, kind: Kind) -> OutputMetric; - -} - -impl OutputMetric { - /// Utility constructor - pub fn new(metric: F) -> OutputMetric { - OutputMetric { inner: Rc::new(metric) } - } - - /// Some may prefer the `metric.write(value)` form to the `(metric)(value)` form. - /// This shouldn't matter as metrics should be of type Counter, Marker, etc. - #[inline] - pub fn write(&self, value: Value) { - (self.inner)(value) - } -} - - -/// A function trait that opens a new metric capture scope. -pub trait Output: Send + Sync + 'static + OutputDyn { - /// The type of Scope returned byt this output. - type SCOPE: OutputScope; - - /// Open a new scope from this output. - fn output(&self) -> Self::SCOPE; -} - -/// A function trait that opens a new metric capture scope. -pub trait OutputDyn { - /// Open a new scope from this output. - fn output_dyn(&self) -> Rc; -} - -/// Blanket impl of dyn output trait -impl OutputDyn for T { - fn output_dyn(&self) -> Rc { - Rc::new(self.output()) - } -} - -//////// FLUSH - -/// Both InputScope and OutputScope share the ability to flush the recorded data. -pub trait Flush { - - /// Flush does nothing by default. - fn flush(&self) -> error::Result<()> { - Ok(()) - } - -} - -///////// LOCKING INPUT -> OUTPUT ADAPTER - - -/// Provide thread-safe locking to RawScope implementers. -#[derive(Clone)] -pub struct LockingScopeBox { - attributes: Attributes, - inner: Arc> -} - -impl WithAttributes for LockingScopeBox { - fn get_attributes(&self) -> &Attributes { &self.attributes } - fn mut_attributes(&mut self) -> &mut Attributes { &mut self.attributes } -} - -impl InputScope for LockingScopeBox { - - fn new_metric(&self, name: Name, kind: Kind) -> InputMetric { - let name = self.qualified_name(name); - let raw_metric = self.inner.lock().expect("RawScope Lock").new_metric(name, kind); - let mutex = self.inner.clone(); - InputMetric::new(move |value| { - let _guard = mutex.lock().expect("OutputMetric Lock"); - raw_metric.write(value) - } ) - } - -} - -impl Flush for LockingScopeBox { - fn flush(&self) -> error::Result<()> { - self.inner.lock().expect("OutputScope Lock").flush() - } -} - -/// Blanket impl that provides RawOutputs their dynamic flavor. -impl Input for T { - type SCOPE = LockingScopeBox; - - fn input(&self) -> Self::SCOPE { - LockingScopeBox { - attributes: Attributes::default(), - inner: Arc::new(Mutex::new(UnsafeScope(self.output_dyn()))) - } - } -} - -///////// UNSAFE INPUT -> OUTPUT ADAPTER - -/// Wrap a RawScope to make it Send + Sync, allowing it to travel the world of threads. -/// Obviously, it should only still be used from a single thread or dragons may occur. -#[derive(Clone)] -pub struct UnsafeScope(Rc ); - -unsafe impl Send for UnsafeScope {} -unsafe impl Sync for UnsafeScope {} - -impl UnsafeScope { - /// Wrap a dynamic RawScope to make it Send + Sync. - pub fn new(scope: Rc) -> Self { - UnsafeScope(scope) - } -} - -impl ops::Deref for UnsafeScope { - type Target = OutputScope + 'static; - fn deref(&self) -> &Self::Target { - Rc::as_ref(&self.0) - } -} - -/// Output metrics are not thread safe. -#[derive(Clone)] -pub struct OutputMetric { - inner: Rc -} - -impl fmt::Debug for OutputMetric { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Box") - } -} - -unsafe impl Send for OutputMetric {} -unsafe impl Sync for OutputMetric {} - - -////////////// INSTRUMENTS - -/// Used to differentiate between metric kinds in the backend. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Kind { - /// Handling one item at a time. - Marker, - /// Handling quantities or multiples. - Counter, - /// Reporting instant measurement of a resource at a point in time. - Gauge, - /// Measuring a time interval, internal to the app or provided by an external source. - Timer, -} - -/// Used by the metrics! macro to obtain the Kind from the stringified type. -impl<'a> From<&'a str> for Kind { - fn from(s: &str) -> Kind { - match s { - "Marker" => Kind::Marker, - "Counter" => Kind::Counter, - "Gauge" => Kind::Gauge, - "Timer" => Kind::Timer, - _ => panic!("No Kind '{}' defined", s) - } - } -} - -/// A monotonic counter metric. -/// Since value is only ever increased by one, no value parameter is provided, -/// preventing programming errors. -#[derive(Debug, Clone)] -pub struct Marker { - inner: InputMetric, -} - -impl Marker { - /// Record a single event occurence. - pub fn mark(&self) { - self.inner.write(1) - } -} - -/// A counter that sends values to the metrics backend -#[derive(Debug, Clone)] -pub struct Counter { - inner: InputMetric, -} - -impl Counter { - /// Record a value count. - pub fn count(&self, count: V) { - self.inner.write(count.to_u64().unwrap()) - } -} - -/// A gauge that sends values to the metrics backend -#[derive(Debug, Clone)] -pub struct Gauge { - inner: InputMetric, -} - -impl Gauge { - /// Record a value point for this gauge. - pub fn value(&self, value: V) { - self.inner.write(value.to_u64().unwrap()) - } -} - -/// A timer that sends values to the metrics backend -/// Timers can record time intervals in multiple ways : -/// - with the time! macrohich wraps an expression or block with start() and stop() calls. -/// - with the time(Fn) methodhich wraps a closure with start() and stop() calls. -/// - with start() and stop() methodsrapping around the operation to time -/// - with the interval_us() method, providing an externally determined microsecond interval -#[derive(Debug, Clone)] -pub struct Timer { - inner: InputMetric, -} - -impl Timer { - /// 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(&self, interval_us: V) -> V { - self.inner.write(interval_us.to_u64().unwrap()); - interval_us - } - - /// Obtain a opaque handle to the current time. - /// The handle is passed back to the stop() method to record a time interval. - /// This is actually a convenience method to the TimeHandle::now() - /// Beware, handles obtained here are not bound to this specific timer instance - /// _for now_ but might be in the future for safety. - /// If you require safe multi-timer handles, get them through TimeType::now() - pub fn start(&self) -> TimeHandle { - TimeHandle::now() - } - - /// Record the time elapsed since the start_time handle was obtained. - /// This call can be performed multiple times using the same handle, - /// reporting distinct time intervals each time. - /// Returns the microsecond interval value that was recorded. - pub fn stop(&self, start_time: TimeHandle) -> u64 { - let elapsed_us = start_time.elapsed_us(); - self.interval_us(elapsed_us) - } - - /// Record the time taken to execute the provided closure - pub fn time R, R>(&self, operations: F) -> R { - let start_time = self.start(); - let value: R = operations(); - self.stop(start_time); - value - } -} - -impl From for Gauge { - fn from(metric: InputMetric) -> Gauge { - Gauge { inner: metric } - } -} - -impl From for Timer { - fn from(metric: InputMetric) -> Timer { - Timer { inner: metric } - } -} - -impl From for Counter { - fn from(metric: InputMetric) -> Counter { - Counter { inner: metric } - } -} - -impl From for Marker { - fn from(metric: InputMetric) -> Marker { - Marker { inner: metric } - } -} - - -/// VOID INPUT & OUTPUT - -/// Discard metrics output. -#[derive(Clone)] -pub struct Void {} - -/// Discard metrics output. -#[derive(Clone)] -pub struct VoidInput {} - -/// Discard metrics output. -#[derive(Clone)] -pub struct VoidOutput {} - -impl Void { - /// Void metrics builder. - pub fn metrics() -> Self { - Void {} - } -} - -impl Output for Void { - type SCOPE = VoidOutput; - fn output(&self) -> VoidOutput { - VoidOutput {} - } -} - -impl OutputScope for VoidOutput { - fn new_metric(&self, _name: Name, _kind: Kind) -> OutputMetric { - OutputMetric::new(|_value| {}) - } -} - -impl Flush for VoidOutput { -} - -/// Discard all metric values sent to it. -pub fn output_none() -> Void { - Void {} -} - -#[cfg(test)] -mod test { - use core::*; - - #[test] - fn test_to_void() { - let c = Void::metrics().input(); - let m = c.new_metric("test".into(), Kind::Marker); - m.write(33); - } - -} - -#[cfg(feature = "bench")] -mod bench { - - use core::*; - use clock::TimeHandle; - use test; - use bucket::Bucket; - - #[bench] - fn get_instant(b: &mut test::Bencher) { - b.iter(|| test::black_box(TimeHandle::now())); - } - - #[bench] - fn time_bench_direct_dispatch_event(b: &mut test::Bencher) { - let metrics = Bucket::new(); - let marker = metrics.marker("aaa"); - b.iter(|| test::black_box(marker.mark())); - } -} diff --git a/src/clock.rs b/src/core/clock.rs old mode 100644 new mode 100755 similarity index 96% rename from src/clock.rs rename to src/core/clock.rs index cb3d0ec..40ae896 --- a/src/clock.rs +++ b/src/core/clock.rs @@ -1,5 +1,6 @@ use std::ops::Add; use std::time::{Duration, Instant}; + use core::Value; #[derive(Debug, Copy, Clone)] @@ -14,7 +15,7 @@ impl TimeHandle { TimeHandle(now()) } - /// Get the elapsed time in microseconds since TimeHanduule was obtained. + /// Get the elapsed time in microseconds since TimeHandle was obtained. pub fn elapsed_us(self) -> Value { let duration = now() - self.0; duration.as_secs() * 1000000 + (duration.subsec_nanos() / 1000) as Value diff --git a/src/core/component.rs b/src/core/component.rs new file mode 100755 index 0000000..0211a6d --- /dev/null +++ b/src/core/component.rs @@ -0,0 +1,220 @@ +use std::sync::Arc; +use std::ops; +use std::collections::HashMap; + +/// The actual distribution (random, fixed-cycled, etc) depends on selected sampling method. +#[derive(Debug, Clone, Copy)] +pub enum Sampling { + /// Do not sample, use all data. + Full, + + /// Floating point sampling rate + /// - 1.0+ records everything + /// - 0.5 records one of two values + /// - 0.0 records nothing + Random(f64) +} + +impl Default for Sampling { + fn default() -> Self { + Sampling::Full + } +} + +/// A metrics buffering strategy. +/// All strategies other than `Unbuffered` are applied as a best-effort, meaning that the buffer +/// may be flushed at any moment before reaching the limit, for any or no reason in particular. +#[derive(Debug, Clone, Copy)] +pub enum Buffering { + /// No buffering is performed (default). + Unbuffered, + + /// A buffer of maximum specified size is used. + BufferSize(usize), + + /// Buffer as much as possible. + Unlimited, +} + +impl Default for Buffering { + fn default() -> Self { + Buffering::Unbuffered + } +} + +/// One struct to rule them all. +/// Possible attributes of metric outputs and scopes. +/// Private trait used by impls of specific With* traits. +/// Not all attributes are used by all structs! +/// This is a design choice to centralize code at the expense of slight waste of memory. +/// Fields have also not been made `pub` to make it easy to change this mechanism. +/// Field access must go through `is_` and `get_` methods declared in sub-traits. +#[derive(Debug, Clone, Default)] +pub struct Attributes { + namespace: Name, + sampling: Sampling, + buffering: Buffering, +} + +/// The only trait that requires concrete impl by metric components. +/// Default impl of actual attributes use this to clone & mutate the original component. +/// This trait is _not_ exposed by the lib. +pub trait WithAttributes: Clone { + /// Return attributes for evaluation. + // TODO replace with fields-in-traits if ever stabilized (https://github.com/nikomatsakis/fields-in-traits-rfc) + fn get_attributes(&self) -> &Attributes; + + /// Return attributes of component to be mutated after cloning. + // TODO replace with fields-in-traits if ever stabilized (https://github.com/nikomatsakis/fields-in-traits-rfc) + fn mut_attributes(&mut self) -> &mut Attributes; + + /// Clone this component and its attributes before returning it. + /// This means one of the attributes will be cloned only to be replaced immediately. + /// But the benefits of a generic solution means we can live with that for a while. + fn with_attributes(&self, edit: F) -> Self { + let mut cloned = self.clone(); + (edit)(cloned.mut_attributes()); + cloned + } +} + +/// Name operations support. +pub trait AddPrefix { + /// Return the namespace of the component. + fn get_namespace(&self) -> &Name; + + /// Join namespace and prepend in newly defined metrics. + fn add_prefix(&self, name: &str) -> Self; + + /// Append the specified name to the local namespace and return the concatenated result. + fn qualified_name(&self, metric_name: Name) -> Name; +} + +/// Name operations support. +pub trait Label { + /// Return the namespace of the component. + fn get_label(&self) -> &Arc>; + + /// Join namespace and prepend in newly defined metrics. + fn label(&self, name: &str) -> Self; + +} + +impl AddPrefix for T { + fn get_namespace(&self) -> &Name { + &self.get_attributes().namespace + } + + /// Join namespace and prepend in newly defined metrics. + fn add_prefix(&self, name: &str) -> Self { + self.with_attributes(|new_attr| new_attr.namespace = new_attr.namespace.concat(name)) + } + + /// Append the specified name to the local namespace and return the concatenated result. + fn qualified_name(&self, name: Name) -> Name { + // FIXME (perf) store name in reverse to prepend with an actual push() to the vec + self.get_attributes().namespace.concat(name) + } +} + +/// Apply statistical sampling to collected metrics data. +pub trait Sampled: WithAttributes { + /// Perform random sampling of values according to the specified rate. + fn sampled(&self, sampling: Sampling) -> Self { + self.with_attributes(|new_attr| new_attr.sampling = sampling) + } + + /// Get the sampling strategy for this component, if any. + fn get_sampling(&self) -> Sampling { + self.get_attributes().sampling + } +} + +/// Determine scope buffering strategy, if supported by output. +/// Changing this only affects scopes opened afterwards. +/// Buffering is done on best effort, meaning flush will occur if buffer capacity is exceeded. +pub trait Buffered: WithAttributes { + /// Return a clone with the specified buffering set. + fn buffered(&self, buffering: Buffering) -> Self { + self.with_attributes(|new_attr| new_attr.buffering = buffering) + } + + /// Is this component using buffering? + fn is_buffered(&self) -> bool { + match self.get_buffering() { + Buffering::Unbuffered => false, + _ => true + } + } + + /// Return the buffering. + fn get_buffering(&self) -> Buffering { + self.get_attributes().buffering + } +} + +/// A namespace for metrics. +/// Does _not_ include the metric's "short" name itself. +/// Can be empty. +#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Default)] +pub struct Name { + inner: Vec, +} + +impl Name { + + /// Concatenate with another namespace into a new one. + pub fn concat(&self, name: impl Into) -> Self { + let mut cloned = self.clone(); + cloned.inner.extend_from_slice(&name.into().inner); + cloned + } + + /// Returns true if the specified namespace is a subset or is equal to this namespace. + pub fn starts_with(&self, name: &Name) -> bool { + (self.inner.len() >= name.inner.len()) && (name.inner[..] == self.inner[..name.inner.len()]) + } + + /// Combine name parts into a string. + pub fn join(&self, separator: &str) -> String { + + let mut buf = String::with_capacity(64); + let mut i = self.inner.iter(); + if let Some(n) = i.next() { + buf.push_str(n.as_ref()); + } else { + return "".into() + } + for n in i { + buf.push_str(separator); + buf.push_str(n.as_ref()); + } + buf + } +} + +impl ops::Deref for Name { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl ops::DerefMut for Name { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl> From for Name { + fn from(name: S) -> Name { + let name: String = name.into(); + if name.is_empty() { + Name::default() + } else { + Name { inner: vec![name] } + } + } +} + diff --git a/src/error.rs b/src/core/error.rs similarity index 97% rename from src/error.rs rename to src/core/error.rs index 9e2307a..eb066a2 100644 --- a/src/error.rs +++ b/src/core/error.rs @@ -5,8 +5,8 @@ use std::error; use std::fmt::{self, Display, Formatter}; use std::result; use std::sync::mpsc; -use queue_in; -use queue_out; +use queue::queue_in; +use queue::queue_out; use self::Error::*; diff --git a/src/core/input.rs b/src/core/input.rs new file mode 100755 index 0000000..ec06b0d --- /dev/null +++ b/src/core/input.rs @@ -0,0 +1,224 @@ +use core::clock::TimeHandle; +use core::{Value, Flush}; +use core::component::Name; + +use std::sync::Arc; +use std::fmt; + +// TODO maybe define an 'AsValue' trait + impl for supported number types, then drop 'num' crate +pub use num::ToPrimitive; + +/// A function trait that opens a new metric capture scope. +pub trait Input: Send + Sync + 'static + InputDyn { + /// The type of Scope returned byt this input. + type SCOPE: InputScope + Send + Sync + 'static; + + /// Open a new scope from this output. + fn input(&self) -> Self::SCOPE; +} + +/// A function trait that opens a new metric capture scope. +pub trait InputDyn: Send + Sync + 'static { + /// Open a new scope from this output. + fn input_dyn(&self) -> Arc; +} + +/// Blanket impl of dyn input trait +impl InputDyn for T { + fn input_dyn(&self) -> Arc { + Arc::new(self.input()) + } +} + +/// InputScope +/// Define metrics, write values and flush them. +pub trait InputScope: Flush { + /// Define a generic metric of the specified type. + /// It is preferable to use counter() / marker() / timer() / gauge() methods. + fn new_metric(&self, name: Name, kind: Kind) -> InputMetric; + + /// Define a counter. + fn counter(&self, name: &str) -> Counter { + self.new_metric(name.into(), Kind::Counter).into() + } + + /// Define a marker. + fn marker(&self, name: &str) -> Marker { + self.new_metric(name.into(), Kind::Marker).into() + } + + /// Define a timer. + fn timer(&self, name: &str) -> Timer { + self.new_metric(name.into(), Kind::Timer).into() + } + + /// Define a gauge. + fn gauge(&self, name: &str) -> Gauge { + self.new_metric(name.into(), Kind::Gauge).into() + } + +} + +/// A metric is actually a function that knows to write a metric value to a metric output. +#[derive(Clone)] +pub struct InputMetric { + inner: Arc +} + +impl fmt::Debug for InputMetric { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "InputMetric") + } +} + +impl InputMetric { + /// Utility constructor + pub fn new(metric: F) -> InputMetric { + InputMetric { inner: Arc::new(metric) } + } + + /// Collect a new value for this metric. + #[inline] + pub fn write(&self, value: Value) { + (self.inner)(value) + } +} + +/// Used to differentiate between metric kinds in the backend. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum Kind { + /// Handling one item at a time. + Marker, + /// Handling quantities or multiples. + Counter, + /// Reporting instant measurement of a resource at a point in time. + Gauge, + /// Measuring a time interval, internal to the app or provided by an external source. + Timer, +} + +/// Used by the metrics! macro to obtain the Kind from the stringified type. +impl<'a> From<&'a str> for Kind { + fn from(s: &str) -> Kind { + match s { + "Marker" => Kind::Marker, + "Counter" => Kind::Counter, + "Gauge" => Kind::Gauge, + "Timer" => Kind::Timer, + _ => panic!("No Kind '{}' defined", s) + } + } +} + +/// A monotonic counter metric. +/// Since value is only ever increased by one, no value parameter is provided, +/// preventing programming errors. +#[derive(Debug, Clone)] +pub struct Marker { + inner: InputMetric, +} + +impl Marker { + /// Record a single event occurence. + pub fn mark(&self) { + self.inner.write(1) + } +} + +/// A counter that sends values to the metrics backend +#[derive(Debug, Clone)] +pub struct Counter { + inner: InputMetric, +} + +impl Counter { + /// Record a value count. + pub fn count(&self, count: V) { + self.inner.write(count.to_u64().unwrap()) + } +} + +/// A gauge that sends values to the metrics backend +#[derive(Debug, Clone)] +pub struct Gauge { + inner: InputMetric, +} + +impl Gauge { + /// Record a value point for this gauge. + pub fn value(&self, value: V) { + self.inner.write(value.to_u64().unwrap()) + } +} + +/// A timer that sends values to the metrics backend +/// Timers can record time intervals in multiple ways : +/// - with the time! macrohich wraps an expression or block with start() and stop() calls. +/// - with the time(Fn) methodhich wraps a closure with start() and stop() calls. +/// - with start() and stop() methodsrapping around the operation to time +/// - with the interval_us() method, providing an externally determined microsecond interval +#[derive(Debug, Clone)] +pub struct Timer { + inner: InputMetric, +} + +impl Timer { + /// 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(&self, interval_us: V) -> V { + self.inner.write(interval_us.to_u64().unwrap()); + interval_us + } + + /// Obtain a opaque handle to the current time. + /// The handle is passed back to the stop() method to record a time interval. + /// This is actually a convenience method to the TimeHandle::now() + /// Beware, handles obtained here are not bound to this specific timer instance + /// _for now_ but might be in the future for safety. + /// If you require safe multi-timer handles, get them through TimeType::now() + pub fn start(&self) -> TimeHandle { + TimeHandle::now() + } + + /// Record the time elapsed since the start_time handle was obtained. + /// This call can be performed multiple times using the same handle, + /// reporting distinct time intervals each time. + /// Returns the microsecond interval value that was recorded. + pub fn stop(&self, start_time: TimeHandle) -> u64 { + let elapsed_us = start_time.elapsed_us(); + self.interval_us(elapsed_us) + } + + /// Record the time taken to execute the provided closure + pub fn time R, R>(&self, operations: F) -> R { + let start_time = self.start(); + let value: R = operations(); + self.stop(start_time); + value + } +} + +impl From for Gauge { + fn from(metric: InputMetric) -> Gauge { + Gauge { inner: metric } + } +} + +impl From for Timer { + fn from(metric: InputMetric) -> Timer { + Timer { inner: metric } + } +} + +impl From for Counter { + fn from(metric: InputMetric) -> Counter { + Counter { inner: metric } + } +} + +impl From for Marker { + fn from(metric: InputMetric) -> Marker { + Marker { inner: metric } + } +} + diff --git a/src/metrics.rs b/src/core/metrics.rs similarity index 88% rename from src/metrics.rs rename to src/core/metrics.rs index 7fd2b91..84edffa 100755 --- a/src/metrics.rs +++ b/src/core/metrics.rs @@ -2,8 +2,9 @@ //! Because the possibly high volume of data, this is pre-set to use aggregation. //! This is also kept in a separate module because it is not to be exposed outside of the crate. -use core::{Marker, AddPrefix, InputScope, Counter}; -use proxy::Proxy; +use core::component::AddPrefix; +use core::input::{Marker, InputScope, Counter}; +use core::proxy::Proxy; metrics!{ /// Dipstick's own internal metrics. diff --git a/src/core/mod.rs b/src/core/mod.rs new file mode 100755 index 0000000..1254ac2 --- /dev/null +++ b/src/core/mod.rs @@ -0,0 +1,58 @@ +pub mod error; +pub mod component; +pub mod input; +pub mod output; +pub mod out_lock; +pub mod clock; +pub mod void; +pub mod proxy; +pub mod pcg32; +pub mod scheduler; +pub mod metrics; + +/// Base type for recorded metric values. +pub type Value = u64; + +/// Both InputScope and OutputScope share the ability to flush the recorded data. +pub trait Flush { + /// Flush does nothing by default. + fn flush(&self) -> error::Result<()> { + Ok(()) + } +} + +#[cfg(test)] +pub mod test { + use super::*; + use super::input::*; + + #[test] + fn test_to_void() { + let c = void::Void::metrics().input(); + let m = c.new_metric("test".into(), input::Kind::Marker); + m.write(33); + } + +} + +#[cfg(feature = "bench")] +pub mod bench { + + use core::{TimeHandle, Marker, Input}; + use aggregate::bucket::Bucket; + use super::clock::TimeHandle; + use test; + use aggregate::Bucket; + + #[bench] + fn get_instant(b: &mut test::Bencher) { + b.iter(|| test::black_box(TimeHandle::now())); + } + + #[bench] + fn time_bench_direct_dispatch_event(b: &mut test::Bencher) { + let metrics = Bucket::new(); + let marker = metrics.marker("aaa"); + b.iter(|| test::black_box(marker.mark())); + } +} diff --git a/src/core/out_lock.rs b/src/core/out_lock.rs new file mode 100755 index 0000000..fab1a89 --- /dev/null +++ b/src/core/out_lock.rs @@ -0,0 +1,69 @@ +use core::input::{InputScope, InputMetric, Input, Kind}; +use core::output::{Output, OutputScope}; +use core::component::{Attributes, WithAttributes, Name, AddPrefix}; +use core::Flush; +use core::error; +use std::rc::Rc; + +use std::sync::{Arc, Mutex}; +use std::ops; + +/// Provide thread-safe locking to RawScope implementers. +#[derive(Clone)] +pub struct LockingScopeBox { + attributes: Attributes, + inner: Arc> +} + +impl WithAttributes for LockingScopeBox { + fn get_attributes(&self) -> &Attributes { &self.attributes } + fn mut_attributes(&mut self) -> &mut Attributes { &mut self.attributes } +} + +impl InputScope for LockingScopeBox { + + fn new_metric(&self, name: Name, kind: Kind) -> InputMetric { + let name = self.qualified_name(name); + let raw_metric = self.inner.lock().expect("RawScope Lock").new_metric(name, kind); + let mutex = self.inner.clone(); + InputMetric::new(move |value| { + let _guard = mutex.lock().expect("OutputMetric Lock"); + raw_metric.write(value) + } ) + } + +} + +impl Flush for LockingScopeBox { + fn flush(&self) -> error::Result<()> { + self.inner.lock().expect("OutputScope Lock").flush() + } +} + +/// Blanket impl that provides RawOutputs their dynamic flavor. +impl Input for T { + type SCOPE = LockingScopeBox; + + fn input(&self) -> Self::SCOPE { + LockingScopeBox { + attributes: Attributes::default(), + inner: Arc::new(Mutex::new(LockScope(self.output_dyn()))) + } + } +} + +/// Wrap an OutputScope to make it Send + Sync, allowing it to travel the world of threads. +/// Obviously, it should only still be used from a single thread or dragons may occur. +#[derive(Clone)] +struct LockScope(Rc ); + +impl ops::Deref for LockScope { + type Target = OutputScope + 'static; + fn deref(&self) -> &Self::Target { + Rc::as_ref(&self.0) + } +} + +unsafe impl Send for LockScope {} +unsafe impl Sync for LockScope {} + diff --git a/src/core/output.rs b/src/core/output.rs new file mode 100755 index 0000000..b8ebd08 --- /dev/null +++ b/src/core/output.rs @@ -0,0 +1,62 @@ +use core::{Flush, Value}; +use core::input::Kind; +use core::component::Name; +use core::void::Void; + +use std::rc::Rc; + +/// Define metrics, write values and flush them. +pub trait OutputScope: Flush { + + /// Define a raw metric of the specified type. + fn new_metric(&self, name: Name, kind: Kind) -> OutputMetric; + +} + +impl OutputMetric { + /// Utility constructor + pub fn new(metric: F) -> OutputMetric { + OutputMetric { inner: Rc::new(metric) } + } + + /// Some may prefer the `metric.write(value)` form to the `(metric)(value)` form. + /// This shouldn't matter as metrics should be of type Counter, Marker, etc. + #[inline] + pub fn write(&self, value: Value) { + (self.inner)(value) + } +} + + +/// A function trait that opens a new metric capture scope. +pub trait Output: Send + Sync + 'static + OutputDyn { + /// The type of Scope returned byt this output. + type SCOPE: OutputScope; + + /// Open a new scope from this output. + fn output(&self) -> Self::SCOPE; +} + +/// A function trait that opens a new metric capture scope. +pub trait OutputDyn { + /// Open a new scope from this output. + fn output_dyn(&self) -> Rc; +} + +/// Blanket impl of dyn output trait +impl OutputDyn for T { + fn output_dyn(&self) -> Rc { + Rc::new(self.output()) + } +} + +/// Output metrics are not thread safe. +#[derive(Clone)] +pub struct OutputMetric { + inner: Rc +} + +/// Discard all metric values sent to it. +pub fn output_none() -> Void { + Void {} +} \ No newline at end of file diff --git a/src/pcg32.rs b/src/core/pcg32.rs similarity index 96% rename from src/pcg32.rs rename to src/core/pcg32.rs index 5407c25..280b713 100644 --- a/src/pcg32.rs +++ b/src/core/pcg32.rs @@ -1,6 +1,6 @@ //! PCG32 random number generation for fast sampling +//! Kept here for low dependency count. -// TODO use https://github.com/codahale/pcg instead? use std::cell::RefCell; use time; diff --git a/src/proxy.rs b/src/core/proxy.rs similarity index 95% rename from src/proxy.rs rename to src/core/proxy.rs index 116f1f5..4c4e866 100755 --- a/src/proxy.rs +++ b/src/core/proxy.rs @@ -1,7 +1,10 @@ //! Decouple metric definition from configuration with trait objects. -use core::{Name, AddPrefix, Kind, InputScope, InputMetric, NO_METRIC_OUTPUT, WithAttributes, Attributes, Flush}; -use error; +use core::component::{Attributes, WithAttributes, Name, AddPrefix}; +use core::Flush; +use core::input::{Kind, InputMetric, InputScope}; +use core::void::VOID_INPUT; +use core::error; use std::collections::{HashMap, BTreeMap}; use std::sync::{Arc, RwLock, Weak}; @@ -118,7 +121,7 @@ impl InnerProxy { } let (up_target, up_nslen) = self.get_effective_target(namespace) - .unwrap_or_else(|| (NO_METRIC_OUTPUT.input_dyn(), 0)); + .unwrap_or_else(|| (VOID_INPUT.input_dyn(), 0)); // update all affected metrics to next upper targeted namespace for (name, metric) in self.metrics.range_mut(namespace..) { @@ -209,7 +212,7 @@ impl InputScope for Proxy { let name2 = name.clone(); // not found, define new let (target, target_namespace_length) = inner.get_effective_target(&name) - .unwrap_or_else(|| (NO_METRIC_OUTPUT.input_dyn(), 0)); + .unwrap_or_else(|| (VOID_INPUT.input_dyn(), 0)); let metric_object = target.new_metric(name.clone(), kind); let proxy = Arc::new(ProxyMetric { name, @@ -239,10 +242,9 @@ impl WithAttributes for Proxy { #[cfg(feature = "bench")] mod bench { - use core::*; - use proxy::*; + use super::*; use test; - use bucket::Bucket; + use aggregate::bucket::Bucket; #[bench] fn proxy_marker_to_aggregate(b: &mut test::Bencher) { diff --git a/src/scheduler.rs b/src/core/scheduler.rs similarity index 98% rename from src/scheduler.rs rename to src/core/scheduler.rs index 5e94988..aa73942 100644 --- a/src/scheduler.rs +++ b/src/core/scheduler.rs @@ -1,6 +1,6 @@ //! Task scheduling facilities. -use core::InputScope; +use core::input::InputScope; use std::time::Duration; use std::thread; diff --git a/src/core/void.rs b/src/core/void.rs new file mode 100755 index 0000000..1f82b4c --- /dev/null +++ b/src/core/void.rs @@ -0,0 +1,49 @@ +use core::output::{Output, OutputScope, OutputMetric}; +use core::component::Name; +use core::input::{Kind, InputDyn}; +use core::Flush; + +use std::sync::Arc; + +lazy_static! { + /// The reference instance identifying an uninitialized metric config. + pub static ref VOID_INPUT: Arc = Arc::new(Void::metrics()); + +// /// The reference instance identifying an uninitialized metric scope. +// pub static ref NO_METRIC_SCOPE: Arc = VOID_INPUT.input_dyn(); +} + +/// Discard metrics output. +#[derive(Clone)] +pub struct Void {} + +/// Discard metrics output. +#[derive(Clone)] +pub struct VoidInput {} + +/// Discard metrics output. +#[derive(Clone)] +pub struct VoidOutput {} + +impl Void { + /// Void metrics builder. + pub fn metrics() -> Self { + Void {} + } +} + +impl Output for Void { + type SCOPE = VoidOutput; + fn output(&self) -> VoidOutput { + VoidOutput {} + } +} + +impl OutputScope for VoidOutput { + fn new_metric(&self, _name: Name, _kind: Kind) -> OutputMetric { + OutputMetric::new(|_value| {}) + } +} + +impl Flush for VoidOutput { +} diff --git a/src/lib.rs b/src/lib.rs index 6a1e987..db7f64c 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,86 +19,47 @@ extern crate num; #[cfg(feature="protobuf")] extern crate protobuf; -// FIXME required only for random seed for sampling +// FIXME required only for pcg32 seed (for sampling) extern crate time; -pub mod error; -pub use error::{Error, Result}; - -pub mod core; -pub use core::{Value, Kind, Marker, Timer, Counter, Gauge, - Flush, InputScope, Input, WithAttributes, - Name, AddPrefix, Sampled, Sampling, Buffering, Buffered, - OutputScope, Output, OutputMetric, UnsafeScope, - output_none, Void}; - #[macro_use] -pub mod macros; +mod macros; -pub mod proxy; -pub use proxy::Proxy; +mod core; +pub use core::{Flush, Value}; +pub use core::component::*; +pub use core::input::*; +pub use core::output::*; +pub use core::scheduler::*; +pub use core::out_lock::*; +pub use core::error::{Error, Result}; +pub use core::clock::{TimeHandle, mock_clock_advance, mock_clock_reset}; +pub use core::proxy::Proxy; -mod bucket; -pub use bucket::{Bucket, stats_summary, stats_all, stats_average}; +mod output; +pub use output::text::*; +pub use output::graphite::*; +pub use output::statsd::*; +pub use output::map::*; +pub use output::logging::*; -mod text; -pub use text::{Text, TextScope}; +mod aggregate; +pub use aggregate::bucket::*; +pub use aggregate::scores::*; -mod logging; -pub use logging::{Log, LogScope}; +mod cache; +pub use cache::cache_in::CachedInput; +pub use cache::cache_out::CachedOutput; -mod pcg32; +mod multi; +pub use multi::multi_in::*; +pub use multi::multi_out::*; -mod scores; -pub use scores::ScoreType; - -mod statds; -pub use statds::{Statsd, StatsdScope}; - -mod graphite; -pub use graphite::{Graphite, GraphiteScope}; - -#[cfg(feature="prometheus")] -mod prometheus; -#[cfg(feature="prometheus, proto")] -mod prometheus_proto; -#[cfg(feature="prometheus")] -pub use prometheus::{PrometheusScope, Prometheus}; - -mod map; -pub use map::StatsMap; - -mod socket; -pub use socket::RetrySocket; - -mod cache_in; -pub use cache_in::{InputScopeCache, InputCache, CachedInput}; - -mod cache_out; -pub use cache_out::{OutputScopeCache, OutputCache, CachedOutput}; - -mod multi_in; -pub use multi_in::{MultiInput, MultiInputScope}; - -mod multi_out; -pub use multi_out::{MultiOutput, MultiOutputScope}; - -mod queue_in; -pub use queue_in::{InputQueueScope, InputQueue, QueuedInput}; - -mod queue_out; -pub use queue_out::{OutputQueueScope, OutputQueue, QueuedOutput}; - -mod scheduler; -pub use scheduler::{set_schedule, CancelHandle, ScheduleFlush}; - -mod metrics; -pub use metrics::DIPSTICK_METRICS; - -mod clock; -pub use clock::{TimeHandle, mock_clock_advance, mock_clock_reset}; +mod queue; +pub use queue::queue_in::*; +pub use queue::queue_out::*; // FIXME using * to prevent "use of deprecated" warnings. #[allow(dead_code)] doesnt work? -#[macro_use] -mod deprecated; -pub use deprecated::*; +//#[macro_use] +//mod deprecated; +//pub use deprecated::*; diff --git a/src/macros.rs b/src/macros.rs index 5402d6b..9d9b7d1 100755 --- a/src/macros.rs +++ b/src/macros.rs @@ -120,8 +120,8 @@ macro_rules! __in_context { #[cfg(test)] mod test { - use core::*; - use proxy::Proxy; + use core::input::*; + use core::proxy::Proxy; metrics!{TEST: Proxy = "test_prefix" => { M1: Marker = "failed"; diff --git a/src/multi/mod.rs b/src/multi/mod.rs new file mode 100755 index 0000000..3805c28 --- /dev/null +++ b/src/multi/mod.rs @@ -0,0 +1,3 @@ +pub mod multi_in; + +pub mod multi_out; diff --git a/src/multi_in.rs b/src/multi/multi_in.rs similarity index 95% rename from src/multi_in.rs rename to src/multi/multi_in.rs index 6338c18..b7927bc 100755 --- a/src/multi_in.rs +++ b/src/multi/multi_in.rs @@ -1,7 +1,10 @@ //! Dispatch metrics to multiple sinks. -use core::{Input, InputScope, Name, AddPrefix, Kind, InputMetric, WithAttributes, Attributes, Flush, InputDyn}; -use error; +use core::Flush; +use core::input::{Kind, Input, InputScope, InputMetric, InputDyn}; +use core::component::{Attributes, WithAttributes, Name, AddPrefix}; +use core::error; + use std::sync::Arc; /// Wrap this output behind an asynchronous metrics dispatch queue. diff --git a/src/multi_out.rs b/src/multi/multi_out.rs similarity index 93% rename from src/multi_out.rs rename to src/multi/multi_out.rs index 568ed87..3e81a22 100755 --- a/src/multi_out.rs +++ b/src/multi/multi_out.rs @@ -1,7 +1,11 @@ //! Dispatch metrics to multiple sinks. -use core::{Output, OutputScope, Name, AddPrefix, Kind, OutputMetric, WithAttributes, Attributes, Flush, OutputDyn}; -use error; +use core::Flush; +use core::component::{Attributes, WithAttributes, Name, AddPrefix}; +use core::input::Kind; +use core::output::{Output, OutputMetric, OutputScope, OutputDyn}; +use core::error; + use std::rc::Rc; use std::sync::Arc; diff --git a/src/graphite.rs b/src/output/graphite.rs similarity index 95% rename from src/graphite.rs rename to src/output/graphite.rs index 3dedd40..6fd99a7 100755 --- a/src/graphite.rs +++ b/src/output/graphite.rs @@ -1,8 +1,14 @@ //! Send metrics to a graphite server. -use core::*; -use error; -use metrics; +use core::component::{Buffered, Attributes, WithAttributes, Name, AddPrefix}; +use core::{Flush, Value}; +use core::input::Kind; +use core::metrics; +use core::output::{Output, OutputScope, OutputMetric}; +use core::error; +use queue::queue_out; +use cache::cache_out; +use output::socket::RetrySocket; use std::net::ToSocketAddrs; @@ -11,7 +17,6 @@ use std::time::{SystemTime, UNIX_EPOCH}; use std::io::Write; use std::fmt::Debug; -use socket::RetrySocket; use std::rc::Rc; use std::cell::{RefCell, RefMut}; @@ -155,9 +160,6 @@ impl WithAttributes for GraphiteScope { impl Buffered for GraphiteScope {} -use queue_out; -use cache_out; - impl queue_out::QueuedOutput for Graphite {} impl cache_out::CachedOutput for Graphite {} diff --git a/src/logging.rs b/src/output/logging.rs similarity index 93% rename from src/logging.rs rename to src/output/logging.rs index d93a917..2c87c75 100755 --- a/src/logging.rs +++ b/src/output/logging.rs @@ -1,10 +1,13 @@ -use core::{Name, AddPrefix, Value, InputMetric, Kind, Input, InputScope, WithAttributes, Attributes, - Buffered, Flush}; -use error; -use std::sync::{RwLock, Arc}; -use text; -use std::io::Write; +use core::{Flush, Value}; +use core::input::{Kind, Input, InputScope, InputMetric}; +use core::component::{Attributes, WithAttributes, Buffered, Name, AddPrefix}; +use core::error; +use cache::cache_in; +use queue::queue_in; +use output::text; +use std::sync::{RwLock, Arc}; +use std::io::Write; use log; /// Buffered metrics log output. @@ -61,9 +64,6 @@ impl WithAttributes for LogScope { impl Buffered for LogScope {} -use queue_in; -use cache_in; - impl queue_in::QueuedInput for Log {} impl cache_in::CachedInput for Log {} @@ -123,7 +123,7 @@ impl Drop for LogScope { #[cfg(test)] mod test { - use core::*; + use core::input::*; #[test] fn test_to_log() { diff --git a/src/map.rs b/src/output/map.rs similarity index 90% rename from src/map.rs rename to src/output/map.rs index 314afa7..e010860 100755 --- a/src/map.rs +++ b/src/output/map.rs @@ -1,4 +1,8 @@ -use core::{Value, OutputMetric, Kind, Name, OutputScope, Flush}; +use core::{Flush, Value}; +use core::input::Kind; +use core::component::Name; +use core::output::{OutputMetric, OutputScope}; + use std::rc::Rc; use std::cell::RefCell; use std::collections::BTreeMap; diff --git a/src/output/mod.rs b/src/output/mod.rs new file mode 100755 index 0000000..bcf75c9 --- /dev/null +++ b/src/output/mod.rs @@ -0,0 +1,17 @@ +pub mod map; + +pub mod text; + +pub mod logging; + +pub mod socket; + +pub mod graphite; + +pub mod statsd; + +#[cfg(feature="prometheus")] +pub mod prometheus; + +#[cfg(feature="prometheus, proto")] +pub mod prometheus_proto; diff --git a/src/prometheus.rs b/src/output/prometheus.rs similarity index 83% rename from src/prometheus.rs rename to src/output/prometheus.rs index 452523c..46faaae 100755 --- a/src/prometheus.rs +++ b/src/output/prometheus.rs @@ -5,8 +5,11 @@ //! - Serve metrics with basic HTTP server //! - Print metrics to a buffer provided by an HTTP framework. -use core::*; -use error; +use core::{Flush, Value}; +use core::input::{Kind, Input, InputScope, InputMetric}; +use core::component::{Attributes, WithAttributes, Buffered, Buffering, Name, AddPrefix}; +use core::output::{Output, OutputMetric, OutputScope}; +use core::error; use std::net::ToSocketAddrs; use std::sync::Arc; diff --git a/src/output/prometheus_proto.rs b/src/output/prometheus_proto.rs new file mode 100755 index 0000000..1016b5e --- /dev/null +++ b/src/output/prometheus_proto.rs @@ -0,0 +1,2533 @@ +// This file is generated by rust-protobuf 2.0.2. Do not edit +// @generated + +// https://github.com/Manishearth/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy)] + +#![cfg_attr(rustfmt, rustfmt_skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unsafe_code)] +#![allow(unused_imports)] +#![allow(unused_results)] + +use protobuf::Message as Message_imported_for_functions; +use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; + +#[derive(PartialEq,Clone,Default)] +pub struct LabelPair { + // message fields + name: ::protobuf::SingularField<::std::string::String>, + value: ::protobuf::SingularField<::std::string::String>, + // special fields + unknown_fields: ::protobuf::UnknownFields, + cached_size: ::protobuf::CachedSize, +} + +impl LabelPair { + pub fn new() -> LabelPair { + ::std::default::Default::default() + } + + // optional string name = 1; + + pub fn clear_name(&mut self) { + self.name.clear(); + } + + pub fn has_name(&self) -> bool { + self.name.is_some() + } + + // Param is passed by value, moved + pub fn set_name(&mut self, v: ::std::string::String) { + self.name = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_name(&mut self) -> &mut ::std::string::String { + if self.name.is_none() { + self.name.set_default(); + } + self.name.as_mut().unwrap() + } + + // Take field + pub fn take_name(&mut self) -> ::std::string::String { + self.name.take().unwrap_or_else(|| ::std::string::String::new()) + } + + pub fn get_name(&self) -> &str { + match self.name.as_ref() { + Some(v) => &v, + None => "", + } + } + + // optional string value = 2; + + pub fn clear_value(&mut self) { + self.value.clear(); + } + + pub fn has_value(&self) -> bool { + self.value.is_some() + } + + // Param is passed by value, moved + pub fn set_value(&mut self, v: ::std::string::String) { + self.value = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_value(&mut self) -> &mut ::std::string::String { + if self.value.is_none() { + self.value.set_default(); + } + self.value.as_mut().unwrap() + } + + // Take field + pub fn take_value(&mut self) -> ::std::string::String { + self.value.take().unwrap_or_else(|| ::std::string::String::new()) + } + + pub fn get_value(&self) -> &str { + match self.value.as_ref() { + Some(v) => &v, + None => "", + } + } +} + +impl ::protobuf::Message for LabelPair { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.name)?; + }, + 2 => { + ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.value)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(ref v) = self.name.as_ref() { + my_size += ::protobuf::rt::string_size(1, &v); + } + if let Some(ref v) = self.value.as_ref() { + my_size += ::protobuf::rt::string_size(2, &v); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if let Some(ref v) = self.name.as_ref() { + os.write_string(1, &v)?; + } + if let Some(ref v) = self.value.as_ref() { + os.write_string(2, &v)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn as_any_mut(&mut self) -> &mut ::std::any::Any { + self as &mut ::std::any::Any + } + fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> LabelPair { + LabelPair::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "name", + |m: &LabelPair| { &m.name }, + |m: &mut LabelPair| { &mut m.name }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "value", + |m: &LabelPair| { &m.value }, + |m: &mut LabelPair| { &mut m.value }, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "LabelPair", + fields, + file_descriptor_proto() + ) + }) + } + } + + fn default_instance() -> &'static LabelPair { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const LabelPair, + }; + unsafe { + instance.get(LabelPair::new) + } + } +} + +impl ::protobuf::Clear for LabelPair { + fn clear(&mut self) { + self.clear_name(); + self.clear_value(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for LabelPair { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for LabelPair { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct Gauge { + // message fields + value: ::std::option::Option, + // special fields + unknown_fields: ::protobuf::UnknownFields, + cached_size: ::protobuf::CachedSize, +} + +impl Gauge { + pub fn new() -> Gauge { + ::std::default::Default::default() + } + + // optional double value = 1; + + pub fn clear_value(&mut self) { + self.value = ::std::option::Option::None; + } + + pub fn has_value(&self) -> bool { + self.value.is_some() + } + + // Param is passed by value, moved + pub fn set_value(&mut self, v: f64) { + self.value = ::std::option::Option::Some(v); + } + + pub fn get_value(&self) -> f64 { + self.value.unwrap_or(0.) + } +} + +impl ::protobuf::Message for Gauge { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + if wire_type != ::protobuf::wire_format::WireTypeFixed64 { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_double()?; + self.value = ::std::option::Option::Some(tmp); + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(v) = self.value { + my_size += 9; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if let Some(v) = self.value { + os.write_double(1, v)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn as_any_mut(&mut self) -> &mut ::std::any::Any { + self as &mut ::std::any::Any + } + fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> Gauge { + Gauge::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeDouble>( + "value", + |m: &Gauge| { &m.value }, + |m: &mut Gauge| { &mut m.value }, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "Gauge", + fields, + file_descriptor_proto() + ) + }) + } + } + + fn default_instance() -> &'static Gauge { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const Gauge, + }; + unsafe { + instance.get(Gauge::new) + } + } +} + +impl ::protobuf::Clear for Gauge { + fn clear(&mut self) { + self.clear_value(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for Gauge { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for Gauge { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct Counter { + // message fields + value: ::std::option::Option, + // special fields + unknown_fields: ::protobuf::UnknownFields, + cached_size: ::protobuf::CachedSize, +} + +impl Counter { + pub fn new() -> Counter { + ::std::default::Default::default() + } + + // optional double value = 1; + + pub fn clear_value(&mut self) { + self.value = ::std::option::Option::None; + } + + pub fn has_value(&self) -> bool { + self.value.is_some() + } + + // Param is passed by value, moved + pub fn set_value(&mut self, v: f64) { + self.value = ::std::option::Option::Some(v); + } + + pub fn get_value(&self) -> f64 { + self.value.unwrap_or(0.) + } +} + +impl ::protobuf::Message for Counter { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + if wire_type != ::protobuf::wire_format::WireTypeFixed64 { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_double()?; + self.value = ::std::option::Option::Some(tmp); + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(v) = self.value { + my_size += 9; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if let Some(v) = self.value { + os.write_double(1, v)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn as_any_mut(&mut self) -> &mut ::std::any::Any { + self as &mut ::std::any::Any + } + fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> Counter { + Counter::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeDouble>( + "value", + |m: &Counter| { &m.value }, + |m: &mut Counter| { &mut m.value }, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "Counter", + fields, + file_descriptor_proto() + ) + }) + } + } + + fn default_instance() -> &'static Counter { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const Counter, + }; + unsafe { + instance.get(Counter::new) + } + } +} + +impl ::protobuf::Clear for Counter { + fn clear(&mut self) { + self.clear_value(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for Counter { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for Counter { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct Quantile { + // message fields + quantile: ::std::option::Option, + value: ::std::option::Option, + // special fields + unknown_fields: ::protobuf::UnknownFields, + cached_size: ::protobuf::CachedSize, +} + +impl Quantile { + pub fn new() -> Quantile { + ::std::default::Default::default() + } + + // optional double quantile = 1; + + pub fn clear_quantile(&mut self) { + self.quantile = ::std::option::Option::None; + } + + pub fn has_quantile(&self) -> bool { + self.quantile.is_some() + } + + // Param is passed by value, moved + pub fn set_quantile(&mut self, v: f64) { + self.quantile = ::std::option::Option::Some(v); + } + + pub fn get_quantile(&self) -> f64 { + self.quantile.unwrap_or(0.) + } + + // optional double value = 2; + + pub fn clear_value(&mut self) { + self.value = ::std::option::Option::None; + } + + pub fn has_value(&self) -> bool { + self.value.is_some() + } + + // Param is passed by value, moved + pub fn set_value(&mut self, v: f64) { + self.value = ::std::option::Option::Some(v); + } + + pub fn get_value(&self) -> f64 { + self.value.unwrap_or(0.) + } +} + +impl ::protobuf::Message for Quantile { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + if wire_type != ::protobuf::wire_format::WireTypeFixed64 { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_double()?; + self.quantile = ::std::option::Option::Some(tmp); + }, + 2 => { + if wire_type != ::protobuf::wire_format::WireTypeFixed64 { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_double()?; + self.value = ::std::option::Option::Some(tmp); + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(v) = self.quantile { + my_size += 9; + } + if let Some(v) = self.value { + my_size += 9; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if let Some(v) = self.quantile { + os.write_double(1, v)?; + } + if let Some(v) = self.value { + os.write_double(2, v)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn as_any_mut(&mut self) -> &mut ::std::any::Any { + self as &mut ::std::any::Any + } + fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> Quantile { + Quantile::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeDouble>( + "quantile", + |m: &Quantile| { &m.quantile }, + |m: &mut Quantile| { &mut m.quantile }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeDouble>( + "value", + |m: &Quantile| { &m.value }, + |m: &mut Quantile| { &mut m.value }, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "Quantile", + fields, + file_descriptor_proto() + ) + }) + } + } + + fn default_instance() -> &'static Quantile { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const Quantile, + }; + unsafe { + instance.get(Quantile::new) + } + } +} + +impl ::protobuf::Clear for Quantile { + fn clear(&mut self) { + self.clear_quantile(); + self.clear_value(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for Quantile { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for Quantile { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct Summary { + // message fields + sample_count: ::std::option::Option, + sample_sum: ::std::option::Option, + quantile: ::protobuf::RepeatedField, + // special fields + unknown_fields: ::protobuf::UnknownFields, + cached_size: ::protobuf::CachedSize, +} + +impl Summary { + pub fn new() -> Summary { + ::std::default::Default::default() + } + + // optional uint64 sample_count = 1; + + pub fn clear_sample_count(&mut self) { + self.sample_count = ::std::option::Option::None; + } + + pub fn has_sample_count(&self) -> bool { + self.sample_count.is_some() + } + + // Param is passed by value, moved + pub fn set_sample_count(&mut self, v: u64) { + self.sample_count = ::std::option::Option::Some(v); + } + + pub fn get_sample_count(&self) -> u64 { + self.sample_count.unwrap_or(0) + } + + // optional double sample_sum = 2; + + pub fn clear_sample_sum(&mut self) { + self.sample_sum = ::std::option::Option::None; + } + + pub fn has_sample_sum(&self) -> bool { + self.sample_sum.is_some() + } + + // Param is passed by value, moved + pub fn set_sample_sum(&mut self, v: f64) { + self.sample_sum = ::std::option::Option::Some(v); + } + + pub fn get_sample_sum(&self) -> f64 { + self.sample_sum.unwrap_or(0.) + } + + // repeated .io.prometheus.client.Quantile quantile = 3; + + pub fn clear_quantile(&mut self) { + self.quantile.clear(); + } + + // Param is passed by value, moved + pub fn set_quantile(&mut self, v: ::protobuf::RepeatedField) { + self.quantile = v; + } + + // Mutable pointer to the field. + pub fn mut_quantile(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.quantile + } + + // Take field + pub fn take_quantile(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.quantile, ::protobuf::RepeatedField::new()) + } + + pub fn get_quantile(&self) -> &[Quantile] { + &self.quantile + } +} + +impl ::protobuf::Message for Summary { + fn is_initialized(&self) -> bool { + for v in &self.quantile { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_uint64()?; + self.sample_count = ::std::option::Option::Some(tmp); + }, + 2 => { + if wire_type != ::protobuf::wire_format::WireTypeFixed64 { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_double()?; + self.sample_sum = ::std::option::Option::Some(tmp); + }, + 3 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.quantile)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(v) = self.sample_count { + my_size += ::protobuf::rt::value_size(1, v, ::protobuf::wire_format::WireTypeVarint); + } + if let Some(v) = self.sample_sum { + my_size += 9; + } + for value in &self.quantile { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if let Some(v) = self.sample_count { + os.write_uint64(1, v)?; + } + if let Some(v) = self.sample_sum { + os.write_double(2, v)?; + } + for v in &self.quantile { + os.write_tag(3, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn as_any_mut(&mut self) -> &mut ::std::any::Any { + self as &mut ::std::any::Any + } + fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> Summary { + Summary::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( + "sample_count", + |m: &Summary| { &m.sample_count }, + |m: &mut Summary| { &mut m.sample_count }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeDouble>( + "sample_sum", + |m: &Summary| { &m.sample_sum }, + |m: &mut Summary| { &mut m.sample_sum }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "quantile", + |m: &Summary| { &m.quantile }, + |m: &mut Summary| { &mut m.quantile }, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "Summary", + fields, + file_descriptor_proto() + ) + }) + } + } + + fn default_instance() -> &'static Summary { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const Summary, + }; + unsafe { + instance.get(Summary::new) + } + } +} + +impl ::protobuf::Clear for Summary { + fn clear(&mut self) { + self.clear_sample_count(); + self.clear_sample_sum(); + self.clear_quantile(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for Summary { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for Summary { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct Untyped { + // message fields + value: ::std::option::Option, + // special fields + unknown_fields: ::protobuf::UnknownFields, + cached_size: ::protobuf::CachedSize, +} + +impl Untyped { + pub fn new() -> Untyped { + ::std::default::Default::default() + } + + // optional double value = 1; + + pub fn clear_value(&mut self) { + self.value = ::std::option::Option::None; + } + + pub fn has_value(&self) -> bool { + self.value.is_some() + } + + // Param is passed by value, moved + pub fn set_value(&mut self, v: f64) { + self.value = ::std::option::Option::Some(v); + } + + pub fn get_value(&self) -> f64 { + self.value.unwrap_or(0.) + } +} + +impl ::protobuf::Message for Untyped { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + if wire_type != ::protobuf::wire_format::WireTypeFixed64 { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_double()?; + self.value = ::std::option::Option::Some(tmp); + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(v) = self.value { + my_size += 9; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if let Some(v) = self.value { + os.write_double(1, v)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn as_any_mut(&mut self) -> &mut ::std::any::Any { + self as &mut ::std::any::Any + } + fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> Untyped { + Untyped::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeDouble>( + "value", + |m: &Untyped| { &m.value }, + |m: &mut Untyped| { &mut m.value }, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "Untyped", + fields, + file_descriptor_proto() + ) + }) + } + } + + fn default_instance() -> &'static Untyped { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const Untyped, + }; + unsafe { + instance.get(Untyped::new) + } + } +} + +impl ::protobuf::Clear for Untyped { + fn clear(&mut self) { + self.clear_value(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for Untyped { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for Untyped { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct Histogram { + // message fields + sample_count: ::std::option::Option, + sample_sum: ::std::option::Option, + bucket: ::protobuf::RepeatedField, + // special fields + unknown_fields: ::protobuf::UnknownFields, + cached_size: ::protobuf::CachedSize, +} + +impl Histogram { + pub fn new() -> Histogram { + ::std::default::Default::default() + } + + // optional uint64 sample_count = 1; + + pub fn clear_sample_count(&mut self) { + self.sample_count = ::std::option::Option::None; + } + + pub fn has_sample_count(&self) -> bool { + self.sample_count.is_some() + } + + // Param is passed by value, moved + pub fn set_sample_count(&mut self, v: u64) { + self.sample_count = ::std::option::Option::Some(v); + } + + pub fn get_sample_count(&self) -> u64 { + self.sample_count.unwrap_or(0) + } + + // optional double sample_sum = 2; + + pub fn clear_sample_sum(&mut self) { + self.sample_sum = ::std::option::Option::None; + } + + pub fn has_sample_sum(&self) -> bool { + self.sample_sum.is_some() + } + + // Param is passed by value, moved + pub fn set_sample_sum(&mut self, v: f64) { + self.sample_sum = ::std::option::Option::Some(v); + } + + pub fn get_sample_sum(&self) -> f64 { + self.sample_sum.unwrap_or(0.) + } + + // repeated .io.prometheus.client.Bucket bucket = 3; + + pub fn clear_bucket(&mut self) { + self.bucket.clear(); + } + + // Param is passed by value, moved + pub fn set_bucket(&mut self, v: ::protobuf::RepeatedField) { + self.bucket = v; + } + + // Mutable pointer to the field. + pub fn mut_bucket(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.bucket + } + + // Take field + pub fn take_bucket(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.bucket, ::protobuf::RepeatedField::new()) + } + + pub fn get_bucket(&self) -> &[Bucket] { + &self.bucket + } +} + +impl ::protobuf::Message for Histogram { + fn is_initialized(&self) -> bool { + for v in &self.bucket { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_uint64()?; + self.sample_count = ::std::option::Option::Some(tmp); + }, + 2 => { + if wire_type != ::protobuf::wire_format::WireTypeFixed64 { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_double()?; + self.sample_sum = ::std::option::Option::Some(tmp); + }, + 3 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.bucket)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(v) = self.sample_count { + my_size += ::protobuf::rt::value_size(1, v, ::protobuf::wire_format::WireTypeVarint); + } + if let Some(v) = self.sample_sum { + my_size += 9; + } + for value in &self.bucket { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if let Some(v) = self.sample_count { + os.write_uint64(1, v)?; + } + if let Some(v) = self.sample_sum { + os.write_double(2, v)?; + } + for v in &self.bucket { + os.write_tag(3, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn as_any_mut(&mut self) -> &mut ::std::any::Any { + self as &mut ::std::any::Any + } + fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> Histogram { + Histogram::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( + "sample_count", + |m: &Histogram| { &m.sample_count }, + |m: &mut Histogram| { &mut m.sample_count }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeDouble>( + "sample_sum", + |m: &Histogram| { &m.sample_sum }, + |m: &mut Histogram| { &mut m.sample_sum }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "bucket", + |m: &Histogram| { &m.bucket }, + |m: &mut Histogram| { &mut m.bucket }, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "Histogram", + fields, + file_descriptor_proto() + ) + }) + } + } + + fn default_instance() -> &'static Histogram { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const Histogram, + }; + unsafe { + instance.get(Histogram::new) + } + } +} + +impl ::protobuf::Clear for Histogram { + fn clear(&mut self) { + self.clear_sample_count(); + self.clear_sample_sum(); + self.clear_bucket(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for Histogram { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for Histogram { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct Bucket { + // message fields + cumulative_count: ::std::option::Option, + upper_bound: ::std::option::Option, + // special fields + unknown_fields: ::protobuf::UnknownFields, + cached_size: ::protobuf::CachedSize, +} + +impl Bucket { + pub fn new() -> Bucket { + ::std::default::Default::default() + } + + // optional uint64 cumulative_count = 1; + + pub fn clear_cumulative_count(&mut self) { + self.cumulative_count = ::std::option::Option::None; + } + + pub fn has_cumulative_count(&self) -> bool { + self.cumulative_count.is_some() + } + + // Param is passed by value, moved + pub fn set_cumulative_count(&mut self, v: u64) { + self.cumulative_count = ::std::option::Option::Some(v); + } + + pub fn get_cumulative_count(&self) -> u64 { + self.cumulative_count.unwrap_or(0) + } + + // optional double upper_bound = 2; + + pub fn clear_upper_bound(&mut self) { + self.upper_bound = ::std::option::Option::None; + } + + pub fn has_upper_bound(&self) -> bool { + self.upper_bound.is_some() + } + + // Param is passed by value, moved + pub fn set_upper_bound(&mut self, v: f64) { + self.upper_bound = ::std::option::Option::Some(v); + } + + pub fn get_upper_bound(&self) -> f64 { + self.upper_bound.unwrap_or(0.) + } +} + +impl ::protobuf::Message for Bucket { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_uint64()?; + self.cumulative_count = ::std::option::Option::Some(tmp); + }, + 2 => { + if wire_type != ::protobuf::wire_format::WireTypeFixed64 { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_double()?; + self.upper_bound = ::std::option::Option::Some(tmp); + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(v) = self.cumulative_count { + my_size += ::protobuf::rt::value_size(1, v, ::protobuf::wire_format::WireTypeVarint); + } + if let Some(v) = self.upper_bound { + my_size += 9; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if let Some(v) = self.cumulative_count { + os.write_uint64(1, v)?; + } + if let Some(v) = self.upper_bound { + os.write_double(2, v)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn as_any_mut(&mut self) -> &mut ::std::any::Any { + self as &mut ::std::any::Any + } + fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> Bucket { + Bucket::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( + "cumulative_count", + |m: &Bucket| { &m.cumulative_count }, + |m: &mut Bucket| { &mut m.cumulative_count }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeDouble>( + "upper_bound", + |m: &Bucket| { &m.upper_bound }, + |m: &mut Bucket| { &mut m.upper_bound }, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "Bucket", + fields, + file_descriptor_proto() + ) + }) + } + } + + fn default_instance() -> &'static Bucket { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const Bucket, + }; + unsafe { + instance.get(Bucket::new) + } + } +} + +impl ::protobuf::Clear for Bucket { + fn clear(&mut self) { + self.clear_cumulative_count(); + self.clear_upper_bound(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for Bucket { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for Bucket { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct Metric { + // message fields + label: ::protobuf::RepeatedField, + gauge: ::protobuf::SingularPtrField, + counter: ::protobuf::SingularPtrField, + summary: ::protobuf::SingularPtrField, + untyped: ::protobuf::SingularPtrField, + histogram: ::protobuf::SingularPtrField, + timestamp_ms: ::std::option::Option, + // special fields + unknown_fields: ::protobuf::UnknownFields, + cached_size: ::protobuf::CachedSize, +} + +impl Metric { + pub fn new() -> Metric { + ::std::default::Default::default() + } + + // repeated .io.prometheus.client.LabelPair label = 1; + + pub fn clear_label(&mut self) { + self.label.clear(); + } + + // Param is passed by value, moved + pub fn set_label(&mut self, v: ::protobuf::RepeatedField) { + self.label = v; + } + + // Mutable pointer to the field. + pub fn mut_label(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.label + } + + // Take field + pub fn take_label(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.label, ::protobuf::RepeatedField::new()) + } + + pub fn get_label(&self) -> &[LabelPair] { + &self.label + } + + // optional .io.prometheus.client.Gauge gauge = 2; + + pub fn clear_gauge(&mut self) { + self.gauge.clear(); + } + + pub fn has_gauge(&self) -> bool { + self.gauge.is_some() + } + + // Param is passed by value, moved + pub fn set_gauge(&mut self, v: Gauge) { + self.gauge = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_gauge(&mut self) -> &mut Gauge { + if self.gauge.is_none() { + self.gauge.set_default(); + } + self.gauge.as_mut().unwrap() + } + + // Take field + pub fn take_gauge(&mut self) -> Gauge { + self.gauge.take().unwrap_or_else(|| Gauge::new()) + } + + pub fn get_gauge(&self) -> &Gauge { + self.gauge.as_ref().unwrap_or_else(|| Gauge::default_instance()) + } + + // optional .io.prometheus.client.Counter counter = 3; + + pub fn clear_counter(&mut self) { + self.counter.clear(); + } + + pub fn has_counter(&self) -> bool { + self.counter.is_some() + } + + // Param is passed by value, moved + pub fn set_counter(&mut self, v: Counter) { + self.counter = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_counter(&mut self) -> &mut Counter { + if self.counter.is_none() { + self.counter.set_default(); + } + self.counter.as_mut().unwrap() + } + + // Take field + pub fn take_counter(&mut self) -> Counter { + self.counter.take().unwrap_or_else(|| Counter::new()) + } + + pub fn get_counter(&self) -> &Counter { + self.counter.as_ref().unwrap_or_else(|| Counter::default_instance()) + } + + // optional .io.prometheus.client.Summary summary = 4; + + pub fn clear_summary(&mut self) { + self.summary.clear(); + } + + pub fn has_summary(&self) -> bool { + self.summary.is_some() + } + + // Param is passed by value, moved + pub fn set_summary(&mut self, v: Summary) { + self.summary = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_summary(&mut self) -> &mut Summary { + if self.summary.is_none() { + self.summary.set_default(); + } + self.summary.as_mut().unwrap() + } + + // Take field + pub fn take_summary(&mut self) -> Summary { + self.summary.take().unwrap_or_else(|| Summary::new()) + } + + pub fn get_summary(&self) -> &Summary { + self.summary.as_ref().unwrap_or_else(|| Summary::default_instance()) + } + + // optional .io.prometheus.client.Untyped untyped = 5; + + pub fn clear_untyped(&mut self) { + self.untyped.clear(); + } + + pub fn has_untyped(&self) -> bool { + self.untyped.is_some() + } + + // Param is passed by value, moved + pub fn set_untyped(&mut self, v: Untyped) { + self.untyped = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_untyped(&mut self) -> &mut Untyped { + if self.untyped.is_none() { + self.untyped.set_default(); + } + self.untyped.as_mut().unwrap() + } + + // Take field + pub fn take_untyped(&mut self) -> Untyped { + self.untyped.take().unwrap_or_else(|| Untyped::new()) + } + + pub fn get_untyped(&self) -> &Untyped { + self.untyped.as_ref().unwrap_or_else(|| Untyped::default_instance()) + } + + // optional .io.prometheus.client.Histogram histogram = 7; + + pub fn clear_histogram(&mut self) { + self.histogram.clear(); + } + + pub fn has_histogram(&self) -> bool { + self.histogram.is_some() + } + + // Param is passed by value, moved + pub fn set_histogram(&mut self, v: Histogram) { + self.histogram = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_histogram(&mut self) -> &mut Histogram { + if self.histogram.is_none() { + self.histogram.set_default(); + } + self.histogram.as_mut().unwrap() + } + + // Take field + pub fn take_histogram(&mut self) -> Histogram { + self.histogram.take().unwrap_or_else(|| Histogram::new()) + } + + pub fn get_histogram(&self) -> &Histogram { + self.histogram.as_ref().unwrap_or_else(|| Histogram::default_instance()) + } + + // optional int64 timestamp_ms = 6; + + pub fn clear_timestamp_ms(&mut self) { + self.timestamp_ms = ::std::option::Option::None; + } + + pub fn has_timestamp_ms(&self) -> bool { + self.timestamp_ms.is_some() + } + + // Param is passed by value, moved + pub fn set_timestamp_ms(&mut self, v: i64) { + self.timestamp_ms = ::std::option::Option::Some(v); + } + + pub fn get_timestamp_ms(&self) -> i64 { + self.timestamp_ms.unwrap_or(0) + } +} + +impl ::protobuf::Message for Metric { + fn is_initialized(&self) -> bool { + for v in &self.label { + if !v.is_initialized() { + return false; + } + }; + for v in &self.gauge { + if !v.is_initialized() { + return false; + } + }; + for v in &self.counter { + if !v.is_initialized() { + return false; + } + }; + for v in &self.summary { + if !v.is_initialized() { + return false; + } + }; + for v in &self.untyped { + if !v.is_initialized() { + return false; + } + }; + for v in &self.histogram { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.label)?; + }, + 2 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.gauge)?; + }, + 3 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.counter)?; + }, + 4 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.summary)?; + }, + 5 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.untyped)?; + }, + 7 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.histogram)?; + }, + 6 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_int64()?; + self.timestamp_ms = ::std::option::Option::Some(tmp); + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + for value in &self.label { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + if let Some(ref v) = self.gauge.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + if let Some(ref v) = self.counter.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + if let Some(ref v) = self.summary.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + if let Some(ref v) = self.untyped.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + if let Some(ref v) = self.histogram.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + if let Some(v) = self.timestamp_ms { + my_size += ::protobuf::rt::value_size(6, v, ::protobuf::wire_format::WireTypeVarint); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + for v in &self.label { + os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + if let Some(ref v) = self.gauge.as_ref() { + os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + if let Some(ref v) = self.counter.as_ref() { + os.write_tag(3, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + if let Some(ref v) = self.summary.as_ref() { + os.write_tag(4, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + if let Some(ref v) = self.untyped.as_ref() { + os.write_tag(5, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + if let Some(ref v) = self.histogram.as_ref() { + os.write_tag(7, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + if let Some(v) = self.timestamp_ms { + os.write_int64(6, v)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn as_any_mut(&mut self) -> &mut ::std::any::Any { + self as &mut ::std::any::Any + } + fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> Metric { + Metric::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "label", + |m: &Metric| { &m.label }, + |m: &mut Metric| { &mut m.label }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "gauge", + |m: &Metric| { &m.gauge }, + |m: &mut Metric| { &mut m.gauge }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "counter", + |m: &Metric| { &m.counter }, + |m: &mut Metric| { &mut m.counter }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "summary", + |m: &Metric| { &m.summary }, + |m: &mut Metric| { &mut m.summary }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "untyped", + |m: &Metric| { &m.untyped }, + |m: &mut Metric| { &mut m.untyped }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "histogram", + |m: &Metric| { &m.histogram }, + |m: &mut Metric| { &mut m.histogram }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeInt64>( + "timestamp_ms", + |m: &Metric| { &m.timestamp_ms }, + |m: &mut Metric| { &mut m.timestamp_ms }, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "Metric", + fields, + file_descriptor_proto() + ) + }) + } + } + + fn default_instance() -> &'static Metric { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const Metric, + }; + unsafe { + instance.get(Metric::new) + } + } +} + +impl ::protobuf::Clear for Metric { + fn clear(&mut self) { + self.clear_label(); + self.clear_gauge(); + self.clear_counter(); + self.clear_summary(); + self.clear_untyped(); + self.clear_histogram(); + self.clear_timestamp_ms(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for Metric { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for Metric { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct MetricFamily { + // message fields + name: ::protobuf::SingularField<::std::string::String>, + help: ::protobuf::SingularField<::std::string::String>, + field_type: ::std::option::Option, + metric: ::protobuf::RepeatedField, + // special fields + unknown_fields: ::protobuf::UnknownFields, + cached_size: ::protobuf::CachedSize, +} + +impl MetricFamily { + pub fn new() -> MetricFamily { + ::std::default::Default::default() + } + + // optional string name = 1; + + pub fn clear_name(&mut self) { + self.name.clear(); + } + + pub fn has_name(&self) -> bool { + self.name.is_some() + } + + // Param is passed by value, moved + pub fn set_name(&mut self, v: ::std::string::String) { + self.name = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_name(&mut self) -> &mut ::std::string::String { + if self.name.is_none() { + self.name.set_default(); + } + self.name.as_mut().unwrap() + } + + // Take field + pub fn take_name(&mut self) -> ::std::string::String { + self.name.take().unwrap_or_else(|| ::std::string::String::new()) + } + + pub fn get_name(&self) -> &str { + match self.name.as_ref() { + Some(v) => &v, + None => "", + } + } + + // optional string help = 2; + + pub fn clear_help(&mut self) { + self.help.clear(); + } + + pub fn has_help(&self) -> bool { + self.help.is_some() + } + + // Param is passed by value, moved + pub fn set_help(&mut self, v: ::std::string::String) { + self.help = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_help(&mut self) -> &mut ::std::string::String { + if self.help.is_none() { + self.help.set_default(); + } + self.help.as_mut().unwrap() + } + + // Take field + pub fn take_help(&mut self) -> ::std::string::String { + self.help.take().unwrap_or_else(|| ::std::string::String::new()) + } + + pub fn get_help(&self) -> &str { + match self.help.as_ref() { + Some(v) => &v, + None => "", + } + } + + // optional .io.prometheus.client.MetricType type = 3; + + pub fn clear_field_type(&mut self) { + self.field_type = ::std::option::Option::None; + } + + pub fn has_field_type(&self) -> bool { + self.field_type.is_some() + } + + // Param is passed by value, moved + pub fn set_field_type(&mut self, v: MetricType) { + self.field_type = ::std::option::Option::Some(v); + } + + pub fn get_field_type(&self) -> MetricType { + self.field_type.unwrap_or(MetricType::COUNTER) + } + + // repeated .io.prometheus.client.Metric metric = 4; + + pub fn clear_metric(&mut self) { + self.metric.clear(); + } + + // Param is passed by value, moved + pub fn set_metric(&mut self, v: ::protobuf::RepeatedField) { + self.metric = v; + } + + // Mutable pointer to the field. + pub fn mut_metric(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.metric + } + + // Take field + pub fn take_metric(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.metric, ::protobuf::RepeatedField::new()) + } + + pub fn get_metric(&self) -> &[Metric] { + &self.metric + } +} + +impl ::protobuf::Message for MetricFamily { + fn is_initialized(&self) -> bool { + for v in &self.metric { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.name)?; + }, + 2 => { + ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.help)?; + }, + 3 => { + ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.field_type, 3, &mut self.unknown_fields)? + }, + 4 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.metric)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(ref v) = self.name.as_ref() { + my_size += ::protobuf::rt::string_size(1, &v); + } + if let Some(ref v) = self.help.as_ref() { + my_size += ::protobuf::rt::string_size(2, &v); + } + if let Some(v) = self.field_type { + my_size += ::protobuf::rt::enum_size(3, v); + } + for value in &self.metric { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if let Some(ref v) = self.name.as_ref() { + os.write_string(1, &v)?; + } + if let Some(ref v) = self.help.as_ref() { + os.write_string(2, &v)?; + } + if let Some(v) = self.field_type { + os.write_enum(3, v.value())?; + } + for v in &self.metric { + os.write_tag(4, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn as_any_mut(&mut self) -> &mut ::std::any::Any { + self as &mut ::std::any::Any + } + fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> MetricFamily { + MetricFamily::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "name", + |m: &MetricFamily| { &m.name }, + |m: &mut MetricFamily| { &mut m.name }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "help", + |m: &MetricFamily| { &m.help }, + |m: &mut MetricFamily| { &mut m.help }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + "type", + |m: &MetricFamily| { &m.field_type }, + |m: &mut MetricFamily| { &mut m.field_type }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "metric", + |m: &MetricFamily| { &m.metric }, + |m: &mut MetricFamily| { &mut m.metric }, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "MetricFamily", + fields, + file_descriptor_proto() + ) + }) + } + } + + fn default_instance() -> &'static MetricFamily { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const MetricFamily, + }; + unsafe { + instance.get(MetricFamily::new) + } + } +} + +impl ::protobuf::Clear for MetricFamily { + fn clear(&mut self) { + self.clear_name(); + self.clear_help(); + self.clear_field_type(); + self.clear_metric(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for MetricFamily { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for MetricFamily { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum MetricType { + COUNTER = 0, + GAUGE = 1, + SUMMARY = 2, + UNTYPED = 3, + HISTOGRAM = 4, +} + +impl ::protobuf::ProtobufEnum for MetricType { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(MetricType::COUNTER), + 1 => ::std::option::Option::Some(MetricType::GAUGE), + 2 => ::std::option::Option::Some(MetricType::SUMMARY), + 3 => ::std::option::Option::Some(MetricType::UNTYPED), + 4 => ::std::option::Option::Some(MetricType::HISTOGRAM), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [MetricType] = &[ + MetricType::COUNTER, + MetricType::GAUGE, + MetricType::SUMMARY, + MetricType::UNTYPED, + MetricType::HISTOGRAM, + ]; + values + } + + fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::EnumDescriptor, + }; + unsafe { + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new("MetricType", file_descriptor_proto()) + }) + } + } +} + +impl ::std::marker::Copy for MetricType { +} + +impl ::protobuf::reflect::ProtobufValue for MetricType { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Enum(self.descriptor()) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x1dschema/prometheus_proto.proto\x12\x14io.prometheus.client\"5\n\tLa\ + belPair\x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04name\x12\x14\n\x05value\ + \x18\x02\x20\x01(\tR\x05value\"\x1d\n\x05Gauge\x12\x14\n\x05value\x18\ + \x01\x20\x01(\x01R\x05value\"\x1f\n\x07Counter\x12\x14\n\x05value\x18\ + \x01\x20\x01(\x01R\x05value\"<\n\x08Quantile\x12\x1a\n\x08quantile\x18\ + \x01\x20\x01(\x01R\x08quantile\x12\x14\n\x05value\x18\x02\x20\x01(\x01R\ + \x05value\"\x87\x01\n\x07Summary\x12!\n\x0csample_count\x18\x01\x20\x01(\ + \x04R\x0bsampleCount\x12\x1d\n\nsample_sum\x18\x02\x20\x01(\x01R\tsample\ + Sum\x12:\n\x08quantile\x18\x03\x20\x03(\x0b2\x1e.io.prometheus.client.Qu\ + antileR\x08quantile\"\x1f\n\x07Untyped\x12\x14\n\x05value\x18\x01\x20\ + \x01(\x01R\x05value\"\x83\x01\n\tHistogram\x12!\n\x0csample_count\x18\ + \x01\x20\x01(\x04R\x0bsampleCount\x12\x1d\n\nsample_sum\x18\x02\x20\x01(\ + \x01R\tsampleSum\x124\n\x06bucket\x18\x03\x20\x03(\x0b2\x1c.io.prometheu\ + s.client.BucketR\x06bucket\"T\n\x06Bucket\x12)\n\x10cumulative_count\x18\ + \x01\x20\x01(\x04R\x0fcumulativeCount\x12\x1f\n\x0bupper_bound\x18\x02\ + \x20\x01(\x01R\nupperBound\"\xff\x02\n\x06Metric\x125\n\x05label\x18\x01\ + \x20\x03(\x0b2\x1f.io.prometheus.client.LabelPairR\x05label\x121\n\x05ga\ + uge\x18\x02\x20\x01(\x0b2\x1b.io.prometheus.client.GaugeR\x05gauge\x127\ + \n\x07counter\x18\x03\x20\x01(\x0b2\x1d.io.prometheus.client.CounterR\ + \x07counter\x127\n\x07summary\x18\x04\x20\x01(\x0b2\x1d.io.prometheus.cl\ + ient.SummaryR\x07summary\x127\n\x07untyped\x18\x05\x20\x01(\x0b2\x1d.io.\ + prometheus.client.UntypedR\x07untyped\x12=\n\thistogram\x18\x07\x20\x01(\ + \x0b2\x1f.io.prometheus.client.HistogramR\thistogram\x12!\n\x0ctimestamp\ + _ms\x18\x06\x20\x01(\x03R\x0btimestampMs\"\xa2\x01\n\x0cMetricFamily\x12\ + \x12\n\x04name\x18\x01\x20\x01(\tR\x04name\x12\x12\n\x04help\x18\x02\x20\ + \x01(\tR\x04help\x124\n\x04type\x18\x03\x20\x01(\x0e2\x20.io.prometheus.\ + client.MetricTypeR\x04type\x124\n\x06metric\x18\x04\x20\x03(\x0b2\x1c.io\ + .prometheus.client.MetricR\x06metric*M\n\nMetricType\x12\x0b\n\x07COUNTE\ + R\x10\0\x12\t\n\x05GAUGE\x10\x01\x12\x0b\n\x07SUMMARY\x10\x02\x12\x0b\n\ + \x07UNTYPED\x10\x03\x12\r\n\tHISTOGRAM\x10\x04B\x16\n\x14io.prometheus.c\ + lient\ +"; + +static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, +}; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + unsafe { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) + } +} diff --git a/src/socket.rs b/src/output/socket.rs old mode 100644 new mode 100755 similarity index 100% rename from src/socket.rs rename to src/output/socket.rs diff --git a/src/statds.rs b/src/output/statsd.rs similarity index 95% rename from src/statds.rs rename to src/output/statsd.rs index 66e069d..334620c 100755 --- a/src/statds.rs +++ b/src/output/statsd.rs @@ -1,15 +1,17 @@ //! Send metrics to a statsd server. -use core::*; -use error; -use metrics; +use core::component::{Buffered, Attributes, Sampled, Sampling, WithAttributes, Name, AddPrefix}; +use core::pcg32; +use core::{Flush, Value}; +use core::input::Kind; +use core::metrics; +use core::output::{Output, OutputScope, OutputMetric}; +use core::error; +use cache::cache_out; +use queue::queue_out; use std::net::ToSocketAddrs; - use std::sync::Arc; - -use pcg32; - use std::net::UdpSocket; use std::rc::Rc; use std::cell::{RefCell, RefMut}; @@ -43,9 +45,6 @@ impl Statsd { impl Buffered for Statsd {} impl Sampled for Statsd {} -use queue_out; -use cache_out; - impl queue_out::QueuedOutput for Statsd {} impl cache_out::CachedOutput for Statsd {} diff --git a/src/text.rs b/src/output/text.rs similarity index 93% rename from src/text.rs rename to src/output/text.rs index 24879bc..a720657 100755 --- a/src/text.rs +++ b/src/output/text.rs @@ -1,20 +1,28 @@ //! Standard stateless metric outputs. // TODO parameterize templates -use core::{Name, AddPrefix, Value, Kind, OutputScope, WithAttributes, Attributes, - Buffered, OutputMetric, Output, Flush}; -use error; + +use core::{Flush, Value}; +use core::input::Kind; +use core::component::{Attributes, WithAttributes, Buffered, Name, AddPrefix}; +use core::output::{Output, OutputMetric, OutputScope}; +use core::error; +use cache::cache_out; +use queue::queue_out; + use std::sync::{RwLock, Arc}; use std::io::{Write, self}; use std::rc::Rc; use std::cell::RefCell; +/// Join metric name parts into a friendly '.' separated String pub fn format_name(name: &Name, _kind: Kind) -> Vec { let mut z = name.join("."); z.push_str(" "); vec![z] } +/// Output template-formatted value pub fn print_name_value_line(output: &mut impl Write, template: &[String], value: Value) -> error::Result<()> { write!(output, "{}", template[0])?; write!(output, "{}", value)?; @@ -30,9 +38,6 @@ pub struct Text { print_fn: Arc, &[String], Value) -> error::Result<()> + Send + Sync>, } -use queue_out; -use cache_out; - impl queue_out::QueuedOutput for Text {} impl cache_out::CachedOutput for Text {} @@ -177,7 +182,8 @@ impl Drop for TextScope { #[cfg(test)] mod test { - use core::*; + use super::*; + use core::input::Kind; use std::io; #[test] diff --git a/src/queue/mod.rs b/src/queue/mod.rs new file mode 100755 index 0000000..1a722f3 --- /dev/null +++ b/src/queue/mod.rs @@ -0,0 +1,2 @@ +pub mod queue_in; +pub mod queue_out; diff --git a/src/queue_in.rs b/src/queue/queue_in.rs similarity index 94% rename from src/queue_in.rs rename to src/queue/queue_in.rs index 9f293c1..eb13427 100755 --- a/src/queue_in.rs +++ b/src/queue/queue_in.rs @@ -1,11 +1,13 @@ //! Queue metrics for write on a separate thread, //! Metrics definitions are still synchronous. //! If queue size is exceeded, calling code reverts to blocking. -use core::{InputScope, Value, InputMetric, Name, Kind, AddPrefix, Input, - WithAttributes, Attributes, Flush, InputDyn}; -use error; -use metrics; -use cache_in::CachedInput; + +use core::component::{Attributes, Name, WithAttributes, AddPrefix}; +use core::input::{Kind, Input, InputScope, InputDyn, InputMetric}; +use core::{Value, Flush}; +use core::metrics; +use cache::cache_in::CachedInput; +use core::error; use std::sync::Arc; use std::sync::mpsc; @@ -85,7 +87,9 @@ impl Input for InputQueue { /// This is only `pub` because `error` module needs to know about it. /// Async commands should be of no concerns to applications. pub enum InputQueueCmd { + /// Send metric write Write(InputMetric, Value), + /// Send metric flush Flush(Arc), } diff --git a/src/queue_out.rs b/src/queue/queue_out.rs similarity index 77% rename from src/queue_out.rs rename to src/queue/queue_out.rs index ca116e4..1b90422 100755 --- a/src/queue_out.rs +++ b/src/queue/queue_out.rs @@ -1,17 +1,23 @@ //! Queue metrics for write on a separate thread, //! RawMetrics definitions are still synchronous. //! If queue size is exceeded, calling code reverts to blocking. -use core::{Value, OutputMetric, Name, Kind, AddPrefix, Output, OutputDyn, - WithAttributes, Attributes, InputScope, Input, InputMetric, UnsafeScope, Flush}; -use error; -use metrics; +//! +use core::component::{Attributes, Name, WithAttributes, AddPrefix}; +use core::input::{Kind, Input, InputScope, InputMetric}; +use core::output::{OutputDyn, OutputScope, OutputMetric, Output}; +use core::{Value, Flush}; +use core::metrics; +use cache::cache_in; +use core::error; + +use std::rc::Rc; +use std::ops; +use std::fmt; use std::sync::Arc; use std::sync::mpsc; use std::thread; -use cache_in; - /// Wrap this raw output behind an asynchronous metrics dispatch queue. pub trait QueuedOutput: Output + Sized { /// Wrap this output with an asynchronous dispatch queue. @@ -86,7 +92,9 @@ impl Input for OutputQueue { /// This is only `pub` because `error` module needs to know about it. /// Async commands should be of no concerns to applications. pub enum OutputQueueCmd { + /// Send metric write Write(Arc, Value), + /// Send metric flush Flush(Arc), } @@ -131,3 +139,35 @@ impl Flush for OutputQueueScope { } } +/// Wrap an OutputScope to make it Send + Sync, allowing it to travel the world of threads. +/// Obviously, it should only still be used from a single thread or dragons may occur. +#[derive(Clone)] +pub struct UnsafeScope(Rc ); + +unsafe impl Send for UnsafeScope {} +unsafe impl Sync for UnsafeScope {} + +impl UnsafeScope { + /// Wrap a dynamic RawScope to make it Send + Sync. + pub fn new(scope: Rc) -> Self { + UnsafeScope(scope) + } +} + +impl ops::Deref for UnsafeScope { + type Target = OutputScope + 'static; + fn deref(&self) -> &Self::Target { + Rc::as_ref(&self.0) + } +} + + +impl fmt::Debug for OutputMetric { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Box") + } +} + +unsafe impl Send for OutputMetric {} +unsafe impl Sync for OutputMetric {} +