private static Scope CreateScope(object controllerContext, out AspNetTags tags) { Scope scope = null; tags = null; try { if (!Tracer.Instance.Settings.IsIntegrationEnabled(IntegrationName)) { // integration disabled, don't create a scope, skip this trace return(null); } var tracer = Tracer.Instance; var request = controllerContext.GetProperty <object>("Request").GetValueOrDefault(); SpanContext propagatedContext = null; var tagsFromHeaders = Enumerable.Empty <KeyValuePair <string, string> >(); if (request != null && tracer.ActiveScope == null) { try { // extract propagated http headers var headers = request.GetProperty <object>("Headers").GetValueOrDefault(); var headersCollection = new ReflectionHttpHeadersCollection(headers); propagatedContext = SpanContextPropagator.Instance.Extract(headersCollection); tagsFromHeaders = SpanContextPropagator.Instance.ExtractHeaderTags(headersCollection, tracer.Settings.HeaderTags); } catch (Exception ex) { Log.Error(ex, "Error extracting propagated HTTP headers."); } } tags = new AspNetTags(); scope = tracer.StartActiveWithTags(OperationName, propagatedContext, tags: tags); UpdateSpan(controllerContext, scope.Span, tags, tagsFromHeaders); // set analytics sample rate if enabled var analyticsSampleRate = tracer.Settings.GetIntegrationAnalyticsSampleRate(IntegrationName, enabledWithGlobalSetting: true); if (analyticsSampleRate != null) { tags.AnalyticsSampleRate = analyticsSampleRate; } } catch (Exception ex) { Log.Error(ex, "Error creating scope."); } return(scope); }
internal static Scope CreateScope(IHttpControllerContext controllerContext, out AspNetTags tags) { Scope scope = null; tags = null; try { if (!Tracer.Instance.Settings.IsIntegrationEnabled(IntegrationId)) { // integration disabled, don't create a scope, skip this trace return(null); } var tracer = Tracer.Instance; var request = controllerContext.Request; SpanContext propagatedContext = null; var tagsFromHeaders = Enumerable.Empty <KeyValuePair <string, string> >(); if (request != null && tracer.InternalActiveScope == null) { try { // extract propagated http headers var headers = request.Headers; var headersCollection = new HttpHeadersCollection(headers); propagatedContext = SpanContextPropagator.Instance.Extract(headersCollection); tagsFromHeaders = SpanContextPropagator.Instance.ExtractHeaderTags(headersCollection, tracer.Settings.HeaderTags, SpanContextPropagator.HttpRequestHeadersTagPrefix, request.Headers.UserAgent.ToString()); } catch (Exception ex) { Log.Error(ex, "Error extracting propagated HTTP headers."); } } tags = new AspNetTags(); scope = tracer.StartActiveInternal(OperationName, propagatedContext, tags: tags); UpdateSpan(controllerContext, scope.Span, tags, tagsFromHeaders); tags.SetAnalyticsSampleRate(IntegrationId, tracer.Settings, enabledWithGlobalSetting: true); tracer.TracerManager.Telemetry.IntegrationGeneratedSpan(IntegrationId); } catch (Exception ex) { Log.Error(ex, "Error creating scope."); } return(scope); }
private static void UpdateSpan(object controllerContext, Span span, AspNetTags tags, IEnumerable <KeyValuePair <string, string> > headerTags) { try { object request = controllerContext.GetProperty <object>("Request").GetValueOrDefault(); Uri requestUri = request.GetProperty <Uri>("RequestUri").GetValueOrDefault(); string host = request.GetProperty <object>("Headers").GetProperty <string>("Host").GetValueOrDefault() ?? string.Empty; string rawUrl = requestUri?.ToString().ToLowerInvariant() ?? string.Empty; string absoluteUri = requestUri?.AbsoluteUri?.ToLowerInvariant() ?? string.Empty; string method = request.GetProperty <object>("Method").GetProperty <string>("Method").GetValueOrDefault()?.ToUpperInvariant() ?? "GET"; string route = null; try { route = controllerContext.GetProperty <object>("RouteData").GetProperty <object>("Route").GetProperty <string>("RouteTemplate").GetValueOrDefault(); } catch { } string resourceName = $"{method} {absoluteUri.ToLowerInvariant()}"; if (route != null) { resourceName = $"{method} {route.ToLowerInvariant()}"; } else if (requestUri != null) { var cleanUri = UriHelpers.GetRelativeUrl(requestUri, tryRemoveIds: true); resourceName = $"{method} {cleanUri.ToLowerInvariant()}"; } string controller = string.Empty; string action = string.Empty; try { var routeValues = controllerContext.GetProperty <object>("RouteData").GetProperty <IDictionary <string, object> >("Values").GetValueOrDefault(); if (routeValues != null) { controller = (routeValues.GetValueOrDefault("controller") as string)?.ToLowerInvariant(); action = (routeValues.GetValueOrDefault("action") as string)?.ToLowerInvariant(); } } catch { } // Fail safe to catch templates in routing values resourceName = resourceName .Replace("{controller}", controller) .Replace("{action}", action); span.DecorateWebServerSpan( resourceName: resourceName, method: method, host: host, httpUrl: rawUrl, tags, headerTags); tags.AspNetAction = action; tags.AspNetController = controller; tags.AspNetRoute = route; } catch (Exception ex) { Log.Error(ex, "Error populating scope data."); } }
internal static void UpdateSpan(IHttpControllerContext controllerContext, Span span, AspNetTags tags, IEnumerable <KeyValuePair <string, string> > headerTags) { try { var newResourceNamesEnabled = Tracer.Instance.Settings.RouteTemplateResourceNamesEnabled; var request = controllerContext.Request; Uri requestUri = request.RequestUri; string host = request.Headers.Host ?? string.Empty; string rawUrl = requestUri?.ToString().ToLowerInvariant() ?? string.Empty; string method = request.Method.Method?.ToUpperInvariant() ?? "GET"; string route = null; try { route = controllerContext.RouteData.Route.RouteTemplate; } catch { } string resourceName; if (route != null) { resourceName = $"{method} {(newResourceNamesEnabled ? "/" : string.Empty)}{route.ToLowerInvariant()}"; } else if (requestUri != null) { var cleanUri = UriHelpers.GetCleanUriPath(requestUri); resourceName = $"{method} {cleanUri.ToLowerInvariant()}"; } else { resourceName = $"{method}"; } string controller = string.Empty; string action = string.Empty; string area = string.Empty; try { var routeValues = controllerContext.RouteData.Values; if (routeValues != null) { controller = (routeValues.GetValueOrDefault("controller") as string)?.ToLowerInvariant(); action = (routeValues.GetValueOrDefault("action") as string)?.ToLowerInvariant(); area = (routeValues.GetValueOrDefault("area") as string)?.ToLowerInvariant(); } } catch { } // Replace well-known routing tokens resourceName = resourceName .Replace("{area}", area) .Replace("{controller}", controller) .Replace("{action}", action); span.DecorateWebServerSpan( resourceName: resourceName, method: method, host: host, httpUrl: rawUrl, tags, headerTags); tags.AspNetAction = action; tags.AspNetController = controller; tags.AspNetArea = area; tags.AspNetRoute = route; if (newResourceNamesEnabled) { // set the resource name in the HttpContext so TracingHttpModule can update root span var httpContext = System.Web.HttpContext.Current; if (httpContext is not null) { httpContext.Items[SharedConstants.HttpContextPropagatedResourceNameKey] = resourceName; } } } catch (Exception ex) { Log.Error(ex, "Error populating scope data."); } }
internal static void UpdateSpan(IHttpControllerContext controllerContext, Span span, AspNetTags tags, IEnumerable <KeyValuePair <string, string> > headerTags) { try { var newResourceNamesEnabled = Tracer.Instance.Settings.RouteTemplateResourceNamesEnabled; var request = controllerContext.Request; Uri requestUri = request.RequestUri; string host = request.Headers.Host ?? string.Empty; string rawUrl = requestUri?.ToString().ToLowerInvariant() ?? string.Empty; string method = request.Method.Method?.ToUpperInvariant() ?? "GET"; string route = null; try { route = controllerContext.RouteData.Route.RouteTemplate; } catch { } IDictionary <string, object> routeValues = null; try { routeValues = controllerContext.RouteData.Values; } catch { } string resourceName; string controller = string.Empty; string action = string.Empty; string area = string.Empty; if (route is not null && routeValues is not null) { resourceName = AspNetResourceNameHelper.CalculateResourceName( httpMethod: method, routeTemplate: route, routeValues, defaults: null, out area, out controller, out action, addSlashPrefix: newResourceNamesEnabled, expandRouteTemplates: newResourceNamesEnabled && Tracer.Instance.Settings.ExpandRouteTemplatesEnabled); } else if (requestUri != null) { var cleanUri = UriHelpers.GetCleanUriPath(requestUri); resourceName = $"{method} {cleanUri}"; } else { resourceName = $"{method}"; } if (route is null && routeValues is not null) { // we weren't able to get the route template (somehow) but _were_ able to // get the route values. Not sure how this is possible, but is preexisting behaviour try { controller = (routeValues.GetValueOrDefault("controller") as string)?.ToLowerInvariant(); action = (routeValues.GetValueOrDefault("action") as string)?.ToLowerInvariant(); area = (routeValues.GetValueOrDefault("area") as string)?.ToLowerInvariant(); } catch { } } span.DecorateWebServerSpan( resourceName: resourceName, method: method, host: host, httpUrl: rawUrl, tags, headerTags); if (tags is not null) { tags.AspNetAction = action; tags.AspNetController = controller; tags.AspNetArea = area; tags.AspNetRoute = route; } if (newResourceNamesEnabled) { // set the resource name in the HttpContext so TracingHttpModule can update root span var httpContext = System.Web.HttpContext.Current; if (httpContext is not null) { httpContext.Items[SharedItems.HttpContextPropagatedResourceNameKey] = resourceName; } } }
/// <summary> /// Creates a scope used to instrument an MVC action and populates some common details. /// </summary> /// <param name="controllerContext">The System.Web.Mvc.ControllerContext that was passed as an argument to the instrumented method.</param> /// <returns>A new scope used to instrument an MVC action.</returns> public static Scope CreateScope(ControllerContextStruct controllerContext) { Scope scope = null; try { if (!Tracer.Instance.Settings.IsIntegrationEnabled(IntegrationId)) { // integration disabled, don't create a scope, skip this trace return(null); } var httpContext = controllerContext.HttpContext; if (httpContext == null) { return(null); } var newResourceNamesEnabled = Tracer.Instance.Settings.RouteTemplateResourceNamesEnabled; string host = httpContext.Request.Headers.Get("Host"); string httpMethod = httpContext.Request.HttpMethod.ToUpperInvariant(); string url = httpContext.Request.RawUrl.ToLowerInvariant(); string resourceName = null; RouteData routeData = controllerContext.RouteData; Route route = routeData?.Route as Route; RouteValueDictionary routeValues = routeData?.Values; bool wasAttributeRouted = false; if (route == null && routeData?.Route.GetType().FullName == RouteCollectionRouteTypeName) { var routeMatches = routeValues?.GetValueOrDefault("MS_DirectRouteMatches") as List <RouteData>; if (routeMatches?.Count > 0) { // route was defined using attribute routing i.e. [Route("/path/{id}")] // get route and routeValues from the RouteData in routeMatches wasAttributeRouted = true; route = routeMatches[0].Route as Route; routeValues = routeMatches[0].Values; if (route != null) { var resourceUrl = route.Url?.ToLowerInvariant() ?? string.Empty; if (resourceUrl.FirstOrDefault() != '/') { resourceUrl = string.Concat("/", resourceUrl); } resourceName = $"{httpMethod} {resourceUrl}"; } } } string routeUrl = route?.Url; string areaName = (routeValues?.GetValueOrDefault("area") as string)?.ToLowerInvariant(); string controllerName = (routeValues?.GetValueOrDefault("controller") as string)?.ToLowerInvariant(); string actionName = (routeValues?.GetValueOrDefault("action") as string)?.ToLowerInvariant(); if (newResourceNamesEnabled && string.IsNullOrEmpty(resourceName) && !string.IsNullOrEmpty(routeUrl)) { resourceName = $"{httpMethod} /{routeUrl.ToLowerInvariant()}"; } if (string.IsNullOrEmpty(resourceName) && httpContext.Request.Url != null) { var cleanUri = UriHelpers.GetCleanUriPath(httpContext.Request.Url); resourceName = $"{httpMethod} {cleanUri.ToLowerInvariant()}"; } if (string.IsNullOrEmpty(resourceName)) { // Keep the legacy resource name, just to have something resourceName = $"{httpMethod} {controllerName}.{actionName}"; } // Replace well-known routing tokens resourceName = resourceName .Replace("{area}", areaName) .Replace("{controller}", controllerName) .Replace("{action}", actionName); if (newResourceNamesEnabled && !wasAttributeRouted && routeValues is not null && route is not null) { // Remove unused parameters from conventional route templates // Don't bother with routes defined using attribute routing foreach (var parameter in route.Defaults) { var parameterName = parameter.Key; if (parameterName != "area" && parameterName != "controller" && parameterName != "action" && !routeValues.ContainsKey(parameterName)) { resourceName = resourceName.Replace($"/{{{parameterName}}}", string.Empty); } } } SpanContext propagatedContext = null; var tracer = Tracer.Instance; var tagsFromHeaders = Enumerable.Empty <KeyValuePair <string, string> >(); if (tracer.ActiveScope == null) { try { // extract propagated http headers var headers = httpContext.Request.Headers.Wrap(); propagatedContext = SpanContextPropagator.Instance.Extract(headers); tagsFromHeaders = SpanContextPropagator.Instance.ExtractHeaderTags(headers, tracer.Settings.HeaderTags, SpanContextPropagator.HttpRequestHeadersTagPrefix); } catch (Exception ex) { Log.Error(ex, "Error extracting propagated HTTP headers."); } } var tags = new AspNetTags(); scope = Tracer.Instance.StartActiveWithTags(OperationName, propagatedContext, tags: tags); Span span = scope.Span; span.DecorateWebServerSpan( resourceName: resourceName, method: httpMethod, host: host, httpUrl: url, tags, tagsFromHeaders); tags.AspNetRoute = routeUrl; tags.AspNetArea = areaName; tags.AspNetController = controllerName; tags.AspNetAction = actionName; tags.SetAnalyticsSampleRate(IntegrationId, tracer.Settings, enabledWithGlobalSetting: true); if (newResourceNamesEnabled) { // set the resource name in the HttpContext so TracingHttpModule can update root span httpContext.Items[SharedConstants.HttpContextPropagatedResourceNameKey] = resourceName; } } catch (Exception ex) { Log.Error(ex, "Error creating or populating scope."); } return(scope); }
/// <summary> /// Creates a scope used to instrument an MVC action and populates some common details. /// </summary> /// <param name="controllerContext">The System.Web.Mvc.ControllerContext that was passed as an argument to the instrumented method.</param> /// <returns>A new scope used to instrument an MVC action.</returns> internal static Scope CreateScope(ControllerContextStruct controllerContext) { Scope scope = null; try { var httpContext = controllerContext.HttpContext; if (httpContext == null) { return(null); } Span span = null; // integration enabled, go create a scope! var tracer = Tracer.Instance; if (tracer.Settings.IsIntegrationEnabled(IntegrationId)) { var newResourceNamesEnabled = tracer.Settings.RouteTemplateResourceNamesEnabled; string host = httpContext.Request.Headers.Get("Host"); string httpMethod = httpContext.Request.HttpMethod.ToUpperInvariant(); string url = httpContext.Request.Url?.ToString(); // Upstream uses RawUrl, ie. the part of the URL following the domain information. string resourceName = null; RouteData routeData = controllerContext.RouteData; Route route = routeData?.Route as Route; RouteValueDictionary routeValues = routeData?.Values; bool wasAttributeRouted = false; bool isChildAction = controllerContext.ParentActionViewContext.RouteData?.Values["controller"] is not null; if (isChildAction && newResourceNamesEnabled) { // For child actions, we want to stick to what was requested in the http request. // And the child action being a child, then we have already computed the resourcename. resourceName = httpContext.Items[SharedItems.HttpContextPropagatedResourceNameKey] as string; } if (route == null && routeData?.Route.GetType().FullName == RouteCollectionRouteTypeName) { var routeMatches = routeValues?.GetValueOrDefault("MS_DirectRouteMatches") as List <RouteData>; if (routeMatches?.Count > 0) { // route was defined using attribute routing i.e. [Route("/path/{id}")] // get route and routeValues from the RouteData in routeMatches wasAttributeRouted = true; route = routeMatches[0].Route as Route; routeValues = routeMatches[0].Values; } } string routeUrl = route?.Url; string areaName; string controllerName; string actionName; if ((wasAttributeRouted || newResourceNamesEnabled) && string.IsNullOrEmpty(resourceName) && !string.IsNullOrEmpty(routeUrl)) { resourceName = AspNetResourceNameHelper.CalculateResourceName( httpMethod: httpMethod, routeTemplate: routeUrl, routeValues, defaults: wasAttributeRouted ? null : route.Defaults, out areaName, out controllerName, out actionName, expandRouteTemplates: newResourceNamesEnabled && tracer.Settings.ExpandRouteTemplatesEnabled); } else { // just grab area/controller/action directly areaName = (routeValues?.GetValueOrDefault("area") as string)?.ToLowerInvariant(); controllerName = (routeValues?.GetValueOrDefault("controller") as string)?.ToLowerInvariant(); actionName = (routeValues?.GetValueOrDefault("action") as string)?.ToLowerInvariant(); } if (string.IsNullOrEmpty(resourceName)) { // Keep the legacy resource name, just to have something resourceName = $"{httpMethod} {controllerName}.{actionName}"; } SpanContext propagatedContext = null; var tagsFromHeaders = Enumerable.Empty <KeyValuePair <string, string> >(); if (tracer.InternalActiveScope == null) { try { // extract propagated http headers var headers = httpContext.Request.Headers.Wrap(); var propagator = SpanContextPropagator.Instance; propagatedContext = propagator.Extract(headers); tagsFromHeaders = headers.ExtractHeaderTags(tracer.Settings.HeaderTags, PropagationExtensions.HttpRequestHeadersTagPrefix); } catch (Exception ex) { Log.Error(ex, "Error extracting propagated HTTP headers."); } } var tags = new AspNetTags(); scope = tracer.StartActiveInternal(resourceName, propagatedContext, tags: tags); span = scope.Span; span.DecorateWebServerSpan( resourceName: resourceName, method: httpMethod, host: host, httpUrl: url, tags, tagsFromHeaders, httpContext.Request.UserHostAddress); span.LogicScope = isChildAction ? ChildActionOperationName : OperationName; tags.AspNetRoute = routeUrl; tags.AspNetArea = areaName; tags.AspNetController = controllerName; tags.AspNetAction = actionName; tags.SetAnalyticsSampleRate(IntegrationId, tracer.Settings, enabledWithGlobalSetting: true); if (string.IsNullOrEmpty(httpContext.Items[SharedItems.HttpContextPropagatedResourceNameKey] as string)) { // set the resource name in the HttpContext so TracingHttpModule can update root span httpContext.Items[SharedItems.HttpContextPropagatedResourceNameKey] = resourceName; } tracer.TracerManager.Telemetry.IntegrationGeneratedSpan(IntegrationId); } } catch (Exception ex) { Log.Error(ex, "Error creating or populating scope."); } return(scope); }
/// <summary> /// Creates a scope used to instrument an MVC action and populates some common details. /// </summary> /// <param name="controllerContext">The System.Web.Mvc.ControllerContext that was passed as an argument to the instrumented method.</param> /// <returns>A new scope used to instrument an MVC action.</returns> public static Scope CreateScope(object controllerContext) { Scope scope = null; try { if (!Tracer.Instance.Settings.IsIntegrationEnabled(IntegrationId)) { // integration disabled, don't create a scope, skip this trace return(null); } if (controllerContext == null || controllerContext.GetType().FullName != ControllerContextTypeName) { return(null); } var httpContext = controllerContext.GetProperty <HttpContextBase>("HttpContext").GetValueOrDefault(); if (httpContext == null) { return(null); } string host = httpContext.Request.Headers.Get("Host"); string httpMethod = httpContext.Request.HttpMethod.ToUpperInvariant(); string url = httpContext.Request.RawUrl.ToLowerInvariant(); string resourceName = null; RouteData routeData = controllerContext.GetProperty <RouteData>("RouteData").GetValueOrDefault(); Route route = routeData?.Route as Route; RouteValueDictionary routeValues = routeData?.Values; if (route == null && routeData?.Route.GetType().FullName == RouteCollectionRouteTypeName) { var routeMatches = routeValues?.GetValueOrDefault("MS_DirectRouteMatches") as List <RouteData>; if (routeMatches?.Count > 0) { // route was defined using attribute routing i.e. [Route("/path/{id}")] // get route and routeValues from the RouteData in routeMatches route = routeMatches[0].Route as Route; routeValues = routeMatches[0].Values; if (route != null) { var resourceUrl = route.Url?.ToLowerInvariant() ?? string.Empty; if (resourceUrl.FirstOrDefault() != '/') { resourceUrl = string.Concat("/", resourceUrl); } resourceName = $"{httpMethod} {resourceUrl}"; } } } if (string.IsNullOrEmpty(resourceName) && httpContext.Request.Url != null) { var cleanUri = UriHelpers.GetRelativeUrl(httpContext.Request.Url, tryRemoveIds: true); resourceName = $"{httpMethod} {cleanUri.ToLowerInvariant()}"; } string areaName = (routeValues?.GetValueOrDefault("area") as string)?.ToLowerInvariant(); string controllerName = (routeValues?.GetValueOrDefault("controller") as string)?.ToLowerInvariant(); string actionName = (routeValues?.GetValueOrDefault("action") as string)?.ToLowerInvariant(); if (string.IsNullOrEmpty(resourceName)) { // Keep the legacy resource name, just to have something resourceName = $"{httpMethod} {controllerName}.{actionName}"; } SpanContext propagatedContext = null; var tracer = Tracer.Instance; var tagsFromHeaders = Enumerable.Empty <KeyValuePair <string, string> >(); if (tracer.ActiveScope == null) { try { // extract propagated http headers var headers = httpContext.Request.Headers.Wrap(); propagatedContext = SpanContextPropagator.Instance.Extract(headers); tagsFromHeaders = SpanContextPropagator.Instance.ExtractHeaderTags(headers, tracer.Settings.HeaderTags); } catch (Exception ex) { Log.Error(ex, "Error extracting propagated HTTP headers."); } } var tags = new AspNetTags(); scope = Tracer.Instance.StartActiveWithTags(OperationName, propagatedContext, tags: tags); Span span = scope.Span; // Fail safe to catch templates in routing values resourceName = resourceName .Replace("{area}", areaName) .Replace("{controller}", controllerName) .Replace("{action}", actionName); span.DecorateWebServerSpan( resourceName: resourceName, method: httpMethod, host: host, httpUrl: url, tags, tagsFromHeaders); tags.AspNetRoute = route?.Url; tags.AspNetArea = areaName; tags.AspNetController = controllerName; tags.AspNetAction = actionName; tags.SetAnalyticsSampleRate(IntegrationId, tracer.Settings, enabledWithGlobalSetting: true); } catch (Exception ex) { Log.Error(ex, "Error creating or populating scope."); } return(scope); }