use std;
use std::fmt;
pub use aggregated_metrics::{
AggregatedCounter, AggregatedGauge, AggregatedHistogram, AggregatedSummary,
};
use label::Labels;
use metrics::{Counter, Gauge, Histogram, Summary};
use {ErrorKind, Result};
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub enum Metric {
Counter(Counter),
Gauge(Gauge),
Summary(Summary),
Histogram(Histogram),
}
impl Metric {
pub fn name(&self) -> &MetricName {
match *self {
Metric::Counter(ref m) => m.metric_name(),
Metric::Gauge(ref m) => m.metric_name(),
Metric::Summary(ref m) => m.metric_name(),
Metric::Histogram(ref m) => m.metric_name(),
}
}
pub fn kind(&self) -> MetricKind {
match *self {
Metric::Counter(_) => MetricKind::Counter,
Metric::Gauge(_) => MetricKind::Gauge,
Metric::Summary(_) => MetricKind::Summary,
Metric::Histogram(_) => MetricKind::Histogram,
}
}
pub fn labels(&self) -> &Labels {
match *self {
Metric::Counter(ref m) => m.labels(),
Metric::Gauge(ref m) => m.labels(),
Metric::Summary(ref m) => m.labels(),
Metric::Histogram(ref m) => m.labels(),
}
}
}
impl From<Counter> for Metric {
fn from(f: Counter) -> Self {
Metric::Counter(f)
}
}
impl From<Gauge> for Metric {
fn from(f: Gauge) -> Self {
Metric::Gauge(f)
}
}
impl From<Histogram> for Metric {
fn from(f: Histogram) -> Self {
Metric::Histogram(f)
}
}
impl From<Summary> for Metric {
fn from(f: Summary) -> Self {
Metric::Summary(f)
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MetricName {
namespace: Option<String>,
subsystem: Option<String>,
name: String,
}
impl MetricName {
pub fn namespace(&self) -> Option<&str> {
self.namespace.as_ref().map(|s| s.as_ref())
}
pub fn subsystem(&self) -> Option<&str> {
self.subsystem.as_ref().map(|s| s.as_ref())
}
pub fn name(&self) -> &str {
&self.name
}
pub(crate) fn new(
namespace: Option<&str>,
subsystem: Option<&str>,
name: &str,
) -> Result<Self> {
if let Some(s) = namespace {
track!(Self::validate_name(s), "{:?}", s)?;
}
if let Some(s) = subsystem {
track!(Self::validate_name(s), "{:?}", s)?;
}
track!(Self::validate_name(name), "{:?}", name)?;
Ok(MetricName {
namespace: namespace.map(|s| s.to_owned()),
subsystem: subsystem.map(|s| s.to_owned()),
name: name.to_string(),
})
}
fn validate_name(name: &str) -> Result<()> {
track_assert!(!name.is_empty(), ErrorKind::InvalidInput);
match name.as_bytes()[0] as char {
'a'..='z' | 'A'..='Z' | '_' | ':' => {}
_ => track_panic!(ErrorKind::InvalidInput),
}
for c in name.chars().skip(1) {
match c {
'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | ':' => {}
_ => track_panic!(ErrorKind::InvalidInput),
}
}
Ok(())
}
}
impl fmt::Display for MetricName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(ref s) = self.namespace {
write!(f, "{}_", s)?;
}
if let Some(ref s) = self.subsystem {
write!(f, "{}_", s)?;
}
write!(f, "{}", self.name)?;
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[allow(missing_docs)]
pub enum MetricKind {
Counter,
Gauge,
Summary,
Histogram,
}
impl fmt::Display for MetricKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
MetricKind::Counter => write!(f, "counter"),
MetricKind::Gauge => write!(f, "gauge"),
MetricKind::Summary => write!(f, "summary"),
MetricKind::Histogram => write!(f, "histogram"),
}
}
}
pub(crate) struct MetricValue(pub f64);
impl fmt::Display for MetricValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.0.is_finite() {
write!(f, "{}", self.0)
} else if self.0.is_nan() {
write!(f, "Nan")
} else if self.0.is_sign_positive() {
write!(f, "+Inf")
} else {
write!(f, "-Inf")
}
}
}
#[derive(Debug, Clone)]
pub struct MetricFamilies(pub(crate) Vec<MetricFamily>);
impl MetricFamilies {
pub fn into_vec(self) -> Vec<MetricFamily> {
self.0
}
pub fn to_text(&self) -> String {
use std::fmt::Write;
let mut buf = String::new();
for m in &self.0 {
write!(buf, "{}", m).expect("Never fails");
}
buf
}
}
impl AsRef<[MetricFamily]> for MetricFamilies {
fn as_ref(&self) -> &[MetricFamily] {
&self.0
}
}
impl IntoIterator for MetricFamilies {
type Item = MetricFamily;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
#[derive(Debug, Clone)]
pub struct MetricFamily {
name: MetricName,
help: Option<String>,
metrics: Metrics,
}
impl MetricFamily {
pub fn name(&self) -> &MetricName {
&self.name
}
pub fn help(&self) -> Option<&str> {
self.help.as_ref().map(|h| h.as_ref())
}
pub fn kind(&self) -> MetricKind {
match self.metrics {
Metrics::Counter(_) => MetricKind::Counter,
Metrics::Gauge(_) => MetricKind::Gauge,
Metrics::Summary(_) => MetricKind::Summary,
Metrics::Histogram(_) => MetricKind::Histogram,
}
}
pub fn metrics(&self) -> &Metrics {
&self.metrics
}
pub(crate) fn new(metric: Metric) -> Self {
match metric {
Metric::Counter(m) => MetricFamily {
name: m.metric_name().clone(),
help: m.help().map(|h| h.to_string()),
metrics: Metrics::Counter(vec![AggregatedCounter::new(m)]),
},
Metric::Gauge(m) => MetricFamily {
name: m.metric_name().clone(),
help: m.help().map(|h| h.to_string()),
metrics: Metrics::Gauge(vec![AggregatedGauge::new(m)]),
},
Metric::Summary(m) => MetricFamily {
name: m.metric_name().clone(),
help: m.help().map(|h| h.to_string()),
metrics: Metrics::Summary(vec![AggregatedSummary::new(m)]),
},
Metric::Histogram(m) => MetricFamily {
name: m.metric_name().clone(),
help: m.help().map(|h| h.to_string()),
metrics: Metrics::Histogram(vec![AggregatedHistogram::new(m)]),
},
}
}
pub(crate) fn same_family(&self, metric: &Metric) -> bool {
(self.name(), self.kind()) == (metric.name(), metric.kind())
}
pub(crate) fn push(&mut self, metric: Metric) {
match metric {
Metric::Counter(m) => {
if let Metrics::Counter(ref mut v) = self.metrics {
let m = AggregatedCounter::new(m);
if v.last_mut().map_or(true, |x| !x.try_merge(&m)) {
v.push(m);
}
}
}
Metric::Gauge(m) => {
if let Metrics::Gauge(ref mut v) = self.metrics {
let m = AggregatedGauge::new(m);
if v.last_mut().map_or(true, |x| !x.try_merge(&m)) {
v.push(m);
}
}
}
Metric::Summary(m) => {
if let Metrics::Summary(ref mut v) = self.metrics {
let m = AggregatedSummary::new(m);
if v.last_mut().map_or(true, |x| !x.try_merge(&m)) {
v.push(m);
}
}
}
Metric::Histogram(m) => {
if let Metrics::Histogram(ref mut v) = self.metrics {
let m = AggregatedHistogram::new(m);
if v.last_mut().map_or(true, |x| !x.try_merge(&m)) {
v.push(m);
}
}
}
}
}
}
impl fmt::Display for MetricFamily {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(help) = self.help() {
write!(f, "# HELP {} ", self.name())?;
for c in help.chars() {
match c {
'\\' => write!(f, "\\\\")?,
'\n' => write!(f, "\\\\n")?,
_ => write!(f, "{}", c)?,
}
}
writeln!(f, "")?;
}
writeln!(f, "# TYPE {} {}", self.name(), self.kind())?;
write!(f, "{}", self.metrics)?;
Ok(())
}
}
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub enum Metrics {
Counter(Vec<AggregatedCounter>),
Gauge(Vec<AggregatedGauge>),
Summary(Vec<AggregatedSummary>),
Histogram(Vec<AggregatedHistogram>),
}
impl fmt::Display for Metrics {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Metrics::Counter(ref v) => {
for m in v.iter() {
writeln!(f, "{}", m)?;
}
}
Metrics::Gauge(ref v) => {
for m in v.iter() {
writeln!(f, "{}", m)?;
}
}
Metrics::Summary(ref v) => {
for m in v.iter() {
writeln!(f, "{}", m)?;
}
}
Metrics::Histogram(ref v) => {
for m in v.iter() {
writeln!(f, "{}", m)?;
}
}
}
Ok(())
}
}