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; } }