use http_body_util::Full;
use opentelemetry::{global::handle_error, metrics::MetricsError};
use prometheus::{Encoder, TextEncoder};
use viz_core::{
header::{HeaderValue, CONTENT_TYPE},
Handler, IntoResponse, Request, Response, Result, StatusCode,
};
#[doc(inline)]
pub use opentelemetry_prometheus::ExporterBuilder;
#[doc(inline)]
pub use prometheus::Registry;
#[derive(Clone, Debug)]
pub struct Prometheus {
registry: Registry,
}
impl Prometheus {
#[must_use]
pub fn new(registry: Registry) -> Self {
Self { registry }
}
}
#[viz_core::async_trait]
impl Handler<Request> for Prometheus {
type Output = Result<Response>;
async fn call(&self, _: Request) -> Self::Output {
let metric_families = self.registry.gather();
let encoder = TextEncoder::new();
let mut body = Vec::new();
if let Err(err) = encoder.encode(&metric_families, &mut body) {
let text = err.to_string();
handle_error(MetricsError::Other(text.clone()));
Err((StatusCode::INTERNAL_SERVER_ERROR, text).into_error())?;
}
let mut res = Response::new(Full::from(body).into());
res.headers_mut().append(
CONTENT_TYPE,
HeaderValue::from_str(encoder.format_type())
.map_err(|err| (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()).into_error())?,
);
Ok(res)
}
}