/// <summary>
        /// Creates a span context for outbound http requests, or get the active one.
        /// Used to propagate headers without changing the active span.
        /// </summary>
        /// <param name="tracer">The tracer instance to use to create the span.</param>
        /// <param name="httpMethod">The HTTP method used by the request.</param>
        /// <param name="requestUri">The URI requested by the request.</param>
        /// <param name="integrationName">The name of the integration creating this scope.</param>
        /// <returns>A span context to use to populate headers</returns>
        public static SpanContext CreateHttpSpanContext(
            Tracer tracer,
            string httpMethod,
            Uri requestUri,
            string integrationName)
        {
            if (!tracer.Settings.IsIntegrationEnabled(integrationName))
            {
                // integration disabled, skip this trace
                return(null);
            }

            try
            {
                var activeScope = GetActiveHttpScope(tracer, httpMethod, requestUri);

                if (activeScope != null)
                {
                    // This HTTP request was already instrumented return the active HTTP context.
                    return(activeScope.Span.Context);
                }

                return(tracer.CreateSpanContext(out bool _));
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error creating or populating span context.");
            }

            return(null);
        }
示例#2
0
        public static object ExecuteAsyncGeneric(
            object wireProtocol,
            object connection,
            object cancellationTokenSource,
            int opCode,
            int mdToken,
            long moduleVersionPtr)
        {
            // The generic type for this method comes from the declaring type of wireProtocol
            if (wireProtocol == null)
            {
                throw new ArgumentNullException(nameof(wireProtocol));
            }

            var tokenSource       = cancellationTokenSource as CancellationTokenSource;
            var cancellationToken = tokenSource?.Token ?? CancellationToken.None;

            var wireProtocolType        = wireProtocol.GetType();
            var wireProtocolGenericArgs = GetGenericsFromWireProtocol(wireProtocolType);

            const string methodName = nameof(ExecuteAsync);
            Func <object, object, CancellationToken, object> executeAsync;

            try
            {
                executeAsync =
                    MethodBuilder <Func <object, object, CancellationToken, object> >
                    .Start(moduleVersionPtr, mdToken, opCode, methodName)
                    .WithConcreteType(wireProtocolType)
                    .WithDeclaringTypeGenerics(wireProtocolGenericArgs)
                    .WithParameters(connection, cancellationToken)
                    .WithNamespaceAndNameFilters(ClrNames.GenericTask, "MongoDB.Driver.Core.Connections.IConnection", ClrNames.CancellationToken)
                    .Build();
            }
            catch (Exception ex)
            {
                // profiled app will not continue working as expected without this method
                Log.Error(ex, $"Error resolving {wireProtocolType.Name}.{methodName}(IConnection connection, CancellationToken cancellationToken)");
                throw;
            }

            return(AsyncHelper.InvokeGenericTaskDelegate(
                       wireProtocolType,
                       wireProtocolGenericArgs[0],
                       nameof(ExecuteAsyncInternalGeneric),
                       typeof(MongoDbIntegration),
                       wireProtocol,
                       connection,
                       cancellationToken,
                       executeAsync));
        }
