Skip to content

Commit be5dfb2

Browse files
authored
fix: Prefer match_pattern over match_name in actix (#539)
1 parent 2001144 commit be5dfb2

File tree

1 file changed

+56
-15
lines changed

1 file changed

+56
-15
lines changed

sentry-actix/src/lib.rs

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -237,12 +237,10 @@ where
237237
.as_ref()
238238
.map_or(false, |client| client.options().send_default_pii);
239239

240-
let (mut tx, sentry_req) = sentry_request_from_http(&req, with_pii);
240+
let sentry_req = sentry_request_from_http(&req, with_pii);
241+
let name = transaction_name_from_http(&req);
241242

242243
let transaction = if inner.start_transaction {
243-
let name = std::mem::take(&mut tx)
244-
.unwrap_or_else(|| format!("{} {}", req.method(), req.uri()));
245-
246244
let headers = req.headers().iter().flat_map(|(header, value)| {
247245
value.to_str().ok().map(|value| (header.as_str(), value))
248246
});
@@ -262,7 +260,7 @@ where
262260
if let Some(transaction) = transaction.as_ref() {
263261
scope.set_span(Some(transaction.clone().into()));
264262
} else {
265-
scope.set_transaction(tx.as_deref());
263+
scope.set_transaction((!inner.start_transaction).then_some(&name));
266264
}
267265
scope.add_event_processor(move |event| Some(process_event(event, &sentry_req)));
268266
parent_span
@@ -336,14 +334,14 @@ fn map_status(status: StatusCode) -> protocol::SpanStatus {
336334
}
337335
}
338336

339-
/// Build a Sentry request struct from the HTTP request
340-
fn sentry_request_from_http(request: &ServiceRequest, with_pii: bool) -> (Option<String>, Request) {
341-
let transaction = if let Some(name) = request.match_name() {
342-
Some(String::from(name))
343-
} else {
344-
request.match_pattern()
345-
};
337+
/// Extract a transaction name from the HTTP request
338+
fn transaction_name_from_http(req: &ServiceRequest) -> String {
339+
let path_part = req.match_pattern().unwrap_or_else(|| "<none>".to_string());
340+
format!("{} {}", req.method(), path_part)
341+
}
346342

343+
/// Build a Sentry request struct from the HTTP request
344+
fn sentry_request_from_http(request: &ServiceRequest, with_pii: bool) -> Request {
347345
let mut sentry_req = Request {
348346
url: format!(
349347
"{}://{}{}",
@@ -369,7 +367,7 @@ fn sentry_request_from_http(request: &ServiceRequest, with_pii: bool) -> (Option
369367
}
370368
};
371369

372-
(transaction, sentry_req)
370+
sentry_req
373371
}
374372

375373
/// Add request data to a Sentry event
@@ -451,13 +449,56 @@ mod tests {
451449
assert_eq!(events.len(), 2);
452450
for event in events {
453451
let request = event.request.expect("Request should be set.");
454-
assert_eq!(event.transaction, Some("/test".into()));
452+
assert_eq!(event.transaction, Some("GET /test".into()));
455453
assert_eq!(event.message, Some("Message".into()));
456454
assert_eq!(event.level, Level::Warning);
457455
assert_eq!(request.method, Some("GET".into()));
458456
}
459457
}
460458

459+
/// Test transaction name HTTP verb.
460+
#[actix_web::test]
461+
async fn test_match_pattern() {
462+
let events = sentry::test::with_captured_events(|| {
463+
block_on(async {
464+
let service = |_name: String| {
465+
// Current Hub should have no events
466+
_assert_hub_no_events();
467+
468+
sentry::capture_message("Message", Level::Warning);
469+
470+
// Current Hub should have the event
471+
_assert_hub_has_events();
472+
473+
HttpResponse::Ok()
474+
};
475+
476+
let app = init_service(
477+
App::new()
478+
.wrap(Sentry::builder().with_hub(Hub::current()).finish())
479+
.service(web::resource("/test/{name}").route(web::post().to(service))),
480+
)
481+
.await;
482+
483+
// Call the service twice (sequentially) to ensure the middleware isn't sticky
484+
for _ in 0..2 {
485+
let req = TestRequest::post().uri("/test/fake_name").to_request();
486+
let res = call_service(&app, req).await;
487+
assert!(res.status().is_success());
488+
}
489+
})
490+
});
491+
492+
assert_eq!(events.len(), 2);
493+
for event in events {
494+
let request = event.request.expect("Request should be set.");
495+
assert_eq!(event.transaction, Some("POST /test/{name}".into()));
496+
assert_eq!(event.message, Some("Message".into()));
497+
assert_eq!(event.level, Level::Warning);
498+
assert_eq!(request.method, Some("POST".into()));
499+
}
500+
}
501+
461502
/// Ensures errors returned in the Actix service trigger an event.
462503
#[actix_web::test]
463504
async fn test_response_errors() {
@@ -490,7 +531,7 @@ mod tests {
490531
assert_eq!(events.len(), 2);
491532
for event in events {
492533
let request = event.request.expect("Request should be set.");
493-
assert_eq!(event.transaction, Some("failing".into())); // Transaction name is the name of the function
534+
assert_eq!(event.transaction, Some("GET /test".into())); // Transaction name is the matcher of the route
494535
assert_eq!(event.message, None);
495536
assert_eq!(event.exception.values[0].ty, String::from("Custom"));
496537
assert_eq!(event.exception.values[0].value, Some("Test Error".into()));

0 commit comments

Comments
 (0)