use shep_core::protocol::{MetricType, ProcessInfo};
use crate::dog::metrics::grammar::REFUSED_TOTAL;
use crate::dog::metrics::samples::{SampleFamily, SamplePoint, sender_labels};
use super::payload::{
KeyValue, Metric, Nanos, attr, cumulative_count_point, cumulative_double_point, cumulative_sum,
double_point, gauge,
};
const NANOS_PER_SECOND: u64 = 1_000_000_000;
struct SenderStart {
owned: Vec<(String, String)>,
start: Nanos,
}
fn sender_starts(flock: &[ProcessInfo], now: Nanos) -> Vec<SenderStart> {
flock
.iter()
.map(|info| SenderStart {
owned: sender_labels(info),
start: instance_start(info, now),
})
.collect()
}
fn sender_start(labels: &[(String, String)], starts: &[SenderStart]) -> Option<Nanos> {
starts
.iter()
.find(|sender| labels.starts_with(&sender.owned))
.map(|sender| sender.start)
}
fn instance_start(info: &ProcessInfo, now: Nanos) -> Nanos {
let up_nano = info.uptime_ms.saturating_mul(1_000_000);
Nanos::new(now.as_u64().saturating_sub(up_nano) / NANOS_PER_SECOND * NANOS_PER_SECOND)
}
fn sample_attributes<'a>(point: &'a SamplePoint) -> Vec<KeyValue<'a>> {
point
.labels
.iter()
.map(|(key, value)| attr(key, value.as_str()))
.collect()
}
fn finite(points: &[SamplePoint]) -> impl Iterator<Item = &SamplePoint> {
points.iter().filter(|point| point.value.is_finite())
}
pub(super) fn sample_metrics<'a>(
samples: &'a [SampleFamily],
flock: &'a [ProcessInfo],
exporter_start: Nanos,
now: Nanos,
) -> Vec<Metric<'a>> {
let starts = sender_starts(flock, now);
samples
.iter()
.filter_map(|family| match family.kind {
MetricType::Gauge => gauge(
family.name.as_str(),
family.help.as_deref(),
finite(&family.points)
.map(|point| double_point(sample_attributes(point), now, point.value))
.collect(),
),
MetricType::Counter => cumulative_sum(
family.name.as_str(),
family.help.as_deref(),
finite(&family.points)
.map(|point| {
let attributes = sample_attributes(point);
let start = sender_start(&point.labels, &starts).unwrap_or(exporter_start);
if family.name == REFUSED_TOTAL {
cumulative_count_point(attributes, start, now, point.value)
} else {
cumulative_double_point(attributes, start, now, point.value)
}
})
.collect(),
),
})
.collect()
}
#[cfg(test)]
mod tests;