Skip to content

Commit

Permalink
[PathPattern] Record and use PathPattern in response
Browse files Browse the repository at this point in the history
...so metrics correctly report the innermost PathPattern.

#461
  • Loading branch information
Peter Kolloch committed Dec 21, 2022
1 parent 080e190 commit 05d8cf6
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 14 deletions.
14 changes: 10 additions & 4 deletions poem/src/middleware/opentelemetry_metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,20 +79,26 @@ impl<E: Endpoint> Endpoint for OpenTelemetryMetricsEndpoint<E> {
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::<PathPattern>() {
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);
let elapsed = s.elapsed();

match &res {
Ok(resp) => {
if let Some(path_pattern) = resp.data::<PathPattern>() {
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::<PathPattern>() {
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()));
Expand Down
37 changes: 27 additions & 10 deletions poem/src/route/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ impl Route {
}
}

#[derive(Debug)]
#[derive(Debug, Clone)]
#[allow(unreachable_pub)]
pub struct PathPattern(pub Arc<str>);

Expand All @@ -316,17 +316,34 @@ impl Endpoint for Route {
None => matches.data.pattern.clone(),
};

match (req.data::<PathPattern>(), req.data::<PathPrefix>()) {
(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::<PathPattern>(), req.data::<PathPrefix>()) {
(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::<PathPattern>().is_none() {
res.set_data(pattern);
}
Ok(res)
}
Err(mut err) => {
if err.data::<PathPattern>().is_none() {
err.set_data(pattern);
}
Err(err)
}
}
matches.data.data.call(req).await
}
None => Err(NotFoundError.into()),
}
Expand Down

0 comments on commit 05d8cf6

Please sign in to comment.