Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Having trouble rendering metrics and integrating metrics_tracing_context with PrometheusRecorder. #551

Open
alv-around opened this issue Jan 22, 2025 · 0 comments

Comments

@alv-around
Copy link

Hi,

I am trying to build the prometheus exporter, and I am encountering 2 problems which I haven't manage to figure it out (see the tests, one working one failing):

  1. and foremost, when using the metrics create (counter!, histogram!... ) the PrometheusHandle.render() returns an empty string. I am a bit bluffed because when using the metrics-process crates this seems to work as expected.
  2. I would like to combine the Recorder with metrics_tracing_context to add some traces as metrics label. However, I haven't found any example or project having something similar? is possible at all? if so, what am I doing wrong in my approach?
//! Prometheus recorder
use std::LazyLock;
  
use metrics_exporter_prometheus::{PrometheusBuilder, PrometheusHandle};
use metrics_tracing_context::MetricsLayer;
use tracing::instrument::WithSubscriber;
use tracing_subscriber::{layer::SubscriberExt, Registry};

/// Installs the Prometheus recorder as the global recorder.
///
/// Caution: This only configures the global recorder and does not spawn the exporter.
pub fn install_prometheus_recorder() -> &'static PrometheusRecorder {
    &PROMETHEUS_RECORDER_HANDLE
}

/// The default Prometheus recorder handle. We use a global static to ensure that it is only
/// installed once.
static PROMETHEUS_RECORDER_HANDLE: LazyLock<PrometheusRecorder> =
    LazyLock::new(|| PrometheusRecorder::new());

/// A handle to the Prometheus recorder.
///
/// This is intended to be used as the global recorder.
/// Callers must ensure that [`PrometheusRecorder::spawn_upkeep`] is called once.
#[derive(Debug)]
pub struct PrometheusRecorder {
    handle: PrometheusHandle,
}

impl PrometheusRecorder {
    /// Installs Prometheus as the metrics recorder.
    ///
    /// Caution: This only configures the global recorder and does not spawn the exporter.
    fn new() -> Self {
        // Set up tracing:
        let subscriber = Registry::default().with(MetricsLayer::new());
        tracing::subscriber::set_global_default(subscriber)
            .expect("Error initializing the tracing subscriber");

        // Prepare metrics.
        let builder = PrometheusBuilder::new()
            .with_current_subscriber()
            .into_inner();
        let handle = builder
            .install_recorder()
            .expect("Error installing the metrics recorder");

        Self { handle }
    }

    pub fn get_handler(&self) -> &PrometheusHandle {
        &self.handle
    }
}

#[cfg(test)]
mod tests {
    use metrics::{counter, describe_counter};
    use metrics_process::Collector;
    use tracing::{span, Level};

    use super::*;
    
    #[test]
    fn test_working() {
        // initialize the lazy handle
        let handle = &PROMETHEUS_RECORDER_HANDLE.handle;
        let collector = Collector::default();

        collector.collect();
        let metrics = handle.render();
        assert!(metrics.contains("process_cpu_seconds_total"), "{metrics:?}");
    }

    #[test]
    fn test_failing() {
        let handle = &PROMETHEUS_RECORDER_HANDLE.handle;
        let span = span!(Level::TRACE, "my_span", test = "tracing_context");
        let _guard = span.enter();

        describe_counter!("example_metric", "A counter for demonstration purposes");
        counter!("example_metric");

        let metrics = handle.render();
        println!("{}", metrics);
        assert!(metrics.contains("example_metric"), "{metrics:?}");
        assert!(metrics.contains("test=\"tracing_context\""), "{metrics:?}");
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant