1use std::sync::Mutex;
9
10use opentelemetry::KeyValue;
11use opentelemetry::metrics::{Counter, Meter};
12
13use subms::SubMsStageKind;
14
15pub const REFERENCE_DIVERGENCE_COUNTER_NAME: &str = "subms.reference.divergence";
17
18pub const REFERENCE_KIND_ATTR: &str = "subms.reference.kind";
21
22pub const REFERENCE_EXPECTED_ATTR: &str = "subms.reference.expected";
24
25pub const REFERENCE_OBSERVED_ATTR: &str = "subms.reference.observed";
27
28pub fn divergence_attributes(
30 stage: &str,
31 kind: SubMsStageKind,
32 reference_kind: &str,
33 expected: &str,
34 observed: &str,
35) -> Vec<KeyValue> {
36 vec![
37 KeyValue::new("subms.stage", stage.to_string()),
38 KeyValue::new("subms.stage.kind", kind.as_str()),
39 KeyValue::new(REFERENCE_KIND_ATTR, reference_kind.to_string()),
40 KeyValue::new(REFERENCE_EXPECTED_ATTR, expected.to_string()),
41 KeyValue::new(REFERENCE_OBSERVED_ATTR, observed.to_string()),
42 ]
43}
44
45pub fn record_reference_divergence(
50 meter: &Meter,
51 stage: &str,
52 kind: SubMsStageKind,
53 reference_kind: &str,
54 expected: &str,
55 observed: &str,
56) {
57 let counter: Counter<u64> = meter
58 .u64_counter(REFERENCE_DIVERGENCE_COUNTER_NAME)
59 .with_description("Count of detected divergences between a recipe and its reference impl")
60 .build();
61 let attrs = divergence_attributes(stage, kind, reference_kind, expected, observed);
62 counter.add(1, &attrs);
63}
64
65pub struct ReferenceDivergenceRecorder {
69 counter: Mutex<Option<Counter<u64>>>,
70 meter: Meter,
71}
72
73impl ReferenceDivergenceRecorder {
74 pub fn new(meter: Meter) -> Self {
76 Self {
77 counter: Mutex::new(None),
78 meter,
79 }
80 }
81
82 pub fn record(
86 &self,
87 stage: &str,
88 kind: SubMsStageKind,
89 reference_kind: &str,
90 expected: &str,
91 observed: &str,
92 ) {
93 let mut slot = self.counter.lock().expect("divergence counter poisoned");
94 if slot.is_none() {
95 *slot = Some(
96 self.meter
97 .u64_counter(REFERENCE_DIVERGENCE_COUNTER_NAME)
98 .with_description(
99 "Count of detected divergences between a recipe and its reference impl",
100 )
101 .build(),
102 );
103 }
104 let counter = slot.as_ref().expect("counter just built");
105 let attrs = divergence_attributes(stage, kind, reference_kind, expected, observed);
106 counter.add(1, &attrs);
107 }
108}