-
-
Notifications
You must be signed in to change notification settings - Fork 207
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into deps/scripts/update-java.ps1/6.27.0
- Loading branch information
Showing
10 changed files
with
542 additions
and
275 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
using Microsoft.AspNetCore.Diagnostics; | ||
using Microsoft.AspNetCore.Routing; | ||
using Sentry.Extensibility; | ||
|
||
namespace Sentry.AspNetCore; | ||
|
||
#if NET6_0_OR_GREATER | ||
internal class ExceptionHandlerFeatureProcessor : ISentryEventExceptionProcessor | ||
{ | ||
private readonly string _originalMethod; | ||
private readonly IExceptionHandlerFeature _exceptionHandlerFeature; | ||
|
||
public ExceptionHandlerFeatureProcessor(string originalMethod, IExceptionHandlerFeature exceptionHandlerFeature) | ||
{ | ||
_originalMethod = originalMethod; | ||
_exceptionHandlerFeature = exceptionHandlerFeature; | ||
} | ||
|
||
public void Process(Exception exception, SentryEvent sentryEvent) | ||
{ | ||
// When exceptions get caught by the UseExceptionHandler feature we reset the TransactionName and Tags | ||
// to reflect the route values of the original route (not the global error handling route) | ||
ApplyTransactionName(sentryEvent, _originalMethod); | ||
ApplyRouteTags(sentryEvent); | ||
} | ||
|
||
internal void ApplyRouteTags(SentryEvent evt) | ||
{ | ||
var endpoint = _exceptionHandlerFeature.Endpoint as RouteEndpoint; | ||
|
||
var actionName = endpoint?.DisplayName; | ||
if (actionName is not null) | ||
{ | ||
evt.SetTag("ActionName", actionName); | ||
} | ||
|
||
if (_exceptionHandlerFeature.RouteValues is {} routeValues) | ||
{ | ||
if (routeValues.TryGetValue("controller", out var controller)) | ||
{ | ||
evt.SetTag("route.controller", $"{controller}"); | ||
} | ||
if (routeValues.TryGetValue("action", out var action)) | ||
{ | ||
evt.SetTag("route.action", $"{action}"); | ||
} | ||
} | ||
} | ||
|
||
internal void ApplyTransactionName(SentryEvent evt, | ||
string method) | ||
{ | ||
// If no route template details are available, fall back to the Path | ||
var route = TryGetRouteTemplate() ?? _exceptionHandlerFeature.Path; | ||
if (!string.IsNullOrWhiteSpace(route)) | ||
{ | ||
evt.TransactionName = $"{method} {route}"; // e.g. "GET /pets/{id}" | ||
} | ||
} | ||
|
||
internal string? TryGetRouteTemplate() | ||
{ | ||
// Requires .UseRouting()/.UseEndpoints() | ||
var endpoint = _exceptionHandlerFeature.Endpoint as RouteEndpoint; | ||
var routePattern = endpoint?.RoutePattern.RawText; | ||
if (string.IsNullOrWhiteSpace(routePattern)) | ||
{ | ||
return null; | ||
} | ||
|
||
var routeValues = _exceptionHandlerFeature.RouteValues; | ||
if (routeValues is null) | ||
{ | ||
return null; | ||
} | ||
|
||
if (RouteUtils.NewRouteFormat(routePattern, routeValues) is { } formattedRoute) | ||
{ | ||
return formattedRoute; | ||
} | ||
|
||
return RouteUtils.LegacyRouteFormat(routeValues); | ||
} | ||
} | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
using Microsoft.AspNetCore.Routing; | ||
|
||
namespace Sentry.AspNetCore; | ||
|
||
internal static class RouteUtils | ||
{ | ||
// Internal for testing. | ||
internal static string? NewRouteFormat(string? routePattern, RouteValueDictionary? values, string? pathBase = null) | ||
{ | ||
if (string.IsNullOrWhiteSpace(routePattern)) | ||
{ | ||
return null; | ||
} | ||
|
||
var builder = new StringBuilder(); | ||
if (!string.IsNullOrWhiteSpace(pathBase)) | ||
{ | ||
builder.Append(pathBase.TrimStart('/')) | ||
.Append('/'); | ||
} | ||
|
||
// Skip route pattern if it resembles to a MVC route or null e.g. | ||
// {controller=Home}/{action=Index}/{id?} | ||
if (RouteHasMvcParameters(routePattern)) | ||
{ | ||
builder.Append(ReplaceMvcParameters(routePattern, values)); | ||
} | ||
else | ||
{ | ||
if (builder is { Length: > 1 } && builder[^1].Equals('/') && routePattern[0] == '/') | ||
{ | ||
builder.Length--; | ||
} | ||
|
||
builder.Append(routePattern); | ||
} | ||
|
||
return builder.ToString(); | ||
} | ||
|
||
// Internal for testing. | ||
internal static string? LegacyRouteFormat(RouteValueDictionary values, string? pathBase = null) | ||
{ | ||
if (values["action"] is not string action) | ||
{ | ||
// If the handler doesn't use routing (i.e. it checks `context.Request.Path` directly), | ||
// then there is no way for us to extract anything that resembles a route template. | ||
return null; | ||
} | ||
|
||
var builder = new StringBuilder(); | ||
if (!string.IsNullOrWhiteSpace(pathBase)) | ||
{ | ||
builder.Append(pathBase.TrimStart('/')) | ||
.Append('.'); | ||
} | ||
|
||
if (values["area"] is string area) | ||
{ | ||
builder.Append(area) | ||
.Append('.'); | ||
} | ||
|
||
if (values["controller"] is string controller) | ||
{ | ||
builder.Append(controller) | ||
.Append('.'); | ||
} | ||
|
||
builder.Append(action); | ||
|
||
return builder.ToString(); | ||
} | ||
|
||
// Internal for testing. | ||
internal static string ReplaceMvcParameters(string route, RouteValueDictionary? values) | ||
{ | ||
// GetRouteData can return null on netstandard2 | ||
if (values == null) | ||
{ | ||
return route; | ||
} | ||
|
||
if (values["controller"] is string controller) | ||
{ | ||
route = Regex.Replace(route, "{controller=[^}]+}", controller); | ||
} | ||
|
||
if (values["action"] is string action) | ||
{ | ||
route = Regex.Replace(route, "{action=[^}]+}", action); | ||
} | ||
|
||
if (values["area"] is string area) | ||
{ | ||
route = Regex.Replace(route, "{area=[^}]+}", area); | ||
} | ||
|
||
if (values["version"] is string version) | ||
{ | ||
route = Regex.Replace(route, "{version:[^}]+}", version); | ||
} | ||
|
||
return route; | ||
} | ||
|
||
// Internal for testing. | ||
internal static bool RouteHasMvcParameters(string route) | ||
=> route.Contains("{controller=") || | ||
route.Contains("{action=") || | ||
route.Contains("{version:") || | ||
route.Contains("{area="); | ||
} |
Oops, something went wrong.