use crate::encoding::{
EncodeCounterValue, EncodeExemplarValue, EncodeLabelSet, EncodeMetric, MetricEncoder,
};
use super::counter::{self, Counter};
use super::histogram::Histogram;
use super::{MetricType, TypedMetric};
use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard};
use std::collections::HashMap;
#[cfg(not(target_has_atomic = "64"))]
use std::sync::atomic::AtomicU32;
#[cfg(target_has_atomic = "64")]
use std::sync::atomic::AtomicU64;
use std::sync::Arc;
#[derive(Debug)]
pub struct Exemplar<S, V> {
pub(crate) label_set: S,
pub(crate) value: V,
}
#[cfg(target_has_atomic = "64")]
#[derive(Debug)]
pub struct CounterWithExemplar<S, N = u64, A = AtomicU64> {
pub(crate) inner: Arc<RwLock<CounterWithExemplarInner<S, N, A>>>,
}
impl<S> TypedMetric for CounterWithExemplar<S> {
const TYPE: MetricType = MetricType::Counter;
}
#[cfg(not(target_has_atomic = "64"))]
#[derive(Debug)]
pub struct CounterWithExemplar<S, N = u32, A = AtomicU32> {
pub(crate) inner: Arc<RwLock<CounterWithExemplarInner<S, N, A>>>,
}
impl<S, N, A> Clone for CounterWithExemplar<S, N, A> {
fn clone(&self) -> Self {
CounterWithExemplar {
inner: self.inner.clone(),
}
}
}
#[derive(Debug)]
pub struct CounterWithExemplarInner<S, N, A> {
pub(crate) exemplar: Option<Exemplar<S, N>>,
pub(crate) counter: Counter<N, A>,
}
impl<S, N, A: Default> Default for CounterWithExemplar<S, N, A> {
fn default() -> Self {
Self {
inner: Arc::new(RwLock::new(CounterWithExemplarInner {
exemplar: None,
counter: Default::default(),
})),
}
}
}
impl<S, N: Clone, A: counter::Atomic<N>> CounterWithExemplar<S, N, A> {
pub fn inc_by(&self, v: N, label_set: Option<S>) -> N {
let mut inner = self.inner.write();
inner.exemplar = label_set.map(|label_set| Exemplar {
label_set,
value: v.clone(),
});
inner.counter.inc_by(v)
}
pub fn get(&self) -> (N, MappedRwLockReadGuard<Option<Exemplar<S, N>>>) {
let inner = self.inner.read();
let value = inner.counter.get();
let exemplar = RwLockReadGuard::map(inner, |inner| &inner.exemplar);
(value, exemplar)
}
pub fn inner(&self) -> MappedRwLockReadGuard<A> {
RwLockReadGuard::map(self.inner.read(), |inner| inner.counter.inner())
}
}
impl<S, N, A> EncodeMetric for crate::metrics::exemplar::CounterWithExemplar<S, N, A>
where
S: EncodeLabelSet,
N: EncodeCounterValue + EncodeExemplarValue + Clone,
A: counter::Atomic<N>,
{
fn encode(&self, mut encoder: MetricEncoder) -> Result<(), std::fmt::Error> {
let (value, exemplar) = self.get();
encoder.encode_counter(&value, exemplar.as_ref())
}
fn metric_type(&self) -> MetricType {
Counter::<N, A>::TYPE
}
}
#[derive(Debug)]
pub struct HistogramWithExemplars<S> {
pub(crate) inner: Arc<RwLock<HistogramWithExemplarsInner<S>>>,
}
impl<S> TypedMetric for HistogramWithExemplars<S> {
const TYPE: MetricType = MetricType::Histogram;
}
impl<S> Clone for HistogramWithExemplars<S> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
#[derive(Debug)]
pub struct HistogramWithExemplarsInner<S> {
pub(crate) exemplars: HashMap<usize, Exemplar<S, f64>>,
pub(crate) histogram: Histogram,
}
impl<S> HistogramWithExemplars<S> {
pub fn new(buckets: impl Iterator<Item = f64>) -> Self {
Self {
inner: Arc::new(RwLock::new(HistogramWithExemplarsInner {
exemplars: Default::default(),
histogram: Histogram::new(buckets),
})),
}
}
pub fn observe(&self, v: f64, label_set: Option<S>) {
let mut inner = self.inner.write();
let bucket = inner.histogram.observe_and_bucket(v);
if let (Some(bucket), Some(label_set)) = (bucket, label_set) {
inner.exemplars.insert(
bucket,
Exemplar {
label_set,
value: v,
},
);
}
}
pub(crate) fn inner(&self) -> RwLockReadGuard<HistogramWithExemplarsInner<S>> {
self.inner.read()
}
}
impl<S: EncodeLabelSet> EncodeMetric for HistogramWithExemplars<S> {
fn encode(&self, mut encoder: MetricEncoder) -> Result<(), std::fmt::Error> {
let inner = self.inner();
let (sum, count, buckets) = inner.histogram.get();
encoder.encode_histogram(sum, count, &buckets, Some(&inner.exemplars))
}
fn metric_type(&self) -> MetricType {
Histogram::TYPE
}
}