internal double?GetIntegrationAnalyticsSampleRate(IntegrationId integration, bool enabledWithGlobalSetting) { var integrationSettings = Integrations[integration]; var analyticsEnabled = integrationSettings.AnalyticsEnabled ?? (enabledWithGlobalSetting && AnalyticsEnabled); return(analyticsEnabled ? integrationSettings.AnalyticsSampleRate : (double?)null); }
internal static void FlushSpans(IntegrationId integrationInfo) { if (!Tracer.Instance.Settings.IsIntegrationEnabled(integrationInfo)) { return; } Ci.CIVisibility.FlushSpans(); }
public void SetAnalyticsSampleRate(IntegrationId integration, ImmutableTracerSettings settings, bool enabledWithGlobalSetting) { if (settings != null) { #pragma warning disable 618 // App analytics is deprecated, but still used AnalyticsSampleRate = settings.GetIntegrationAnalyticsSampleRate(integration, enabledWithGlobalSetting); #pragma warning restore 618 } }
internal bool IsIntegrationEnabled(IntegrationId integration, bool defaultValue = true) { if (TraceEnabled && !_domainMetadata.ShouldAvoidAppDomain()) { return(Integrations[integration].Enabled ?? defaultValue); } return(false); }
public AspNetCoreHttpRequestHandler( IDatadogLogger log, string requestInOperationName, IntegrationId integrationInfo) { _log = log; _integrationId = integrationInfo; _requestInOperationName = requestInOperationName; }
internal static bool TryGetIntegrationId(string integrationName, out IntegrationId integration) { if (Ids.TryGetValue(integrationName, out var id)) { integration = (IntegrationId)id; return(true); } integration = default; return(false); }
internal static Scope CreateScope(Tracer tracer, IntegrationId integrationId, string host, string port, string rawCommand) { if (!Tracer.Instance.Settings.IsIntegrationEnabled(integrationId)) { // integration disabled, don't create a scope, skip this trace return(null); } var parent = tracer.ActiveScope?.Span; if (parent != null && parent.Type == SpanTypes.Redis && parent.GetTag(Tags.InstrumentationName) != null) { return(null); } string serviceName = tracer.Settings.GetServiceName(tracer, ServiceName); Scope scope = null; try { var tags = new RedisTags(); scope = tracer.StartActiveInternal(OperationName, serviceName: serviceName, tags: tags); int separatorIndex = rawCommand.IndexOf(' '); string command; if (separatorIndex >= 0) { command = rawCommand.Substring(0, separatorIndex); } else { command = rawCommand; } var span = scope.Span; span.Type = SpanTypes.Redis; span.ResourceName = command; tags.RawCommand = rawCommand; tags.Host = host; tags.Port = port; tags.SetAnalyticsSampleRate(integrationId, tracer.Settings, enabledWithGlobalSetting: false); tracer.TracerManager.Telemetry.IntegrationGeneratedSpan(integrationId); } catch (Exception ex) { Log.Error(ex, "Error creating or populating scope."); } return(scope); }
// ReSharper restore StaticMemberInGenericType static Cache() { var commandType = typeof(TCommand); if (TryGetIntegrationDetails(commandType.FullName, out var integrationId, out var dbTypeName)) { // cache values for this TCommand type CommandType = commandType; DbTypeName = dbTypeName; OperationName = $"{DbTypeName}.query"; IntegrationId = integrationId.Value; } }
public static Scope CreateScope <T>(Tracer tracer, IntegrationId integrationId, RequestPipelineStruct pipeline, T requestData) where T : IRequestData { if (!tracer.Settings.IsIntegrationEnabled(integrationId)) { // integration disabled, don't create a scope, skip this trace return(null); } var pathAndQuery = requestData.Path; string method = requestData.Method; var url = requestData.Uri?.ToString(); var scope = CreateScope(tracer, integrationId, pathAndQuery, method, pipeline.RequestParameters, out var tags); tags.Url = url; return(scope); }
private static Scope CreateDbCommandScope(Tracer tracer, IDbCommand command, IntegrationId integrationId, string dbType, string operationName, string serviceName, ref DbCommandCache.TagsCacheItem tagsFromConnectionString) { if (!tracer.Settings.IsIntegrationEnabled(integrationId) || !tracer.Settings.IsIntegrationEnabled(IntegrationId.AdoNet)) { // integration disabled, don't create a scope, skip this span return(null); } Scope scope = null; try { Span parent = tracer.InternalActiveScope?.Span; if (IsDbAlreadyInstrumented(parent, dbType, command.CommandText)) { // we are already instrumenting this, // don't instrument nested methods that belong to the same stacktrace // e.g. ExecuteReader() -> ExecuteReader(commandBehavior) return(null); } var tags = new SqlTags { DbType = dbType, InstrumentationName = IntegrationRegistry.GetName(integrationId) }; tags.SetAnalyticsSampleRate(integrationId, tracer.Settings, enabledWithGlobalSetting: false); scope = tracer.StartActiveInternal(operationName, tags: tags, serviceName: serviceName); scope.Span.AddTagsFromDbCommand(command); tracer.TracerManager.Telemetry.IntegrationGeneratedSpan(integrationId); } catch (Exception ex) { Log.Error(ex, "Error creating or populating scope."); } return(scope); }
private static Scope CreateDbCommandScope(Tracer tracer, IDbCommand command, IntegrationId integrationId, string dbType, string operationName, string serviceName, ref DbCommandCache.TagsCacheItem tagsFromConnectionString) { if (!tracer.Settings.IsIntegrationEnabled(integrationId) || !tracer.Settings.IsIntegrationEnabled(IntegrationId.AdoNet)) { // integration disabled, don't create a scope, skip this span return(null); } Scope scope = null; try { Span parent = tracer.InternalActiveScope?.Span; if (parent is { Type : SpanTypes.Sql } && parent.GetTag(Tags.DbType) == dbType && parent.ResourceName == command.CommandText) { // we are already instrumenting this, // don't instrument nested methods that belong to the same stacktrace // e.g. ExecuteReader() -> ExecuteReader(commandBehavior) return(null); } var tags = new SqlTags { DbType = dbType, InstrumentationName = IntegrationRegistry.GetName(integrationId), DbName = tagsFromConnectionString.DbName, DbUser = tagsFromConnectionString.DbUser, OutHost = tagsFromConnectionString.OutHost, }; tags.SetAnalyticsSampleRate(integrationId, tracer.Settings, enabledWithGlobalSetting: false); scope = tracer.StartActiveInternal(operationName, tags: tags, serviceName: serviceName); scope.Span.ResourceName = command.CommandText; scope.Span.Type = SpanTypes.Sql; tracer.TracerManager.Telemetry.IntegrationGeneratedSpan(integrationId); }
public static Scope CreateScope(Tracer tracer, IntegrationId integrationId, string path, string method, object requestParameters, out ElasticsearchTags tags) { if (!tracer.Settings.IsIntegrationEnabled(integrationId)) { // integration disabled, don't create a scope, skip this trace tags = null; return(null); } string requestName = requestParameters?.GetType().Name.Replace("RequestParameters", string.Empty); string serviceName = tracer.Settings.GetServiceName(tracer, ServiceName); Scope scope = null; tags = new ElasticsearchTags(); try { var operationName = requestName ?? OperationName; scope = tracer.StartActiveInternal(operationName, serviceName: serviceName, tags: tags); var span = scope.Span; span.LogicScope = OperationName; span.ResourceName = requestName ?? path ?? string.Empty; span.Type = SpanType; tags.Action = requestName; tags.Method = method; tags.SetAnalyticsSampleRate(integrationId, tracer.Settings, enabledWithGlobalSetting: false); tracer.TracerManager.Telemetry.IntegrationGeneratedSpan(integrationId); } catch (Exception ex) { Log.Error(ex, "Error creating or populating scope."); } return(scope); }
public static TelemetryData AssertIntegrationDisabled(this MockTelemetryAgent <TelemetryData> telemetry, IntegrationId integrationId) { return(telemetry.AssertIntegration(integrationId, enabled: false, autoEnabled: true)); }
internal static string GetName(IntegrationId integration) => Names[(int)integration];
/// <summary> /// Should be called when an integration is first executed (not necessarily successfully) /// </summary> public void IntegrationRunning(IntegrationId integrationId) { ref var value = ref _integrationsById[(int)integrationId];
/// <summary> /// Creates a scope for outbound http requests and populates some common details. /// </summary> /// <param name="tracer">The tracer instance to use to create the new scope.</param> /// <param name="httpMethod">The HTTP method used by the request.</param> /// <param name="requestUri">The URI requested by the request.</param> /// <param name="integrationId">The id of the integration creating this scope.</param> /// <param name="tags">The tags associated to the scope</param> /// <param name="traceId">The trace id - this id will be ignored if there's already an active trace</param> /// <param name="spanId">The span id</param> /// <param name="startTime">The start time that should be applied to the span</param> /// <param name="addToTraceContext">Set to false if the span is meant to be discarded. In that case, the span won't be added to the TraceContext.</param> /// <returns>A new pre-populated scope.</returns> internal static Span CreateInactiveOutboundHttpSpan(Tracer tracer, string httpMethod, Uri requestUri, IntegrationId integrationId, out HttpTags tags, ulong?traceId, ulong?spanId, DateTimeOffset?startTime, bool addToTraceContext) { tags = null; if (!tracer.Settings.IsIntegrationEnabled(integrationId) || PlatformHelpers.PlatformStrategy.ShouldSkipClientSpan(tracer.InternalActiveScope) || HttpBypassHelper.UriContainsAnyOf(requestUri, tracer.Settings.HttpClientExcludedUrlSubstrings)) { // integration disabled, don't create a scope, skip this trace return(null); } Span span = null; try { if (GetActiveHttpScope(tracer) != null) { // we are already instrumenting this, // don't instrument nested methods that belong to the same stacktrace // e.g. HttpClientHandler.SendAsync() -> SocketsHttpHandler.SendAsync() return(null); } string resourceUrl = requestUri != null?UriHelpers.CleanUri(requestUri, removeScheme : true, tryRemoveIds : true) : null; string httpUrl = requestUri != null?UriHelpers.CleanUri(requestUri, removeScheme : false, tryRemoveIds : false) : null; tags = new HttpTags(); string serviceName = tracer.Settings.GetServiceName(tracer, ServiceName); span = tracer.StartSpan(OperationName, tags, serviceName: serviceName, traceId: traceId, spanId: spanId, startTime: startTime, addToTraceContext: addToTraceContext); span.Type = SpanTypes.Http; span.ResourceName = $"{httpMethod} {resourceUrl}"; tags.HttpMethod = httpMethod?.ToUpperInvariant(); tags.HttpUrl = httpUrl; tags.InstrumentationName = IntegrationRegistry.GetName(integrationId); tags.SetAnalyticsSampleRate(integrationId, tracer.Settings, enabledWithGlobalSetting: false); if (!addToTraceContext && span.Context.TraceContext.SamplingPriority == null) { // If we don't add the span to the trace context, then we need to manually call the sampler span.Context.TraceContext.SetSamplingPriority(tracer.TracerManager.Sampler?.GetSamplingPriority(span)); } } catch (Exception ex) { Log.Error(ex, "Error creating or populating span."); } // always returns the span, even if it's null because we couldn't create it, // or we couldn't populate it completely (some tags is better than no tags) return(span); }
/// <summary> /// Creates a scope for outbound http requests and populates some common details. /// </summary> /// <param name="tracer">The tracer instance to use to create the new scope.</param> /// <param name="httpMethod">The HTTP method used by the request.</param> /// <param name="requestUri">The URI requested by the request.</param> /// <param name="integrationId">The id of the integration creating this scope.</param> /// <param name="tags">The tags associated to the scope</param> /// <param name="traceId">The trace id - this id will be ignored if there's already an active trace</param> /// <param name="spanId">The span id</param> /// <param name="startTime">The start time that should be applied to the span</param> /// <returns>A new pre-populated scope.</returns> internal static Scope CreateOutboundHttpScope(Tracer tracer, string httpMethod, Uri requestUri, IntegrationId integrationId, out HttpTags tags, ulong?traceId = null, ulong?spanId = null, DateTimeOffset?startTime = null) { var span = CreateInactiveOutboundHttpSpan(tracer, httpMethod, requestUri, integrationId, out tags, traceId, spanId, startTime, addToTraceContext: true); if (span != null) { return(tracer.ActivateSpan(span)); } return(null); }
public bool IsIntegrationEnabled(IntegrationId integrationId) { return(IsEnabled && _enabledIntegrations[(int)integrationId]); }
public static TelemetryData AssertIntegration(this MockTelemetryAgent <TelemetryData> telemetry, IntegrationId integrationId, bool enabled, bool?autoEnabled) { telemetry.WaitForLatestTelemetry(x => x.RequestType == TelemetryRequestTypes.AppClosing); var allData = telemetry.Telemetry.ToArray(); allData.Should().ContainSingle(x => x.RequestType == TelemetryRequestTypes.AppClosing); var(latestIntegrationsData, integrationsPayload) = allData .Where( x => x.RequestType == TelemetryRequestTypes.AppStarted || x.RequestType == TelemetryRequestTypes.AppIntegrationsChanged) .OrderByDescending(x => x.SeqId) .Select( data => { var integrations = data.Payload is AppStartedPayload payload ? payload.Integrations : ((AppIntegrationsChangedPayload)data.Payload).Integrations; return(data, integrations); }) .FirstOrDefault(x => x.integrations is not null); latestIntegrationsData.Should().NotBeNull(); integrationsPayload.Should().NotBeNull(); var integration = integrationsPayload .FirstOrDefault(x => x.Name == integrationId.ToString()); integration.Should().NotBeNull(); integration.Enabled.Should().Be(enabled, $"{integration.Name} should only be enabled if we generate a span"); if (autoEnabled.HasValue) { integration.AutoEnabled.Should().Be(autoEnabled.Value, $"{integration.Name} should only be auto-enabled if available"); } integration.Error.Should().BeNullOrEmpty(); return(latestIntegrationsData); }
public static CallTargetState OnMethodBegin <TTarget, TRequest>(TTarget instance, TRequest requestMessage, CancellationToken cancellationToken, IntegrationId integrationId, IntegrationId?implementationIntegrationId) where TRequest : IHttpRequestMessage { var tracer = Tracer.Instance; if (requestMessage.Instance is not null && IsTracingEnabled(requestMessage.Headers, implementationIntegrationId)) { Scope scope = ScopeFactory.CreateOutboundHttpScope(tracer, requestMessage.Method.Method, requestMessage.RequestUri, integrationId, out HttpTags tags); if (scope != null) { tags.HttpClientHandlerType = instance.GetType().FullName; // add distributed tracing headers to the HTTP request SpanContextPropagator.Instance.Inject(scope.Span.Context, new HttpHeadersCollection(requestMessage.Headers)); tracer.TracerManager.Telemetry.IntegrationGeneratedSpan(implementationIntegrationId ?? integrationId); return(new CallTargetState(scope)); } } return(CallTargetState.GetDefault()); }
internal ImmutableIntegrationSettings this[IntegrationId integration] => Settings[(int)integration];