sd2k/rocket_prometheus

custom metrics with callback

genofire opened this issue · 4 comments

How to write custom metrics which query data out of a database?

e.g. count of users in database as a gauge

sd2k commented

The answer depends when you want that metric to be updated. Would you like to update it on every call to an API route? In that case, you'd just add a piece of logic to your Rocket route to query the database and update your metric when the result is returned, using gauge.set(value). If you wanted to instead update that metric every 30 seconds, you'd need to spawn either a thread (if sync) or a task (if async) which queries the database, updates the gauge, then sleeps for 30 seconds and repeats.

both is useful if you ask me a async task would be nice ;)

sd2k commented

Something like this should work:

use futures::StreamExt;

pub static USER_COUNT: once_cell::sync::Lazy<prometheus::IntGauge> =
    once_cell::sync::Lazy::new(|| {
        prometheus::IntGauge::new("user_count", "Number of users in database").unwrap()
    });

async fn count_users() -> Result<i64, Box<dyn std::error::Error>> {
    // // get database connection and run query
    todo!()
}

async fn start_refreshing_user_count() {
    tokio::time::interval(std::time::Duration::from_secs(30))
        .for_each(|_| async {
            match count_users().await {
                Ok(val) => {
                    USER_COUNT.set(val);
                }
                Err(e) => {
                    tracing::warn!("Failed to update user count: {}", e);
                }
            };
        })
        .await;
}

#[tokio::main]
async fn main() {
    tokio::spawn(start_refreshing_user_count());
    // Do other stuff, like launching Rocket.
}

Is there a way to get it on call of /metrics ?