internal double?GetIntegrationAnalyticsSampleRate(IntegrationId integration, bool enabledWithGlobalSetting)
        {
            var integrationSettings = Integrations[integration];
            var analyticsEnabled    = integrationSettings.AnalyticsEnabled ?? (enabledWithGlobalSetting && AnalyticsEnabled);

            return(analyticsEnabled ? integrationSettings.AnalyticsSampleRate : (double?)null);
        }
示例#2
0
        internal static void FlushSpans(IntegrationId integrationInfo)
        {
            if (!Tracer.Instance.Settings.IsIntegrationEnabled(integrationInfo))
            {
                return;
            }

            Ci.CIVisibility.FlushSpans();
        }
示例#3
0
        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;
 }
示例#6
0
        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);
        }
示例#8
0
            // 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);
        }
示例#10
0
        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));
 }
示例#14
0
 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];
示例#16
0
        /// <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);
        }
示例#17
0
        /// <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];