示例#3
0
        private static SpanContext ExtractPropagatedContext(IPropagator propagator, HttpRequest request)
        {
            try
            {
                // extract propagation details from http headers
                var requestHeaders = request.Headers;

                if (requestHeaders != null)
                {
                    var headersCollection = new DictionaryHeadersCollection();

                    foreach (var header in requestHeaders)
                    {
                        string   key    = header.Key;
                        string[] values = header.Value.ToArray();

                        if (key != null && values.Length > 0)
                        {
                            headersCollection.Add(key, values);
                        }
                    }

                    return(propagator.Extract(headersCollection));
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error extracting propagated HTTP headers.");
            }

            return(null);
        }
        /// <summary>
        /// Gets a <see cref="ConcurrentDictionary{TKey, TValue}"/> containing all of the values.
        /// </summary>
        /// <remarks>
        /// Example JSON where `globalTags` is the configuration key.
        /// {
        ///  "globalTags": {
        ///     "name1": "value1",
        ///     "name2": "value2"
        ///     }
        /// }
        /// </remarks>
        /// <param name="key">The key that identifies the setting.</param>
        /// <returns><see cref="IDictionary{TKey, TValue}"/> containing all of the key-value pairs.</returns>
        /// <exception cref="JsonReaderException">Thrown if the configuration value is not a valid JSON string.</exception>"
        public IDictionary <string, string> GetDictionary(string key)
        {
            var token = _configuration.SelectToken(key, errorWhenNoMatch: false);

            if (token == null)
            {
                return(null);
            }

            if (token.Type == JTokenType.Object)
            {
                try
                {
                    var dictionary = token
                                     ?.ToObject <ConcurrentDictionary <string, string> >();
                    return(dictionary);
                }
                catch (Exception e)
                {
                    Log.Error(e, "Unable to parse configuration value for {0} as key-value pairs of strings.", key);
                    return(null);
                }
            }

            return(StringConfigurationSource.ParseCustomKeyValues(token.ToString()));
        }
        private async Task FlushTracesTaskLoopAsync()
        {
            while (true)
            {
                try
                {
                    await Task.WhenAny(Task.Delay(TimeSpan.FromSeconds(1)), _processExit.Task)
                    .ConfigureAwait(false);

                    if (_processExit.Task.IsCompleted)
                    {
                        await FlushTracesAsync().ConfigureAwait(false);

                        return;
                    }
                    else
                    {
                        await FlushTracesAsync().ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Log.Error(ex, "An unhandled error occurred during the flushing task");
                }
            }
        }
        public async Task SendTracesAsync(Span[][] traces)
        {
            // retry up to 5 times with exponential back-off
            var retryLimit    = 5;
            var retryCount    = 1;
            var sleepDuration = 100; // in milliseconds

            while (true)
            {
                HttpResponseMessage responseMessage;

                try
                {
                    // re-create content on every retry because some versions of HttpClient always dispose of it, so we can't reuse.
                    using (var content = new ZipkinContent(traces, _settings))
                    {
                        responseMessage = await _client.PostAsync(_settings.EndpointUrl, content).ConfigureAwait(false);

                        responseMessage.EnsureSuccessStatusCode();
                        return;
                    }
                }
                catch (Exception ex)
                {
                    if (ex.InnerException is InvalidOperationException ioe)
                    {
                        Log.Error("A fatal error occurred while sending traces to {Endpoint}\n{Exception}", _settings.EndpointUrl, ex.Message);
                        return;
                    }

                    if (retryCount >= retryLimit)
                    {
                        // stop retrying
                        Log.Error("No more retries to send traces to {Endpoint}\n{Exception}", _settings.EndpointUrl, ex.Message);
                        return;
                    }

                    Log.Debug("Error sending traces to {Endpoint}\n{Exception}", _settings.EndpointUrl, ex.Message);

                    // retry
                    await Task.Delay(sleepDuration).ConfigureAwait(false);

                    retryCount++;
                    sleepDuration *= 2;
                }
            }
        }
        private static Scope CreateScope(object controllerContext)
        {
            Scope scope = 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 <HttpRequestMessage>("Request").GetValueOrDefault();
                SpanContext propagatedContext = null;

                if (request != null && tracer.ActiveScope == null)
                {
                    try
                    {
                        // extract propagated http headers
                        var headers = request.Headers.Wrap();
                        propagatedContext = B3SpanContextPropagator.Instance.Extract(headers);
                    }
                    catch (Exception ex)
                    {
                        Log.Error(ex, "Error extracting propagated HTTP headers.");
                    }
                }

                scope = tracer.StartActive(OperationName, propagatedContext);
                UpdateSpan(controllerContext, scope.Span);

                // set analytics sample rate if enabled
                var analyticsSampleRate = tracer.Settings.GetIntegrationAnalyticsSampleRate(IntegrationName, enabledWithGlobalSetting: true);
                scope.Span.SetMetric(Tags.Analytics, analyticsSampleRate);
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error creating scope.");
            }

            return(scope);
        }
 void IObserver <KeyValuePair <string, object> > .OnNext(KeyValuePair <string, object> value)
 {
     try
     {
         OnNext(value.Key, value.Value);
     }
     catch (Exception ex)
     {
         Log.Error(ex, "Event Exception: {0}", value.Key);
     }
 }
示例#9
0
        public static int ExecuteNonQuery(
            object command,
            int opCode,
            int mdToken,
            long moduleVersionPtr)
        {
            Func <DbCommand, int> instrumentedMethod;

            try
            {
                instrumentedMethod =
                    MethodBuilder <Func <DbCommand, int> >
                    .Start(moduleVersionPtr, mdToken, opCode, AdoNetConstants.MethodNames.ExecuteNonQuery)
                    .WithConcreteType(typeof(DbCommand))
                    .WithNamespaceAndNameFilters(ClrNames.Int32)
                    .Build();
            }
            catch (Exception ex)
            {
                Log.Error(ex, $"Error resolving {DbCommandTypeName}.{AdoNetConstants.MethodNames.ExecuteNonQuery}(...)");
                throw;
            }

            var dbCommand = command as DbCommand;

            using (var scope = ScopeFactory.CreateDbCommandScope(Tracer.Instance, dbCommand, IntegrationName))
            {
                try
                {
                    return(instrumentedMethod(dbCommand));
                }
                catch (Exception ex)
                {
                    scope?.Span.SetException(ex);
                    throw;
                }
            }
        }
示例#10
0
        public static Module Get(Guid moduleVersionId)
        {
            // First attempt at cached values with no blocking
            if (_modules.TryGetValue(moduleVersionId, out Module value))
            {
                return(value);
            }

            // Block if a population event is happening
            _populationResetEvent.Wait();

            // See if the previous population event populated what we need
            if (_modules.TryGetValue(moduleVersionId, out value))
            {
                return(value);
            }

            if (_failures >= MaxFailures)
            {
                // For some unforeseeable reason we have failed on a lot of AppDomain lookups
                if (!_shortCircuitLogicHasLogged)
                {
                    Log.Warning("Datadog is unable to continue attempting module lookups for this AppDomain. Falling back to legacy method lookups.");
                }

                return(null);
            }

            // Block threads on this event
            _populationResetEvent.Reset();

            try
            {
                PopulateModules();
            }
            catch (Exception ex)
            {
                _failures++;
                Log.Error(ex, "Error when populating modules.");
            }
            finally
            {
                // Continue threads blocked on this event
                _populationResetEvent.Set();
            }

            _modules.TryGetValue(moduleVersionId, out value);

            return(value);
        }
示例#11
0
        /// <summary>
        /// Gets an "application name" for the executing application by looking at
        /// the hosted app name (.NET Framework on IIS only), assembly name, and process name.
        /// </summary>
        /// <returns>The default service name.</returns>
        private static string GetApplicationName()
        {
            try
            {
#if !NETSTANDARD2_0
                // System.Web.dll is only available on .NET Framework
                if (System.Web.Hosting.HostingEnvironment.IsHosted)
                {
                    // if this app is an ASP.NET application, return "SiteName/ApplicationVirtualPath".
                    // note that ApplicationVirtualPath includes a leading slash.
                    return((System.Web.Hosting.HostingEnvironment.SiteName + System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath).TrimEnd('/'));
                }
#endif

                return(Assembly.GetEntryAssembly()?.GetName().Name ??
                       Process.GetCurrentProcess().ProcessName);
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error creating default service name.");
                return(null);
            }
        }
        private string CompileResourceId()
        {
            string resourceId = null;

            try
            {
                var success = true;
                if (SubscriptionId == null)
                {
                    success = false;
                    Log.Warning("Could not successfully retrieve the subscription ID from variable: {0}", WebsiteOwnerNameKey);
                }

                if (SiteName == null)
                {
                    success = false;
                    Log.Warning("Could not successfully retrieve the deployment ID from variable: {0}", SiteNameKey);
                }

                if (ResourceGroup == null)
                {
                    success = false;
                    Log.Warning("Could not successfully retrieve the resource group name from variable: {0}", ResourceGroupKey);
                }

                if (success)
                {
                    resourceId = $"/subscriptions/{SubscriptionId}/resourcegroups/{ResourceGroup}/providers/microsoft.web/sites/{SiteName}".ToLowerInvariant();
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Could not successfully setup the resource id for azure app services.");
            }

            return(resourceId);
        }
        internal static Scope CreateScope(Tracer tracer, string integrationName, string componentName, string host, string port, string rawCommand)
        {
            if (!Tracer.Instance.Settings.IsIntegrationEnabled(integrationName))
            {
                // integration disabled, don't create a scope, skip this trace
                return(null);
            }

            Scope scope = null;

            try
            {
                int    separatorIndex = rawCommand.IndexOf(' ');
                string command;

                if (separatorIndex >= 0)
                {
                    command = rawCommand.Substring(0, separatorIndex);
                }
                else
                {
                    command = rawCommand;
                }

                scope = tracer.StartActive(command ?? OperationName, serviceName: tracer.DefaultServiceName);

                var span = scope.Span;
                span.SetTag(Tags.InstrumentationName, componentName);
                span.SetTag(Tags.DbType, SpanTypes.Redis);
                span.SetTag(Tags.SpanKind, SpanKinds.Client);
                if (Tracer.Instance.Settings.TagRedisCommands)
                {
                    span.SetTag(Tags.DbStatement, rawCommand);
                }

                span.SetTag(Tags.OutHost, host);
                span.SetTag(Tags.OutPort, port);

                // set analytics sample rate if enabled
                var analyticsSampleRate = tracer.Settings.GetIntegrationAnalyticsSampleRate(integrationName, enabledWithGlobalSetting: false);
                span.SetMetric(Tags.Analytics, analyticsSampleRate);
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error creating or populating scope.");
            }

            return(scope);
        }
        public static Scope CreateScope(Tracer tracer, string integrationName, object pipeline, object requestData)
        {
            if (!tracer.Settings.IsIntegrationEnabled(integrationName))
            {
                // integration disabled, don't create a scope, skip this trace
                return(null);
            }

            string requestName = pipeline.GetProperty("RequestParameters")
                                 .GetValueOrDefault()
                                 ?.GetType()
                                 .Name
                                 .Replace("RequestParameters", string.Empty);

            var pathAndQuery = requestData.GetProperty <string>("PathAndQuery").GetValueOrDefault() ??
                               requestData.GetProperty <string>("Path").GetValueOrDefault();

            string method = requestData.GetProperty("Method").GetValueOrDefault()?.ToString();
            var    url    = requestData.GetProperty("Uri").GetValueOrDefault()?.ToString();

            Scope scope = null;

            try
            {
                var operationName = requestName ?? OperationName;
                scope = tracer.StartActive(operationName, serviceName: tracer.DefaultServiceName);
                var span = scope.Span;
                span.SetTag(Tags.InstrumentationName, ComponentValue);
                span.SetTag(Tags.DbType, SpanType);
                span.SetTag(Tags.SpanKind, SpanKinds.Client);
                span.SetTag(ElasticsearchMethodKey, method);
                span.SetTag(ElasticsearchUrlKey, url);

                // set analytics sample rate if enabled
                var analyticsSampleRate = tracer.Settings.GetIntegrationAnalyticsSampleRate(integrationName, enabledWithGlobalSetting: false);
                span.SetMetric(Tags.Analytics, analyticsSampleRate);
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error creating or populating scope.");
            }

            return(scope);
        }
        public static void ErrorRetrievingMethod(
            this SignalFx.Tracing.Vendors.Serilog.ILogger logger,
            Exception exception,
            long moduleVersionPointer,
            int mdToken,
            int opCode,
            string instrumentedType,
            string methodName,
            string instanceType        = null,
            string[] relevantArguments = null)
        {
            var instrumentedMethod = $"{instrumentedType}.{methodName}(...)";

            if (instanceType != null)
            {
                instrumentedMethod = $"{instrumentedMethod} on {instanceType}";
            }

            if (relevantArguments != null)
            {
                instrumentedMethod = $"{instrumentedMethod} with {string.Join(", ", relevantArguments)}";
            }

            var moduleVersionId = PointerHelpers.GetGuidFromNativePointer(moduleVersionPointer);

            logger.Error(
                exception,
                $"Error (MVID: {moduleVersionId}, mdToken: {mdToken}, opCode: {opCode}) could not retrieve: {instrumentedMethod}");

            var statsd = Tracer.Instance.Statsd;

            if (statsd != null)
            {
                string[] tags = { $"instrumented-method:{instrumentedMethod}" };
                statsd.AppendException(exception, source: instrumentedType, message: "Error retrieving instrumented method", tags);
                statsd.Send();
            }
        }
示例#16
0
        public static object Validate(
            object documentValidator,
            object originalQuery,
            object schema,
            object document,
            object rules,
            object userContext,
            object inputs,
            int opCode,
            int mdToken,
            long moduleVersionPtr)
        {
            if (documentValidator == null)
            {
                throw new ArgumentNullException(nameof(documentValidator));
            }

            const string methodName = nameof(Validate);

            // At runtime, get a Type object for GraphQL.ExecutionResult
            var documentValidatorInstanceType = documentValidator.GetType();

            try
            {
                var graphQLAssembly = AppDomain.CurrentDomain
                                      .GetAssemblies()
                                      .Single(a => a.GetName().Name.Equals(GraphQLAssemblyName));
            }
            catch (Exception ex)
            {
                // This shouldn't happen because the GraphQL assembly should have been loaded to construct various other types
                // profiled app will not continue working as expected without this method
                Log.Error(ex, $"Error finding types in the GraphQL assembly.");
                throw;
            }

            Func <object, object, object, object, object, object, object, object> instrumentedMethod;

            try
            {
                instrumentedMethod =
                    MethodBuilder <Func <object, object, object, object, object, object, object, object> >
                    .Start(moduleVersionPtr, mdToken, opCode, methodName)
                    .WithConcreteType(documentValidatorInstanceType)
                    .WithParameters(originalQuery, schema, document, rules, userContext, inputs)
                    .WithNamespaceAndNameFilters(
                        GraphQLValidationResultInterfaceName,
                        ClrNames.String,
                        "GraphQL.Types.ISchema",
                        "GraphQL.Language.AST.Document",
                        "System.Collections.Generic.IEnumerable`1",
                        ClrNames.Ignore,
                        "GraphQL.Inputs")
                    .Build();
            }
            catch (Exception ex)
            {
                Log.ErrorRetrievingMethod(
                    exception: ex,
                    moduleVersionPointer: moduleVersionPtr,
                    mdToken: mdToken,
                    opCode: opCode,
                    instrumentedType: GraphQLDocumentValidatorInterfaceName,
                    methodName: methodName,
                    instanceType: documentValidator.GetType().AssemblyQualifiedName);
                throw;
            }

            using (var scope = CreateScopeFromValidate(document))
            {
                try
                {
                    var validationResult = instrumentedMethod(documentValidator, originalQuery, schema, document, rules, userContext, inputs);
                    RecordExecutionErrorsIfPresent(scope.Span, "GraphQL.Validation.ValidationError", validationResult.GetProperty("Errors").GetValueOrDefault());
                    return(validationResult);
                }
                catch (Exception ex)
                {
                    scope?.Span.SetException(ex);
                    throw;
                }
            }
        }
        private static Scope CreateScope(RequestContext requestContext)
        {
            var requestMessage = requestContext?.RequestMessage;

            if (requestMessage == null)
            {
                return(null);
            }

            var tracer = Tracer.Instance;

            if (!tracer.Settings.IsIntegrationEnabled(IntegrationName))
            {
                // integration disabled, don't create a scope, skip this trace
                return(null);
            }

            Scope scope = null;

            try
            {
                SpanContext propagatedContext = null;
                string      host       = null;
                string      httpMethod = null;

                if (requestMessage.Properties.TryGetValue("httpRequest", out var httpRequestProperty) &&
                    httpRequestProperty is HttpRequestMessageProperty httpRequestMessageProperty)
                {
                    // we're using an http transport
                    host       = httpRequestMessageProperty.Headers[HttpRequestHeader.Host];
                    httpMethod = httpRequestMessageProperty.Method?.ToUpperInvariant();

                    // try to extract propagated context values from http headers
                    if (tracer.ActiveScope == null)
                    {
                        try
                        {
                            var headers = httpRequestMessageProperty.Headers.Wrap();
                            propagatedContext = B3SpanContextPropagator.Instance.Extract(headers);
                        }
                        catch (Exception ex)
                        {
                            Log.Error(ex, "Error extracting propagated HTTP headers.");
                        }
                    }
                }

                var operationNameSuffix = requestMessage.Headers.Action ?? requestMessage.Headers.To?.LocalPath;
                var operationName       = !string.IsNullOrEmpty(operationNameSuffix)
                    ? "wcf.request " + operationNameSuffix
                    : "wcf.request";

                scope = tracer.StartActive(operationName, propagatedContext);
                var span = scope.Span;

                span.DecorateWebServerSpan(
                    resourceName: null,
                    httpMethod,
                    host,
                    httpUrl: requestMessage.Headers.To?.AbsoluteUri);

                // set analytics sample rate if enabled
                var analyticsSampleRate = tracer.Settings.GetIntegrationAnalyticsSampleRate(IntegrationName, enabledWithGlobalSetting: true);
                span.SetMetric(Tags.Analytics, analyticsSampleRate);
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error creating or populating scope.");
            }

            // always returns the scope, even if it's null
            return(scope);
        }
        private void OnBeginRequest(object sender, EventArgs eventArgs)
        {
            Scope scope = null;

            try
            {
                var tracer = Tracer.Instance;

                if (!tracer.Settings.IsIntegrationEnabled(IntegrationName))
                {
                    // integration disabled
                    return;
                }

                var httpContext = (sender as HttpApplication)?.Context;

                if (httpContext == null)
                {
                    return;
                }

                HttpRequest httpRequest       = httpContext.Request;
                SpanContext propagatedContext = null;

                if (tracer.ActiveScope == null)
                {
                    try
                    {
                        // extract propagated http headers
                        var headers = httpRequest.Headers.Wrap();
                        propagatedContext = B3SpanContextPropagator.Instance.Extract(headers);
                    }
                    catch (Exception ex)
                    {
                        Log.Error(ex, "Error extracting propagated HTTP headers.");
                    }
                }

                string host         = httpRequest.Headers.Get("Host");
                string httpMethod   = httpRequest.HttpMethod.ToUpperInvariant();
                string url          = httpRequest.RawUrl.ToLowerInvariant();
                string path         = UriHelpers.GetRelativeUrl(httpRequest.Url, tryRemoveIds: true);
                string resourceName = $"{httpMethod} {path.ToLowerInvariant()}";

                scope = tracer.StartActive(_requestOperationName, propagatedContext);

                IPAddress remoteIp = null;
                if (Tracer.Instance.Settings.AddClientIpToServerSpans)
                {
                    IPAddress.TryParse(httpRequest.UserHostAddress, out remoteIp);
                }

                scope.Span.DecorateWebServerSpan(resourceName, httpMethod, host, url, remoteIp);

                // set analytics sample rate if enabled
                var analyticsSampleRate = tracer.Settings.GetIntegrationAnalyticsSampleRate(IntegrationName, enabledWithGlobalSetting: true);
                scope.Span.SetMetric(Tags.Analytics, analyticsSampleRate);

                httpContext.Items[_httpContextScopeKey] = scope;
            }
            catch (Exception ex)
            {
                // Dispose here, as the scope won't be in context items and won't get disposed on request end in that case...
                scope?.Dispose();
                Log.Error(ex, "Datadog ASP.NET HttpModule instrumentation error");
            }
        }
        /// <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(IntegrationName))
                {
                    // 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 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;

                if (tracer.ActiveScope == null)
                {
                    try
                    {
                        // extract propagated http headers
                        var headers = httpContext.Request.Headers.Wrap();
                        propagatedContext = tracer.Propagator.Extract(headers);
                    }
                    catch (Exception ex)
                    {
                        Log.Error(ex, "Error extracting propagated HTTP headers.");
                    }
                }

                scope = Tracer.Instance.StartActive(OperationName, propagatedContext);
                Span span = scope.Span;

                // Fail safe to catch templates in routing values
                resourceName =
                    resourceName
                    .Replace("{controller}", controllerName)
                    .Replace("{action}", actionName);

                IPAddress remoteIp = null;
                if (Tracer.Instance.Settings.AddClientIpToServerSpans)
                {
                    IPAddress.TryParse(httpContext.Request.UserHostAddress, out remoteIp);
                }

                span.DecorateWebServerSpan(
                    resourceName: resourceName,
                    method: httpMethod,
                    host: host,
                    httpUrl: url,
                    remoteIp: remoteIp);
                span.SetTag(Tags.AspNetRoute, route?.Url);
                span.SetTag(Tags.AspNetController, controllerName);
                span.SetTag(Tags.AspNetAction, actionName);

                // set analytics sample rate if enabled
                var analyticsSampleRate = tracer.Settings.GetIntegrationAnalyticsSampleRate(IntegrationName, enabledWithGlobalSetting: true);
                span.SetMetric(Tags.Analytics, analyticsSampleRate);
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error creating or populating scope.");
            }

            return(scope);
        }
        private AspNetAmbientContext(string integrationName, object httpContext)
        {
            try
            {
                Tracer       = Tracer.Instance;
                _httpContext = httpContext;

                var request  = _httpContext.GetProperty("Request").GetValueOrDefault();
                var response = _httpContext.GetProperty("Response").GetValueOrDefault();

                GetTagValues(
                    request,
                    out string absoluteUri,
                    out string httpMethod,
                    out string host,
                    out string resourceName);

                if (httpMethod == StartupDiagnosticMethod)
                {
                    // An initial diagnostic HttpContext is created on the start of many web applications
                    AbortRegistration = true;
                    return;
                }

                RegisterForDisposalWithPipeline(response, this);

                SpanContext propagatedContext = null;

                if (Tracer.ActiveScope == null)
                {
                    try
                    {
                        // extract propagated http headers
                        var requestHeaders = request.GetProperty <IEnumerable>("Headers").GetValueOrDefault();

                        if (requestHeaders != null)
                        {
                            var headersCollection = new DictionaryHeadersCollection();

                            foreach (object header in requestHeaders)
                            {
                                var key    = header.GetProperty <string>("Key").GetValueOrDefault();
                                var values = header.GetProperty <IList <string> >("Value").GetValueOrDefault();

                                if (key != null && values != null)
                                {
                                    headersCollection.Add(key, values);
                                }
                            }

                            propagatedContext = B3SpanContextPropagator.Instance.Extract(headersCollection);
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Error(ex, "Error extracting propagated HTTP headers.");
                    }
                }

                _rootScope = Tracer.StartActive(TopLevelOperationName, propagatedContext);

                RegisterForDisposal(_rootScope);

                var span = _rootScope.Span;

                IPAddress remoteIp = null;
                if (Tracer.Instance.Settings.AddClientIpToServerSpans)
                {
                    var userHostAddress = request.GetProperty <string>("UserHostAddress").GetValueOrDefault();
                    IPAddress.TryParse(userHostAddress, out remoteIp);
                }

                span.DecorateWebServerSpan(
                    resourceName: resourceName,
                    method: httpMethod,
                    host: host,
                    httpUrl: absoluteUri,
                    remoteIp: remoteIp);

                var statusCode = response.GetProperty <int>("StatusCode");

                if (statusCode.HasValue)
                {
                    span.SetTag(Tags.HttpStatusCode, statusCode.Value.ToString());
                }

                var analyticSampleRate = Tracer.Settings.GetIntegrationAnalyticsSampleRate(integrationName, enabledWithGlobalSetting: true);
                span.SetMetric(Tags.Analytics, analyticSampleRate);
            }
            catch (Exception ex)
            {
                // Don't crash client apps
                Log.Error(ex, $"Exception when initializing {nameof(AspNetAmbientContext)}.");
            }
        }