Skip to content

Commit 1f32ebe

Browse files
authored
Merge pull request #5687 from Turbo87/update-metrics
middleware/update_metrics: Migrate to `axum`
2 parents 61f711b + 33b9c84 commit 1f32ebe

File tree

5 files changed

+50
-43
lines changed

5 files changed

+50
-43
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ path = "src/tests/all.rs"
2424
[dependencies]
2525
anyhow = "=1.0.67"
2626
aws-sigv4 = "=0.52.0"
27-
axum = { version = "=0.6.1", features = ["headers", "macros"] }
27+
axum = { version = "=0.6.1", features = ["headers", "macros", "matched-path"] }
2828
axum-extra = { version = "=0.4.2", features = ["cookie-signed"] }
2929
base64 = "=0.13.1"
3030
cargo-registry-index = { path = "cargo-registry-index" }

conduit-axum/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ rust-version = "1.56.0"
1111
[dependencies]
1212
axum = "=0.6.1"
1313
conduit = "=0.10.0"
14+
conduit-router = "=0.10.0"
1415
hyper = { version = "=0.14.23", features = ["server", "stream"] }
1516
http = "=0.2.8"
1617
percent-encoding = "=2.2.0"

conduit-axum/src/fallback.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ use axum::body::{Body, HttpBody};
1111
use axum::extract::{ConnectInfo, Extension};
1212
use axum::handler::Handler as AxumHandler;
1313
use axum::response::IntoResponse;
14-
use conduit::{Handler, StartInstant};
14+
use conduit::{Handler, RequestExt, StartInstant};
15+
use conduit_router::RoutePattern;
1516
use http::header::CONTENT_LENGTH;
1617
use http::StatusCode;
1718
use hyper::{Request, Response};
@@ -58,7 +59,7 @@ async fn fallback_to_conduit(
5859
let mut request = ConduitRequest::new(request, remote_addr, now);
5960
handler
6061
.call(&mut request)
61-
.map(conduit_into_axum)
62+
.map(|response| conduit_into_axum(response, request))
6263
.unwrap_or_else(|e| server_error_response(&*e))
6364
})
6465
})
@@ -67,9 +68,13 @@ async fn fallback_to_conduit(
6768
}
6869

6970
/// Turns a `ConduitResponse` into a `AxumResponse`
70-
pub fn conduit_into_axum(response: ConduitResponse) -> AxumResponse {
71+
fn conduit_into_axum(mut response: ConduitResponse, mut request: ConduitRequest) -> AxumResponse {
7172
use conduit::Body::*;
7273

74+
if let Some(pattern) = request.mut_extensions().remove::<RoutePattern>() {
75+
response.extensions_mut().insert(pattern);
76+
}
77+
7378
let (parts, body) = response.into_parts();
7479
match body {
7580
Static(slice) => Response::from_parts(parts, axum::body::Body::from(slice)).into_response(),

src/middleware.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use self::ember_html::EmberHtml;
1010
use self::head::Head;
1111
use self::known_error_to_json::KnownErrorToJson;
1212
use self::static_or_continue::StaticOrContinue;
13-
use self::update_metrics::UpdateMetrics;
1413

1514
pub mod app;
1615
mod balance_capacity;
@@ -49,6 +48,10 @@ pub fn apply_axum_middleware(state: AppState, router: Router) -> Router {
4948
.layer(sentry_tower::NewSentryLayer::<Request>::new_from_top())
5049
.layer(sentry_tower::SentryHttpLayer::with_transaction())
5150
.layer(from_fn(log_request::log_requests))
51+
.layer(from_fn_with_state(
52+
state.clone(),
53+
update_metrics::update_metrics,
54+
))
5255
// The following layer is unfortunately necessary for `option_layer()` to work
5356
.layer(HandleErrorLayer::new(dummy_error_handler))
5457
// Optionally print debug information for each request
@@ -78,9 +81,6 @@ pub fn build_middleware(app: Arc<App>, endpoints: RouteBuilder) -> MiddlewareBui
7881
m.add(AppMiddleware::new(app));
7982
m.add(KnownErrorToJson);
8083

81-
// This is added *after* AppMiddleware to make sure the app is available.
82-
m.add(UpdateMetrics);
83-
8484
// Note: The following `m.around()` middleware is run from bottom to top
8585

8686
// This is currently the final middleware to run. If a middleware layer requires a database

src/middleware/update_metrics.rs

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,45 @@
1-
use super::app::RequestApp;
2-
use super::prelude::*;
1+
use crate::app::AppState;
2+
use axum::extract::{MatchedPath, State};
3+
use axum::middleware::Next;
4+
use axum::response::Response;
35
use conduit_router::RoutePattern;
6+
use http::Request;
7+
use std::time::Instant;
48

5-
#[derive(Debug, Default)]
6-
pub(super) struct UpdateMetrics;
9+
pub async fn update_metrics<B>(
10+
State(state): State<AppState>,
11+
matched_path: Option<MatchedPath>,
12+
req: Request<B>,
13+
next: Next<B>,
14+
) -> Response {
15+
let start_instant = Instant::now();
716

8-
impl Middleware for UpdateMetrics {
9-
fn before(&self, req: &mut dyn RequestExt) -> BeforeResult {
10-
let metrics = &req.app().instance_metrics;
17+
let metrics = &state.instance_metrics;
18+
metrics.requests_in_flight.inc();
1119

12-
metrics.requests_in_flight.inc();
20+
let response = next.run(req).await;
1321

14-
Ok(())
15-
}
22+
metrics.requests_in_flight.dec();
23+
metrics.requests_total.inc();
1624

17-
fn after(&self, req: &mut dyn RequestExt, res: AfterResult) -> AfterResult {
18-
let metrics = &req.app().instance_metrics;
19-
20-
metrics.requests_in_flight.dec();
21-
metrics.requests_total.inc();
22-
23-
let endpoint = req
25+
let endpoint = match matched_path {
26+
Some(ref matched_path) => matched_path.as_str(),
27+
None => response
2428
.extensions()
2529
.get::<RoutePattern>()
26-
.map(|p| p.pattern())
27-
.unwrap_or("<unknown>");
28-
metrics
29-
.response_times
30-
.with_label_values(&[endpoint])
31-
.observe(req.elapsed().as_millis() as f64 / 1000.0);
32-
33-
let status = match &res {
34-
Ok(res) => res.status().as_u16(),
35-
Err(_) => 500,
36-
};
37-
metrics
38-
.responses_by_status_code_total
39-
.with_label_values(&[&status.to_string()])
40-
.inc();
41-
42-
res
43-
}
30+
.map(|route_pattern| route_pattern.pattern())
31+
.unwrap_or("<unknown>"),
32+
};
33+
metrics
34+
.response_times
35+
.with_label_values(&[endpoint])
36+
.observe(start_instant.elapsed().as_millis() as f64 / 1000.0);
37+
38+
let status = response.status().as_u16();
39+
metrics
40+
.responses_by_status_code_total
41+
.with_label_values(&[&status.to_string()])
42+
.inc();
43+
44+
response
4445
}

0 commit comments

Comments
 (0)