asjeeves-telemetry 0.2.0

Metrics, Logging and Tracing
Documentation
use std::fmt::Display;
use std::sync::{Arc, OnceLock};
use std::time::Instant;

#[cfg(feature = "bb8")]
use metrics::gauge;
use metrics::histogram;

static DB_CONFIG: OnceLock<DbConfig> = OnceLock::new();

pub fn db_metrics_setup(name: impl Into<Arc<str>>, system: impl Into<Arc<str>>) {
    let name: Arc<str> = name.into();
    let system: Arc<str> = system.into();

    let config = DbConfig { name, system };

    let _ = DB_CONFIG.set(config);
}

pub async fn time_async_query<Closure, Fut, RetVal>(
    query_name: impl Display,
    query: Closure,
) -> RetVal
where
    Closure: FnOnce() -> Fut,
    Fut: Future<Output = RetVal>,
{
    let timer = Instant::now();

    let result = query().await;

    let system_name: &str = match DB_CONFIG.get() {
        Some(config) => &config.system,
        None => "",
    };

    let histogram = histogram!(
        description: "Query execution time",
        unit: metrics::Unit::Seconds,
        "db.client.operation.duration",
        "db.query.summary" => query_name.to_string(),
        "db.system.name" => system_name
    );

    histogram.record(timer.elapsed().as_secs_f64());

    result
}

#[cfg(feature = "bb8")]
pub fn track_database_metrics(dbstate: bb8::State, pool_size: u32) {
    let Some(config) = DB_CONFIG.get() else {
        return;
    };

    let stats: bb8::Statistics = dbstate.statistics;

    let active_connections: u32 = dbstate.connections - dbstate.idle_connections;

    let pool_name: &str = &config.name;

    let conn_count = gauge!(
        description: "Active Connections",
        unit: metrics::Unit::Count,
        "db.client.connection.count",
        "db.client.connetion.pool.name" => pool_name,
        "db.client.connection.state" => "used",
    );

    let idle_count = gauge!(
        description: "Idle Connections",
        unit: metrics::Unit::Count,
        "db.client.connection.count",
        "db.client.connetion.pool.name" => pool_name,
        "db.client.connection.state" => "idle",
    );

    let max_conn = gauge!(
        description: "Pool Size",
        unit: metrics::Unit::Count,
        "db.client.connection.idle.max",
        "db.client.connection.pool.name" => pool_name
    );

    let conn_get = gauge!(
        description: "Connection aquisition duration",
        unit: metrics::Unit::Seconds,
        "db.client.connection.create_time",
        "db.client.connection.pool.name" => pool_name
    );

    conn_count.set(active_connections as f64);
    idle_count.set(dbstate.idle_connections as f64);
    max_conn.set(pool_size as f64);
    conn_get.set(stats.get_wait_time.as_secs_f64());
}

#[allow(dead_code)]
struct DbConfig {
    name: Arc<str>,
    system: Arc<str>,
}