prometheus_metrics.rs 2.95 KB
Newer Older
1
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
3
// SPDX-License-Identifier: Apache-2.0

4
5
6
7
8
//! Python bindings for Prometheus metrics callbacks.
//!
//! This module provides minimal bindings for registering callbacks to integrate
//! external Prometheus metrics (e.g., from vLLM, SGLang, TensorRT-LLM) into
//! Dynamo's metrics endpoint.
9
10
11
12
13
14

use pyo3::prelude::*;
use std::sync::Arc;

use crate::rs;

15
16
/// RuntimeMetrics provides utilities for registering metrics callbacks.
/// Exposed as endpoint.metrics in Python.
17
///
18
19
/// Note: Metric creation methods have been removed from the public API.
/// This class only provides callback registration for integrating external metrics.
20
21
#[pyclass]
#[derive(Clone)]
22
pub struct RuntimeMetrics {
23
    hierarchy: Arc<dyn rs::metrics::MetricsHierarchy>,
24
25
}

26
impl RuntimeMetrics {
27
28
29
    /// Create from Endpoint
    pub fn from_endpoint(endpoint: dynamo_runtime::component::Endpoint) -> Self {
        Self {
30
            hierarchy: Arc::new(endpoint),
31
32
33
34
35
        }
    }
}

#[pymethods]
36
impl RuntimeMetrics {
37
38
39
40
    /// Register a Python callback that returns Prometheus exposition text
    /// The returned text will be appended to the /metrics endpoint output
    /// The callback should return a string in Prometheus text exposition format
    fn register_prometheus_expfmt_callback(&self, callback: PyObject, _py: Python) -> PyResult<()> {
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
        // Create the callback once (Arc allows sharing across registries)
        let callback_arc = Arc::new(move || {
            // Execute the Python callback in the Python event loop
            Python::with_gil(|py| {
                match callback.call0(py) {
                    Ok(result) => {
                        // Try to extract a string from the result
                        match result.extract::<String>(py) {
                            Ok(text) => Ok(text),
                            Err(e) => {
                                tracing::error!(
                                    "Metrics exposition text callback must return a string: {}",
                                    e
                                );
                                Ok(String::new())
56
57
58
                            }
                        }
                    }
59
60
61
62
63
64
65
66
                    Err(e) => {
                        tracing::error!("Metrics exposition text callback failed: {}", e);
                        Ok(String::new())
                    }
                }
            })
        });

67
68
69
        // Register the callback at this hierarchy level only.
        // Do NOT register on parent hierarchies - combined scrapes automatically
        // traverse child registries and include their callbacks.
70
71
72
73
        self.hierarchy
            .get_metrics_registry()
            .add_expfmt_callback(callback_arc.clone());

74
75
        Ok(())
    }
76
77
}

78
79
pub fn add_to_module(_m: &Bound<'_, PyModule>) -> PyResult<()> {
    // No metric type classes to add - only RuntimeMetrics is exposed
80
81
    Ok(())
}