Example #1
0
        public override void OnStartActivity(Activity activity, object payload)
        {
            const string EventNameSuffix = ".OnStartActivity";

            if (!(this.startRequestFetcher.Fetch(payload) is HttpRequestMessage request))
            {
                InstrumentationEventSource.Log.NullPayload(nameof(HttpHandlerDiagnosticListener) + EventNameSuffix);
                return;
            }

            if (request.Headers.Contains("traceparent"))
            {
                // this request is already instrumented, we should back off
                return;
            }

            // TODO: Avoid the reflection hack once .NET ships new Activity with Kind settable.
            activity.GetType().GetProperty("Kind").SetValue(activity, ActivityKind.Client);
            activity.DisplayName = HttpTagHelper.GetOperationNameForHttpMethod(request.Method);

            var samplingParameters = new ActivitySamplingParameters(
                activity.Context,
                activity.TraceId,
                activity.DisplayName,
                activity.Kind,
                activity.Tags,
                activity.Links);

            // TODO: Find a way to avoid Instrumentation being tied to Sampler
            var samplingDecision = this.sampler.ShouldSample(samplingParameters);

            activity.IsAllDataRequested = samplingDecision.IsSampled;
            if (samplingDecision.IsSampled)
            {
                activity.ActivityTraceFlags |= ActivityTraceFlags.Recorded;
            }

            if (activity.IsAllDataRequested)
            {
                activity.AddTag(SpanAttributeConstants.ComponentKey, "http");
                activity.AddTag(SpanAttributeConstants.HttpMethodKey, HttpTagHelper.GetNameForHttpMethod(request.Method));
                activity.AddTag(SpanAttributeConstants.HttpHostKey, HttpTagHelper.GetHostTagValueFromRequestUri(request.RequestUri));
                activity.AddTag(SpanAttributeConstants.HttpUrlKey, request.RequestUri.OriginalString);

                if (this.options.SetHttpFlavor)
                {
                    activity.AddTag(SpanAttributeConstants.HttpFlavorKey, HttpTagHelper.GetFlavorTagValueFromProtocolVersion(request.Version));
                }
            }

            if (!(this.httpClientSupportsW3C && this.options.TextFormat is TraceContextFormat))
            {
                // TODO: implement this
                // this.options.TextFormat.Inject(span.Context, request, (r, k, v) => r.Headers.Add(k, v));
            }
        }
        public override void OnStartActivity(Activity activity, object payload)
        {
            const string EventNameSuffix = ".OnStartActivity";
            var          context         = this.startContextFetcher.Fetch(payload) as HttpContext;

            if (context == null)
            {
                InstrumentationEventSource.Log.NullPayload(nameof(HttpInListener) + EventNameSuffix);
                return;
            }

            if (this.options.RequestFilter != null && !this.options.RequestFilter(context))
            {
                InstrumentationEventSource.Log.RequestIsFilteredOut(activity.OperationName);
                return;
            }

            var request = context.Request;
            var path    = (request.PathBase.HasValue || request.Path.HasValue) ? (request.PathBase + request.Path).ToString() : "/";

            activity.DisplayName = path;

            if (!this.hostingSupportsW3C || !(this.options.TextFormat is TraceContextFormat))
            {
                // This requires to ignore the current activity and create a new one
                // using the context extracted from w3ctraceparent header or
                // using the format TextFormat supports.
                // TODO: implement this

                /*
                 * var ctx = this.options.TextFormat.Extract<HttpRequest>(
                 *  request,
                 *  (r, name) => r.Headers[name]);
                 *
                 * Activity newOne = new Activity(path);
                 * newOne.SetParentId(ctx.Id);
                 * newOne.TraceState = ctx.TraceStateString;
                 * activity = newOne;
                 */
            }

            // TODO: Avoid the reflection hack once .NET ships new Activity with Kind settable.
            activity.GetType().GetProperty("Kind").SetValue(activity, ActivityKind.Server);

            var samplingParameters = new ActivitySamplingParameters(
                activity.Context,
                activity.TraceId,
                activity.DisplayName,
                activity.Kind,
                activity.Tags,
                activity.Links);

            // TODO: Find a way to avoid Instrumentation being tied to Sampler
            var samplingDecision = this.sampler.ShouldSample(samplingParameters);

            activity.IsAllDataRequested = samplingDecision.IsSampled;
            if (samplingDecision.IsSampled)
            {
                activity.ActivityTraceFlags |= ActivityTraceFlags.Recorded;
            }

            if (activity.IsAllDataRequested)
            {
                // see the spec https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md

                if (request.Host.Port == 80 || request.Host.Port == 443)
                {
                    activity.AddTag(SpanAttributeConstants.HttpHostKey, request.Host.Host);
                }
                else
                {
                    activity.AddTag(SpanAttributeConstants.HttpHostKey, request.Host.Host + ":" + request.Host.Port);
                }

                activity.AddTag(SpanAttributeConstants.HttpMethodKey, request.Method);
                activity.AddTag(SpanAttributeConstants.HttpPathKey, path);

                var userAgent = request.Headers["User-Agent"].FirstOrDefault();
                activity.AddTag(SpanAttributeConstants.HttpUserAgentKey, userAgent);
                activity.AddTag(SpanAttributeConstants.HttpUrlKey, GetUri(request));
            }
        }
        public override void OnStartActivity(Activity activity, object payload)
        {
            const string EventNameSuffix = ".OnStartActivity";

            var context = HttpContext.Current;

            if (context == null)
            {
                InstrumentationEventSource.Log.NullPayload(nameof(HttpInListener) + EventNameSuffix);
                return;
            }

            if (this.options.RequestFilter != null && !this.options.RequestFilter(context))
            {
                // TODO: These filters won't prevent the activity from being tracked
                // as they are fired anyway.
                InstrumentationEventSource.Log.RequestIsFilteredOut(activity.OperationName);
                return;
            }

            // TODO: Avoid the reflection hack once .NET ships new Activity with Kind settable.
            activity.GetType().GetProperty("Kind").SetValue(activity, ActivityKind.Server);

            var request       = context.Request;
            var requestValues = request.Unvalidated;

            // see the spec https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md
            var path = requestValues.Path;

            activity.DisplayName = path;

            var samplingParameters = new ActivitySamplingParameters(
                activity.Context,
                activity.TraceId,
                activity.DisplayName,
                activity.Kind,
                activity.Tags,
                activity.Links);

            // TODO: Find a way to avoid Instrumentation being tied to Sampler
            var samplingDecision = this.sampler.ShouldSample(samplingParameters);

            activity.IsAllDataRequested = samplingDecision.IsSampled;
            if (samplingDecision.IsSampled)
            {
                activity.ActivityTraceFlags |= ActivityTraceFlags.Recorded;
            }

            if (!(this.options.TextFormat is TraceContextFormat))
            {
                // This requires to ignore the current activity and create a new one
                // using the context extracted using the format TextFormat supports.
                // TODO: actually implement code doing the above.

                /*
                 * var ctx = this.options.TextFormat.Extract<HttpRequest>(
                 *  request,
                 *  (r, name) => requestValues.Headers.GetValues(name));
                 *
                 * this.Tracer.StartActiveSpan(path, ctx, SpanKind.Server, out span);
                 */
            }

            if (activity.IsAllDataRequested)
            {
                if (request.Url.Port == 80 || request.Url.Port == 443)
                {
                    activity.AddTag(SpanAttributeConstants.HttpHostKey, request.Url.Host);
                }
                else
                {
                    activity.AddTag(SpanAttributeConstants.HttpHostKey, request.Url.Host + ":" + request.Url.Port);
                }

                activity.AddTag(SpanAttributeConstants.HttpMethodKey, request.HttpMethod);
                activity.AddTag(SpanAttributeConstants.HttpPathKey, path);
                activity.AddTag(SpanAttributeConstants.HttpUserAgentKey, request.UserAgent);
                activity.AddTag(SpanAttributeConstants.HttpUrlKey, request.Url.ToString());
            }
        }
        public override void OnCustom(string name, Activity activity, object payload)
        {
            switch (name)
            {
            case SqlDataBeforeExecuteCommand:
            case SqlMicrosoftBeforeExecuteCommand:
            {
                var command = this.commandFetcher.Fetch(payload);

                if (command == null)
                {
                    InstrumentationEventSource.Log.NullPayload($"{nameof(SqlClientDiagnosticListener)}-{name}");
                    return;
                }

                var connection = this.connectionFetcher.Fetch(command);
                var database   = this.databaseFetcher.Fetch(connection);

                // TODO: Avoid the reflection hack once .NET ships new Activity with Kind settable.
                activity.GetType().GetProperty("Kind").SetValue(activity, ActivityKind.Client);
                activity.DisplayName = (string)database;

                var samplingParameters = new ActivitySamplingParameters(
                    activity.Context,
                    activity.TraceId,
                    activity.DisplayName,
                    activity.Kind,
                    activity.Tags,
                    activity.Links);

                // TODO: Find a way to avoid Instrumentation being tied to Sampler
                var samplingDecision = this.sampler.ShouldSample(samplingParameters);
                activity.IsAllDataRequested = samplingDecision.IsSampled;
                if (samplingDecision.IsSampled)
                {
                    activity.ActivityTraceFlags |= ActivityTraceFlags.Recorded;
                }

                if (activity.IsAllDataRequested)
                {
                    var dataSource  = this.dataSourceFetcher.Fetch(connection);
                    var commandText = this.commandTextFetcher.Fetch(command);

                    activity.AddTag(SpanAttributeConstants.ComponentKey, "sql");
                    activity.AddTag(SpanAttributeConstants.DatabaseTypeKey, "sql");
                    activity.AddTag(SpanAttributeConstants.PeerServiceKey, (string)dataSource);
                    activity.AddTag(SpanAttributeConstants.DatabaseInstanceKey, (string)database);

                    if (this.commandTypeFetcher.Fetch(command) is CommandType commandType)
                    {
                        activity.AddTag(DatabaseStatementTypeSpanAttributeKey, commandType.ToString());

                        switch (commandType)
                        {
                        case CommandType.StoredProcedure:
                            if (this.options.CaptureStoredProcedureCommandName)
                            {
                                activity.AddTag(SpanAttributeConstants.DatabaseStatementKey, (string)commandText);
                            }

                            break;

                        case CommandType.Text:
                            if (this.options.CaptureTextCommandContent)
                            {
                                activity.AddTag(SpanAttributeConstants.DatabaseStatementKey, (string)commandText);
                            }

                            break;
                        }
                    }
                }
            }

            break;

            case SqlDataAfterExecuteCommand:
            case SqlMicrosoftAfterExecuteCommand:
            {
            }

            break;

            case SqlDataWriteCommandError:
            case SqlMicrosoftWriteCommandError:
            {
                if (activity.IsAllDataRequested)
                {
                    if (this.exceptionFetcher.Fetch(payload) is Exception exception)
                    {
                        Status status = Status.Unknown;
                        activity.AddTag(SpanAttributeConstants.StatusCodeKey, SpanHelper.GetCachedCanonicalCodeString(status.CanonicalCode));
                        activity.AddTag(SpanAttributeConstants.StatusDescriptionKey, exception.Message);
                    }
                    else
                    {
                        InstrumentationEventSource.Log.NullPayload($"{nameof(SqlClientDiagnosticListener)}-{name}");
                    }
                }
            }

            break;
            }
        }