use super::{CONFIG_LOAD_COUNTER, CONFIG_LOAD_DURATION, DIAG_MODE_PHASE, MERGE_PHASE};
use metrics::{Counter, Gauge, Histogram, Key, KeyName, Metadata, SharedString, Unit};
use metrics_util::MetricKind;
use metrics_util::debugging::{DebuggingRecorder, Snapshotter};
const PHASE_LABEL: &str = "phase";
const OUTCOME_LABEL: &str = "outcome";
const PHASE_VALUES: [&str; 2] = [DIAG_MODE_PHASE, MERGE_PHASE];
const OUTCOME_VALUES: [&str; 2] = ["success", "failure"];
#[derive(Debug)]
pub(super) struct ConfigMetricsRecorder {
inner: DebuggingRecorder,
}
impl ConfigMetricsRecorder {
pub(super) fn new() -> Self {
Self {
inner: DebuggingRecorder::new(),
}
}
pub(super) fn snapshotter(&self) -> Snapshotter {
self.inner.snapshotter()
}
fn accepts_name(name: &str) -> bool {
matches!(name, CONFIG_LOAD_COUNTER | CONFIG_LOAD_DURATION)
}
fn accepts_registration(key: &Key, kind: MetricKind) -> bool {
match kind {
MetricKind::Counter => {
key.name() == CONFIG_LOAD_COUNTER
&& exact_labels(
key,
&[
(PHASE_LABEL, &PHASE_VALUES),
(OUTCOME_LABEL, &OUTCOME_VALUES),
],
)
}
MetricKind::Histogram => {
key.name() == CONFIG_LOAD_DURATION
&& exact_labels(key, &[(PHASE_LABEL, &PHASE_VALUES)])
}
MetricKind::Gauge => false,
}
}
fn forward<R>(
&self,
accepted: bool,
reject: impl FnOnce() -> R,
accept: impl FnOnce(&DebuggingRecorder) -> R,
) -> R {
if accepted {
accept(&self.inner)
} else {
reject()
}
}
}
fn exact_labels(key: &Key, expected: &[(&str, &[&str])]) -> bool {
let labels: Vec<_> = key.labels().collect();
labels.len() == expected.len()
&& labels
.iter()
.zip(expected)
.all(|(label, &(name, values))| label.key() == name && values.contains(&label.value()))
}
impl metrics::Recorder for ConfigMetricsRecorder {
fn describe_counter(&self, key_name: KeyName, unit: Option<Unit>, description: SharedString) {
self.forward(
Self::accepts_name(key_name.as_str()),
|| {},
|inner| inner.describe_counter(key_name, unit, description),
);
}
fn describe_gauge(&self, key_name: KeyName, unit: Option<Unit>, description: SharedString) {
self.forward(
Self::accepts_name(key_name.as_str()),
|| {},
|inner| inner.describe_gauge(key_name, unit, description),
);
}
fn describe_histogram(&self, key_name: KeyName, unit: Option<Unit>, description: SharedString) {
self.forward(
Self::accepts_name(key_name.as_str()),
|| {},
|inner| inner.describe_histogram(key_name, unit, description),
);
}
fn register_counter(&self, key: &Key, metadata: &Metadata<'_>) -> Counter {
self.forward(
Self::accepts_registration(key, MetricKind::Counter),
Counter::noop,
|inner| inner.register_counter(key, metadata),
)
}
fn register_gauge(&self, key: &Key, metadata: &Metadata<'_>) -> Gauge {
self.forward(
Self::accepts_registration(key, MetricKind::Gauge),
Gauge::noop,
|inner| inner.register_gauge(key, metadata),
)
}
fn register_histogram(&self, key: &Key, metadata: &Metadata<'_>) -> Histogram {
self.forward(
Self::accepts_registration(key, MetricKind::Histogram),
Histogram::noop,
|inner| inner.register_histogram(key, metadata),
)
}
}