gsm-telemetry 0.1.3

Tracing and OpenTelemetry configuration helpers for Greentic messaging services.
Documentation
use once_cell::sync::Lazy;
use opentelemetry::global;
use opentelemetry::metrics::{Counter, Histogram, Meter, UpDownCounter};
use opentelemetry::KeyValue;
use std::collections::HashMap;
use std::sync::Mutex;

use crate::context::TelemetryLabels;
use crate::tracing_init::telemetry_enabled;

static COUNTERS: Lazy<Mutex<HashMap<&'static str, Counter<u64>>>> =
    Lazy::new(|| Mutex::new(HashMap::new()));
static HISTOGRAMS: Lazy<Mutex<HashMap<&'static str, Histogram<f64>>>> =
    Lazy::new(|| Mutex::new(HashMap::new()));
static GAUGES: Lazy<Mutex<HashMap<&'static str, UpDownCounter<i64>>>> =
    Lazy::new(|| Mutex::new(HashMap::new()));

const METER_NAME: &str = super::tracing_init::TELEMETRY_METER_NAME;

fn meter() -> Meter {
    global::meter(METER_NAME)
}

pub fn record_counter(name: &'static str, value: u64, labels: &TelemetryLabels) {
    if !telemetry_enabled() {
        return;
    }
    let counter = {
        let mut guard = COUNTERS.lock().unwrap();
        guard
            .entry(name)
            .or_insert_with(|| meter().u64_counter(name).build())
            .clone()
    };
    let attrs = labels_to_kv(labels);
    counter.add(value, &attrs);
}

pub fn record_histogram(name: &'static str, value: f64, labels: &TelemetryLabels) {
    if !telemetry_enabled() {
        return;
    }
    let histogram = {
        let mut guard = HISTOGRAMS.lock().unwrap();
        guard
            .entry(name)
            .or_insert_with(|| meter().f64_histogram(name).build())
            .clone()
    };
    let attrs = labels_to_kv(labels);
    histogram.record(value, &attrs);
}

pub fn record_gauge(name: &'static str, value: i64, labels: &TelemetryLabels) {
    if !telemetry_enabled() {
        return;
    }
    let gauge = {
        let mut guard = GAUGES.lock().unwrap();
        guard
            .entry(name)
            .or_insert_with(|| meter().i64_up_down_counter(name).build())
            .clone()
    };
    let attrs = labels_to_kv(labels);
    gauge.add(value, &attrs);
}

fn labels_to_kv(labels: &TelemetryLabels) -> Vec<KeyValue> {
    labels
        .tags()
        .into_iter()
        .map(|(k, v)| KeyValue::new(k.to_string(), v))
        .collect()
}