diff --git a/src/metrics/server.rs b/src/metrics/server.rs index bd992360a..0c19641e9 100644 --- a/src/metrics/server.rs +++ b/src/metrics/server.rs @@ -62,7 +62,7 @@ impl Server { async fn handle_metrics( reg: Arc>, - _req: Request, + req: Request, ) -> Response> { let mut buf = String::new(); let reg = reg.lock().expect("mutex"); @@ -73,12 +73,82 @@ async fn handle_metrics( .expect("builder with known status code should not fail"); } + let response_content_type = content_type(&req); + Response::builder() .status(hyper::StatusCode::OK) - .header( - hyper::header::CONTENT_TYPE, - "application/openmetrics-text;charset=utf-8;version=1.0.0", - ) + .header(hyper::header::CONTENT_TYPE, response_content_type) .body(buf.into()) .expect("builder with known status code should not fail") } + +#[derive(Default)] +enum ContentType { + #[default] + PlainText, + OpenMetrics, +} + +impl From for &str { + fn from(c: ContentType) -> Self { + match c { + ContentType::PlainText => "text/plain; charset=utf-8", + ContentType::OpenMetrics => "application/openmetrics-text;charset=utf-8;version=1.0.0", + } + } +} + +#[inline(always)] +fn content_type(req: &Request) -> &str { + req.headers() + .get_all(http::header::ACCEPT) + .iter() + .find_map(|v| { + match v + .to_str() + .unwrap_or_default() + .to_lowercase() + .split(";") + .collect::>() + .first() + { + Some(&"application/openmetrics-text") => Some(ContentType::OpenMetrics), + _ => None, + } + }) + .unwrap_or_default() + .into() +} + +mod test { + + #[test] + fn test_content_type() { + let plain_text_req = http::Request::new("I want some plain text"); + assert_eq!( + super::content_type(&plain_text_req), + "text/plain; charset=utf-8" + ); + + let openmetrics_req = http::Request::builder() + .header("X-Custom-Beep", "boop") + .header("Accept", "application/json") + .header("Accept", "application/openmetrics-text; other stuff") + .body("I would like openmetrics") + .unwrap(); + assert_eq!( + super::content_type(&openmetrics_req), + "application/openmetrics-text;charset=utf-8;version=1.0.0" + ); + + let unsupported_req_accept = http::Request::builder() + .header("Accept", "application/json") + .body("I would like some json") + .unwrap(); + // asking for something we don't support, fall back to plaintext + assert_eq!( + super::content_type(&unsupported_req_accept), + "text/plain; charset=utf-8" + ) + } +}