From 05d8cf6600613fb2e9fd334f62fcee69171e181a Mon Sep 17 00:00:00 2001 From: Peter Kolloch Date: Wed, 21 Dec 2022 11:08:32 +0100 Subject: [PATCH] [PathPattern] Record and use PathPattern in response ...so metrics correctly report the innermost PathPattern. https://github.com/poem-web/poem/issues/461 --- poem/src/middleware/opentelemetry_metrics.rs | 14 +++++--- poem/src/route/router.rs | 37 ++++++++++++++------ 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/poem/src/middleware/opentelemetry_metrics.rs b/poem/src/middleware/opentelemetry_metrics.rs index 87e4b0642a..1e18f56683 100644 --- a/poem/src/middleware/opentelemetry_metrics.rs +++ b/poem/src/middleware/opentelemetry_metrics.rs @@ -79,10 +79,6 @@ impl Endpoint for OpenTelemetryMetricsEndpoint { let mut labels = Vec::with_capacity(3); labels.push(trace::HTTP_METHOD.string(req.method().to_string())); labels.push(trace::HTTP_URL.string(req.original_uri().to_string())); - if let Some(path_pattern) = req.data::() { - const HTTP_PATH_PATTERN: Key = Key::from_static_str("http.path_pattern"); - labels.push(HTTP_PATH_PATTERN.string(path_pattern.0.to_string())); - } let s = Instant::now(); let res = self.inner.call(req).await.map(IntoResponse::into_response); @@ -90,9 +86,19 @@ impl Endpoint for OpenTelemetryMetricsEndpoint { match &res { Ok(resp) => { + if let Some(path_pattern) = resp.data::() { + const HTTP_PATH_PATTERN: Key = Key::from_static_str("http.path_pattern"); + labels.push(HTTP_PATH_PATTERN.string(path_pattern.0.to_string())); + } + labels.push(trace::HTTP_STATUS_CODE.i64(resp.status().as_u16() as i64)); } Err(err) => { + if let Some(path_pattern) = err.data::() { + const HTTP_PATH_PATTERN: Key = Key::from_static_str("http.path_pattern"); + labels.push(HTTP_PATH_PATTERN.string(path_pattern.0.to_string())); + } + labels.push(trace::HTTP_STATUS_CODE.i64(err.status().as_u16() as i64)); self.error_count.add(&cx, 1, &labels); labels.push(trace::EXCEPTION_MESSAGE.string(err.to_string())); diff --git a/poem/src/route/router.rs b/poem/src/route/router.rs index 0b5747c36e..be03861135 100644 --- a/poem/src/route/router.rs +++ b/poem/src/route/router.rs @@ -298,7 +298,7 @@ impl Route { } } -#[derive(Debug)] +#[derive(Debug, Clone)] #[allow(unreachable_pub)] pub struct PathPattern(pub Arc); @@ -316,17 +316,34 @@ impl Endpoint for Route { None => matches.data.pattern.clone(), }; - match (req.data::(), req.data::()) { - (Some(parent), Some(prefix)) => req.set_data(PathPattern( - format!("{}{}", parent.0, &pattern[prefix.0..]).into(), - )), - (None, Some(prefix)) => req.set_data(PathPattern(pattern[prefix.0..].into())), - (None, None) => req.set_data(PathPattern(pattern)), - (Some(parent), None) => { - req.set_data(PathPattern(format!("{}{}", parent.0, pattern).into())) + let pattern = match (req.data::(), req.data::()) { + (Some(parent), Some(prefix)) => { + PathPattern(format!("{}{}", parent.0, &pattern[prefix.0..]).into()) + } + (None, Some(prefix)) => PathPattern(pattern[prefix.0..].into()), + (None, None) => PathPattern(pattern), + (Some(parent), None) => PathPattern(format!("{}{}", parent.0, pattern).into()), + }; + req.set_data(pattern.clone()); + + let result = matches.data.data.call(req).await; + + // Add PathPattern to the innermost response so that metrics instrumentation + // can report the innermost matched pattern. + match result { + Ok(mut res) => { + if res.data::().is_none() { + res.set_data(pattern); + } + Ok(res) + } + Err(mut err) => { + if err.data::().is_none() { + err.set_data(pattern); + } + Err(err) } } - matches.data.data.call(req).await } None => Err(NotFoundError.into()), }