public async ValueTask <int> TrackAsync(IEnumerable <TelemetryItem> telemetryItems, bool async, CancellationToken cancellationToken)
        {
            // Prevent Azure Monitor's HTTP operations from being instrumented.
            using var scope = SuppressInstrumentationScope.Begin();

            if (cancellationToken.IsCancellationRequested)
            {
                return(0);
            }

            Azure.Response <TrackResponse> response = null;

            try
            {
                if (async)
                {
                    response = await this.applicationInsightsRestClient.InternalTrackAsync(telemetryItems, cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    response = this.applicationInsightsRestClient.InternalTrackAsync(telemetryItems, cancellationToken).Result;
                }
            }
            catch (Exception ex)
            {
                // TODO: Log the exception to new event source. If we get a common logger we could just log exception to it.
                AzureMonitorTraceExporterEventSource.Log.FailedExport(ex);
            }

            return(response == null ? 0 : response.Value.ItemsAccepted.GetValueOrDefault());
        }
示例#2
0
        public void TracerSdkSetsActivityDataRequestedToFalseWhenSuppressInstrumentationIsTrueForLegacyActivity()
        {
            using TestActivityProcessor testActivityProcessor = new TestActivityProcessor();

            bool startCalled = false;
            bool endCalled   = false;

            testActivityProcessor.StartAction =
                (a) =>
            {
                startCalled = true;
            };

            testActivityProcessor.EndAction =
                (a) =>
            {
                endCalled = true;
            };

            using var openTelemetry = Sdk.CreateTracerProviderBuilder()
                                      .AddLegacySource("random")
                                      .AddProcessor(testActivityProcessor)
                                      .SetSampler(new AlwaysOnSampler())
                                      .Build();

            using (SuppressInstrumentationScope.Begin(true))
            {
                using var activity = new Activity("random").Start();
                Assert.False(activity.IsAllDataRequested);
            }

            Assert.False(startCalled);
            Assert.False(endCalled);
        }
        public override void OnStartActivity(Activity activity, object payload)
        {
            var uri = this.uriFetcher.Fetch(payload);

            if (uri == null)
            {
                ElasticsearchInstrumentationEventSource.Log.NullPayload(nameof(ElasticsearchRequestPipelineDiagnosticListener), nameof(this.OnStartActivity));
                return;
            }

            var method = this.methodFetcher.Fetch(payload);

            activity.DisplayName = this.GetDisplayName(activity, method);

            this.activitySource.Start(activity, ActivityKind.Client);

            if (this.options.SuppressDownstreamInstrumentation)
            {
                SuppressInstrumentationScope.Enter();
            }

            if (!activity.IsAllDataRequested)
            {
                return;
            }

            var elasticIndex = this.GetElasticIndex(uri);

            activity.DisplayName = this.GetDisplayName(activity, method, elasticIndex);
            activity.SetTag(Constants.AttributeDbSystem, "elasticsearch");

            if (elasticIndex != null)
            {
                activity.SetTag(Constants.AttributeDbName, elasticIndex);
            }

            var uriHostNameType = Uri.CheckHostName(uri.Host);

            if (uriHostNameType == UriHostNameType.IPv4 || uriHostNameType == UriHostNameType.IPv6)
            {
                activity.SetTag(Constants.AttributeNetPeerIp, uri.Host);
            }
            else
            {
                activity.SetTag(Constants.AttributeNetPeerName, uri.Host);
            }

            if (uri.Port > 0)
            {
                activity.SetTag(Constants.AttributeNetPeerPort, uri.Port);
            }

            if (method != null)
            {
                activity.SetTag(Constants.AttributeDbMethod, method.ToString());
            }

            activity.SetTag(Constants.AttributeDbUrl, uri.OriginalString);
        }
示例#4
0
        private void Application_BeginRequest(object sender, EventArgs e)
        {
            var context = ((HttpApplication)sender).Context;

            if (context.Request.QueryString["suppress"] == "true")
            {
                this.suppressionScope = SuppressInstrumentationScope.Begin();
            }
        }
        public override void OnStartActivity(Activity activity, object payload)
        {
            if (!this.startRequestFetcher.TryFetch(payload, out HttpRequestMessage request) || request == null)
            {
                GrpcInstrumentationEventSource.Log.NullPayload(nameof(GrpcClientDiagnosticListener), nameof(this.OnStartActivity));
                return;
            }

            if (this.options.SuppressDownstreamInstrumentation)
            {
                SuppressInstrumentationScope.Enter();
            }

            var grpcMethod = GrpcTagHelper.GetGrpcMethodFromActivity(activity);

            activity.DisplayName = grpcMethod?.Trim('/');

            this.activitySource.Start(activity, ActivityKind.Client);

            if (activity.IsAllDataRequested)
            {
                try
                {
                    this.options.Enrich?.Invoke(activity, "OnStartActivity", request);
                }
                catch (Exception ex)
                {
                    GrpcInstrumentationEventSource.Log.EnrichmentException(ex);
                }

                activity.SetTag(SemanticConventions.AttributeRpcSystem, GrpcTagHelper.RpcSystemGrpc);

                if (GrpcTagHelper.TryParseRpcServiceAndRpcMethod(grpcMethod, out var rpcService, out var rpcMethod))
                {
                    activity.SetTag(SemanticConventions.AttributeRpcService, rpcService);
                    activity.SetTag(SemanticConventions.AttributeRpcMethod, rpcMethod);

                    // Remove the grpc.method tag added by the gRPC .NET library
                    activity.SetTag(GrpcTagHelper.GrpcMethodTagName, null);
                }

                var uriHostNameType = Uri.CheckHostName(request.RequestUri.Host);
                if (uriHostNameType == UriHostNameType.IPv4 || uriHostNameType == UriHostNameType.IPv6)
                {
                    activity.SetTag(SemanticConventions.AttributeNetPeerIp, request.RequestUri.Host);
                }
                else
                {
                    activity.SetTag(SemanticConventions.AttributeNetPeerName, request.RequestUri.Host);
                }

                activity.SetTag(SemanticConventions.AttributeNetPeerPort, request.RequestUri.Port);
            }
        }
        public void DecrementIfTriggeredOnlyWorksInReferenceCountingMode()
        {
            // Instrumentation is not suppressed, DecrementIfTriggered is a no op
            Assert.False(OpenTelemetrySdk.SuppressInstrumentation);
            SuppressInstrumentationScope.DecrementIfTriggered();
            Assert.False(OpenTelemetrySdk.SuppressInstrumentation);

            // Instrumentation is suppressed in reference counting mode, DecrementIfTriggered should work
            SuppressInstrumentationScope.Enter();
            Assert.True(OpenTelemetrySdk.SuppressInstrumentation);
            SuppressInstrumentationScope.DecrementIfTriggered();
            Assert.False(OpenTelemetrySdk.SuppressInstrumentation); // Instrumentation is not suppressed anymore
        }
        public async void SuppressInstrumentationScopeEnterIsLocalToAsyncFlow()
        {
            Assert.False(OpenTelemetrySdk.SuppressInstrumentation);

            // SuppressInstrumentationScope.Enter called inside the task is only applicable to this async flow
            await Task.Factory.StartNew(() =>
            {
                Assert.False(OpenTelemetrySdk.SuppressInstrumentation);
                SuppressInstrumentationScope.Enter();
                Assert.True(OpenTelemetrySdk.SuppressInstrumentation);
            });

            Assert.False(OpenTelemetrySdk.SuppressInstrumentation); // Changes made by SuppressInstrumentationScope.Enter in the task above are not reflected here as it's not part of the same async flow
        }
        public void SuppressInstrumentationBeginTest(bool?shouldBegin)
        {
            Assert.False(OpenTelemetrySdk.SuppressInstrumentation);

            using var scope = shouldBegin.HasValue ? SuppressInstrumentationScope.Begin(shouldBegin.Value) : SuppressInstrumentationScope.Begin();
            if (shouldBegin.HasValue)
            {
                Assert.Equal(shouldBegin.Value, OpenTelemetrySdk.SuppressInstrumentation);
            }
            else
            {
                Assert.True(OpenTelemetrySdk.SuppressInstrumentation); // Default behavior is to pass true and suppress the instrumentation
            }
        }
        public void OnNext(KeyValuePair <string, object> value)
        {
            if (!this.handler.SupportsNullActivity && Activity.Current == null)
            {
                if (!Sdk.SuppressInstrumentation)
                {
                    InstrumentationEventSource.Log.NullActivity(value.Key);
                }

                return;
            }

            try
            {
                if (value.Key.EndsWith("Start", StringComparison.Ordinal))
                {
                    if (SuppressInstrumentationScope.IncrementIfTriggered() == 0)
                    {
                        this.handler.OnStartActivity(Activity.Current, value.Value);
                    }
                }
                else if (value.Key.EndsWith("Stop", StringComparison.Ordinal))
                {
                    if (SuppressInstrumentationScope.DecrementIfTriggered() == 0)
                    {
                        this.handler.OnStopActivity(Activity.Current, value.Value);
                    }
                }
                else if (value.Key.EndsWith("Exception", StringComparison.Ordinal))
                {
                    if (!Sdk.SuppressInstrumentation)
                    {
                        this.handler.OnException(Activity.Current, value.Value);
                    }
                }
                else
                {
                    if (!Sdk.SuppressInstrumentation)
                    {
                        this.handler.OnCustom(value.Key, Activity.Current, value.Value);
                    }
                }
            }
            catch (Exception ex)
            {
                InstrumentationEventSource.Log.UnknownErrorProcessingEvent(this.handler?.SourceName, value.Key, ex);
            }
        }
示例#10
0
    public override Task <ExportResult> ExportAsync(
        IEnumerable <Activity> batch, CancellationToken cancellationToken)
    {
        // Exporter code which can generate further
        // telemetry should do so inside SuppressInstrumentation
        // scope. This suppresses telemetry from
        // exporter's own code to avoid live-loop situation.
        using var scope = SuppressInstrumentationScope.Begin();

        foreach (var activity in batch)
        {
            Console.WriteLine($"{activity.DisplayName}");
        }

        return(Task.FromResult(ExportResult.Success));
    }
        public void IncrementIfTriggeredOnlyWorksInReferenceCountingMode()
        {
            // Instrumentation is not suppressed, IncrementIfTriggered is a no op
            Assert.False(OpenTelemetrySdk.SuppressInstrumentation);
            SuppressInstrumentationScope.IncrementIfTriggered();
            Assert.False(OpenTelemetrySdk.SuppressInstrumentation);

            // Instrumentation is suppressed in reference counting mode, IncrementIfTriggered should work
            SuppressInstrumentationScope.Enter();
            SuppressInstrumentationScope.IncrementIfTriggered();
            Assert.True(OpenTelemetrySdk.SuppressInstrumentation);
            SuppressInstrumentationScope.DecrementIfTriggered();
            Assert.True(OpenTelemetrySdk.SuppressInstrumentation);  // Instrumentation is still suppressed as IncrementIfTriggered incremented the slot count after Enter, need to decrement the slot count again to enable instrumentation
            SuppressInstrumentationScope.DecrementIfTriggered();
            Assert.False(OpenTelemetrySdk.SuppressInstrumentation); // Instrumentation is not suppressed anymore
        }
示例#12
0
        public void TracerSdkSetsActivitySamplingResultToNoneWhenSuppressInstrumentationIsTrue()
        {
            using var scope = SuppressInstrumentationScope.Begin();

            var testSampler = new TestSampler();

            using var activitySource = new ActivitySource(ActivitySourceName);
            using var sdk            = Sdk.CreateTracerProviderBuilder()
                                       .AddSource(ActivitySourceName)
                                       .SetSampler(testSampler)
                                       .Build();

            using (var activity = activitySource.StartActivity("root"))
            {
                Assert.Null(activity);
            }
        }
示例#13
0
        public void ListenerHandlerIsNotInvokedWhenSuppressInstrumentationTrue(bool suppressInstrumentation)
        {
            using var scope = SuppressInstrumentationScope.Begin(suppressInstrumentation);

            var activity = new Activity("Main");

            this.diagnosticSource.StartActivity(activity, null);
            this.diagnosticSource.StopActivity(activity, null);

            if (suppressInstrumentation)
            {
                Assert.Equal(0, this.testListenerHandler.OnStartInvokedCount);
                Assert.Equal(0, this.testListenerHandler.OnStopInvokedCount);
            }
            else
            {
                Assert.Equal(1, this.testListenerHandler.OnStartInvokedCount);
                Assert.Equal(1, this.testListenerHandler.OnStopInvokedCount);
            }
        }
        public int Send(byte[] buffer, int offset, int count)
        {
            // Prevent Jaeger's HTTP operations from being instrumented.
            using var scope = SuppressInstrumentationScope.Begin();

            using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "/api/traces");

            request.Content = new ByteArrayContent(buffer, offset, count)
            {
                Headers = { ContentType = ContentTypeHeader },
            };

#if NET5_0_OR_GREATER
            using HttpResponseMessage response = this.httpClient.Send(request);
#else
            using HttpResponseMessage response = this.httpClient.SendAsync(request).GetAwaiter().GetResult();
#endif
            response.EnsureSuccessStatusCode();

            return(count);
        }
示例#15
0
        public async Task ShouldMapMassTransitTagsWhenIntrumentationIsSuppressed()
        {
            var activityProcessor = new Mock <BaseProcessor <Activity> >();

            using (Sdk.CreateTracerProviderBuilder()
                   .AddProcessor(activityProcessor.Object)
                   .AddMassTransitInstrumentation()
                   .Build())
            {
                var harness         = new InMemoryTestHarness();
                var consumerHarness = harness.Consumer <TestConsumer>();
                var handlerHarness  = harness.Handler <TestMessage>();
                using var scope = SuppressInstrumentationScope.Begin();
                await harness.Start();

                try
                {
                    await harness.InputQueueSendEndpoint.Send <TestMessage>(new { Text = "Hello, world!" });

                    Assert.True(await harness.Consumed.SelectAsync <TestMessage>().Any());
                    Assert.True(await consumerHarness.Consumed.SelectAsync <TestMessage>().Any());
                    Assert.True(await handlerHarness.Consumed.SelectAsync().Any());
                }
                finally
                {
                    await harness.Stop();
                }

                var expectedMessageContext = harness.Sent.Select <TestMessage>().FirstOrDefault()?.Context;
                Assert.NotNull(expectedMessageContext);
            }

            // Since instrumentation is suppressed, activiy is not emitted
            Assert.Equal(3, activityProcessor.Invocations.Count); // SetParentProvider + OnShutdown + Dispose

            // Processor.OnStart and Processor.OnEnd are not called
            Assert.DoesNotContain(activityProcessor.Invocations, invo => invo.Method.Name == nameof(activityProcessor.Object.OnStart));
            Assert.DoesNotContain(activityProcessor.Invocations, invo => invo.Method.Name == nameof(activityProcessor.Object.OnEnd));
        }
        public static void UsingSuppressInstrumentation()
        {
            Assert.False(Sdk.SuppressInstrumentation);

            using (var scope = SuppressInstrumentationScope.Begin())
            {
                Assert.True(Sdk.SuppressInstrumentation);

                using (var innerScope = SuppressInstrumentationScope.Begin())
                {
                    innerScope.Dispose();

                    Assert.True(Sdk.SuppressInstrumentation);

                    scope.Dispose();
                }

                Assert.False(Sdk.SuppressInstrumentation);
            }

            Assert.False(Sdk.SuppressInstrumentation);
        }
示例#17
0
        private Activity ProcessBeginRequest(IExecutionContext executionContext)
        {
            Activity activity = null;

            var requestContext = executionContext.RequestContext;
            var service        = this.GetAWSServiceName(requestContext);
            var operation      = this.GetAWSOperationName(requestContext);

            activity = AWSSDKActivitySource.StartActivity(service + "." + operation, ActivityKind.Client);

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

            if (this.options.SuppressDownstreamInstrumentation)
            {
                SuppressInstrumentationScope.Enter();
            }

            if (activity.IsAllDataRequested)
            {
                activity.SetTag(AWSSemanticConventions.AttributeAWSServiceName, service);
                activity.SetTag(AWSSemanticConventions.AttributeAWSOperationName, operation);
                var client = executionContext.RequestContext.ClientConfig;
                if (client != null)
                {
                    var region = client.RegionEndpoint?.SystemName;
                    activity.SetTag(AWSSemanticConventions.AttributeAWSRegion, region ?? AWSSDKUtils.DetermineRegion(client.ServiceURL));
                }

                this.AddRequestSpecificInformation(activity, requestContext, service);
            }

            AwsPropagator.Inject(new PropagationContext(activity.Context, Baggage.Current), requestContext.Request.Headers, Setter);

            return(activity);
        }
示例#18
0
 private IDisposable SuppressDownstreamInstrumentation()
 {
     return(WcfInstrumentationActivitySource.Options?.SuppressDownstreamInstrumentation ?? false
         ? SuppressInstrumentationScope.Begin()
         : null);
 }
示例#19
0
        public override void OnStartActivity(Activity activity, object payload)
        {
            // By this time, samplers have already run and
            // activity.IsAllDataRequested populated accordingly.

            if (Sdk.SuppressInstrumentation)
            {
                return;
            }

            if (activity.IsAllDataRequested)
            {
                var uri = this.uriFetcher.Fetch(payload);

                if (uri == null)
                {
                    ElasticsearchInstrumentationEventSource.Log.NullPayload(nameof(ElasticsearchRequestPipelineDiagnosticListener), nameof(this.OnStartActivity));
                    return;
                }

                ActivityInstrumentationHelper.SetActivitySourceProperty(activity, ActivitySource);
                ActivityInstrumentationHelper.SetKindProperty(activity, ActivityKind.Client);

                var method = this.methodFetcher.Fetch(payload);

                if (this.options.SuppressDownstreamInstrumentation)
                {
                    SuppressInstrumentationScope.Enter();
                }

                var elasticIndex = this.GetElasticIndex(uri);
                activity.DisplayName = this.GetDisplayName(activity, method, elasticIndex);
                activity.SetTag(SemanticConventions.AttributeDbSystem, DatabaseSystemName);

                if (elasticIndex != null)
                {
                    activity.SetTag(SemanticConventions.AttributeDbName, elasticIndex);
                }

                var uriHostNameType = Uri.CheckHostName(uri.Host);
                if (uriHostNameType == UriHostNameType.IPv4 || uriHostNameType == UriHostNameType.IPv6)
                {
                    activity.SetTag(SemanticConventions.AttributeNetPeerIp, uri.Host);
                }
                else
                {
                    activity.SetTag(SemanticConventions.AttributeNetPeerName, uri.Host);
                }

                if (uri.Port > 0)
                {
                    activity.SetTag(SemanticConventions.AttributeNetPeerPort, uri.Port);
                }

                if (method != null)
                {
                    activity.SetTag(AttributeDbMethod, method.ToString());
                }

                activity.SetTag(SemanticConventions.AttributeDbUrl, uri.OriginalString);

                try
                {
                    this.options.Enrich?.Invoke(activity, "OnStartActivity", payload);
                }
                catch (Exception ex)
                {
                    ElasticsearchInstrumentationEventSource.Log.EnrichmentException(ex);
                }
            }
        }
        internal TracerProviderSdk(
            Resource resource,
            IEnumerable <string> sources,
            IEnumerable <TracerProviderBuilderBase.InstrumentationFactory> instrumentationFactories,
            Sampler sampler,
            List <BaseProcessor <Activity> > processors,
            Dictionary <string, bool> legacyActivityOperationNames)
        {
            this.Resource = resource;
            this.sampler  = sampler;
            this.supportLegacyActivity = legacyActivityOperationNames.Count > 0;

            bool  legacyActivityWildcardMode      = false;
            Regex legacyActivityWildcardModeRegex = null;

            foreach (var legacyName in legacyActivityOperationNames)
            {
                if (legacyName.Key.Contains('*'))
                {
                    legacyActivityWildcardMode      = true;
                    legacyActivityWildcardModeRegex = GetWildcardRegex(legacyActivityOperationNames.Keys);
                    break;
                }
            }

            foreach (var processor in processors)
            {
                this.AddProcessor(processor);
            }

            if (instrumentationFactories.Any())
            {
                foreach (var instrumentationFactory in instrumentationFactories)
                {
                    this.instrumentations.Add(instrumentationFactory.Factory());
                }
            }

            var listener = new ActivityListener();

            if (this.supportLegacyActivity)
            {
                Func <Activity, bool> legacyActivityPredicate = null;
                if (legacyActivityWildcardMode)
                {
                    legacyActivityPredicate = activity => legacyActivityWildcardModeRegex.IsMatch(activity.OperationName);
                }
                else
                {
                    legacyActivityPredicate = activity => legacyActivityOperationNames.ContainsKey(activity.OperationName);
                }

                listener.ActivityStarted = activity =>
                {
                    OpenTelemetrySdkEventSource.Log.ActivityStarted(activity);

                    if (string.IsNullOrEmpty(activity.Source.Name))
                    {
                        if (legacyActivityPredicate(activity))
                        {
                            // Legacy activity matches the user configured list.
                            // Call sampler for the legacy activity
                            // unless suppressed.
                            if (!Sdk.SuppressInstrumentation)
                            {
                                this.getRequestedDataAction(activity);
                            }
                            else
                            {
                                activity.IsAllDataRequested = false;
                            }
                        }
                        else
                        {
                            // Legacy activity doesn't match the user configured list. No need to proceed further.
                            return;
                        }
                    }

                    if (!activity.IsAllDataRequested)
                    {
                        return;
                    }

                    if (SuppressInstrumentationScope.IncrementIfTriggered() == 0)
                    {
                        this.processor?.OnStart(activity);
                    }
                };

                listener.ActivityStopped = activity =>
                {
                    OpenTelemetrySdkEventSource.Log.ActivityStopped(activity);

                    if (string.IsNullOrEmpty(activity.Source.Name) && !legacyActivityPredicate(activity))
                    {
                        // Legacy activity doesn't match the user configured list. No need to proceed further.
                        return;
                    }

                    if (!activity.IsAllDataRequested)
                    {
                        return;
                    }

                    // Spec says IsRecording must be false once span ends.
                    // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#isrecording
                    // However, Activity has slightly different semantic
                    // than Span and we don't have strong reason to do this
                    // now, as Activity anyway allows read/write always.
                    // Intentionally commenting the following line.
                    // activity.IsAllDataRequested = false;

                    if (SuppressInstrumentationScope.DecrementIfTriggered() == 0)
                    {
                        this.processor?.OnEnd(activity);
                    }
                };
            }
            else
            {
                listener.ActivityStarted = activity =>
                {
                    OpenTelemetrySdkEventSource.Log.ActivityStarted(activity);

                    if (activity.IsAllDataRequested && SuppressInstrumentationScope.IncrementIfTriggered() == 0)
                    {
                        this.processor?.OnStart(activity);
                    }
                };

                listener.ActivityStopped = activity =>
                {
                    OpenTelemetrySdkEventSource.Log.ActivityStopped(activity);

                    if (!activity.IsAllDataRequested)
                    {
                        return;
                    }

                    // Spec says IsRecording must be false once span ends.
                    // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#isrecording
                    // However, Activity has slightly different semantic
                    // than Span and we don't have strong reason to do this
                    // now, as Activity anyway allows read/write always.
                    // Intentionally commenting the following line.
                    // activity.IsAllDataRequested = false;

                    if (SuppressInstrumentationScope.DecrementIfTriggered() == 0)
                    {
                        this.processor?.OnEnd(activity);
                    }
                };
            }

            if (sampler is AlwaysOnSampler)
            {
                listener.Sample = (ref ActivityCreationOptions <ActivityContext> options) =>
                                  !Sdk.SuppressInstrumentation ? ActivitySamplingResult.AllDataAndRecorded : ActivitySamplingResult.None;
                this.getRequestedDataAction = this.RunGetRequestedDataAlwaysOnSampler;
            }
            else if (sampler is AlwaysOffSampler)
            {
                listener.Sample = (ref ActivityCreationOptions <ActivityContext> options) =>
                                  !Sdk.SuppressInstrumentation ? PropagateOrIgnoreData(options.Parent.TraceId) : ActivitySamplingResult.None;
                this.getRequestedDataAction = this.RunGetRequestedDataAlwaysOffSampler;
            }
            else
            {
                // This delegate informs ActivitySource about sampling decision when the parent context is an ActivityContext.
                listener.Sample = (ref ActivityCreationOptions <ActivityContext> options) =>
                                  !Sdk.SuppressInstrumentation ? ComputeActivitySamplingResult(options, sampler) : ActivitySamplingResult.None;
                this.getRequestedDataAction = this.RunGetRequestedDataOtherSampler;
            }

            if (sources.Any())
            {
                // Sources can be null. This happens when user
                // is only interested in InstrumentationLibraries
                // which do not depend on ActivitySources.

                var wildcardMode = false;

                // Validation of source name is already done in builder.
                foreach (var name in sources)
                {
                    if (name.Contains('*'))
                    {
                        wildcardMode = true;
                        break;
                    }
                }

                if (wildcardMode)
                {
                    var regex = GetWildcardRegex(sources);

                    // Function which takes ActivitySource and returns true/false to indicate if it should be subscribed to
                    // or not.
                    listener.ShouldListenTo = (activitySource) =>
                                              this.supportLegacyActivity ?
                                              string.IsNullOrEmpty(activitySource.Name) || regex.IsMatch(activitySource.Name) :
                                              regex.IsMatch(activitySource.Name);
                }
                else
                {
                    var activitySources = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

                    foreach (var name in sources)
                    {
                        activitySources.Add(name);
                    }

                    if (this.supportLegacyActivity)
                    {
                        activitySources.Add(string.Empty);
                    }

                    // Function which takes ActivitySource and returns true/false to indicate if it should be subscribed to
                    // or not.
                    listener.ShouldListenTo = (activitySource) => activitySources.Contains(activitySource.Name);
                }
            }
            else
            {
                if (this.supportLegacyActivity)
                {
                    listener.ShouldListenTo = (activitySource) => string.IsNullOrEmpty(activitySource.Name);
                }
            }

            ActivitySource.AddActivityListener(listener);
            this.listener = listener;

            Regex GetWildcardRegex(IEnumerable <string> collection)
            {
                var pattern = '^' + string.Join("|", from name in collection select "(?:" + Regex.Escape(name).Replace("\\*", ".*") + ')') + '$';

                return(new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase));
            }
        }
示例#21
0
        public override void OnStartActivity(Activity activity, object payload)
        {
            if (!this.startRequestFetcher.TryFetch(payload, out HttpRequestMessage request) || request == null)
            {
                GrpcInstrumentationEventSource.Log.NullPayload(nameof(GrpcClientDiagnosticListener), nameof(this.OnStartActivity));
                return;
            }

            if (this.options.SuppressDownstreamInstrumentation)
            {
                SuppressInstrumentationScope.Enter();

                // If we are suppressing downstream instrumentation then inject
                // context here. Grpc.Net.Client uses HttpClient, so
                // SuppressDownstreamInstrumentation means that the
                // OpenTelemetry instrumentation for HttpClient will not be
                // invoked.

                // Note that HttpClient natively generates its own activity and
                // propagates W3C trace context headers regardless of whether
                // OpenTelemetry HttpClient instrumentation is invoked.
                // Therefore, injecting here preserves more intuitive span
                // parenting - i.e., the entry point span of a downstream
                // service would be parented to the span generated by
                // Grpc.Net.Client rather than the span generated natively by
                // HttpClient. Injecting here also ensures that baggage is
                // propagated to downstream services.
                // Injecting context here also ensures that the configured
                // propagator is used, as HttpClient by itself will only
                // do TraceContext propagation.
                var textMapPropagator = Propagators.DefaultTextMapPropagator;
                textMapPropagator.Inject(
                    new PropagationContext(activity.Context, Baggage.Current),
                    request,
                    HttpRequestMessageContextPropagation.HeaderValueSetter);
            }

            var grpcMethod = GrpcTagHelper.GetGrpcMethodFromActivity(activity);

            activity.DisplayName = grpcMethod?.Trim('/');

            this.activitySource.Start(activity, ActivityKind.Client, ActivitySource);

            if (activity.IsAllDataRequested)
            {
                try
                {
                    this.options.Enrich?.Invoke(activity, "OnStartActivity", request);
                }
                catch (Exception ex)
                {
                    GrpcInstrumentationEventSource.Log.EnrichmentException(ex);
                }

                activity.SetTag(SemanticConventions.AttributeRpcSystem, GrpcTagHelper.RpcSystemGrpc);

                if (GrpcTagHelper.TryParseRpcServiceAndRpcMethod(grpcMethod, out var rpcService, out var rpcMethod))
                {
                    activity.SetTag(SemanticConventions.AttributeRpcService, rpcService);
                    activity.SetTag(SemanticConventions.AttributeRpcMethod, rpcMethod);

                    // Remove the grpc.method tag added by the gRPC .NET library
                    activity.SetTag(GrpcTagHelper.GrpcMethodTagName, null);
                }

                var uriHostNameType = Uri.CheckHostName(request.RequestUri.Host);
                if (uriHostNameType == UriHostNameType.IPv4 || uriHostNameType == UriHostNameType.IPv6)
                {
                    activity.SetTag(SemanticConventions.AttributeNetPeerIp, request.RequestUri.Host);
                }
                else
                {
                    activity.SetTag(SemanticConventions.AttributeNetPeerName, request.RequestUri.Host);
                }

                activity.SetTag(SemanticConventions.AttributeNetPeerPort, request.RequestUri.Port);
            }
        }
示例#22
0
        internal TracerProviderSdk(
            Resource resource,
            IEnumerable <string> sources,
            IEnumerable <TracerProviderBuilder.InstrumentationFactory> instrumentationFactories,
            Sampler sampler,
            List <ActivityProcessor> processors)
        {
            this.resource = resource;
            this.sampler  = sampler;

            foreach (var processor in processors)
            {
                this.AddProcessor(processor);
            }

            if (instrumentationFactories.Any())
            {
                this.adapter = new ActivitySourceAdapter(sampler, this.processor, resource);
                foreach (var instrumentationFactory in instrumentationFactories)
                {
                    this.instrumentations.Add(instrumentationFactory.Factory(this.adapter));
                }
            }

            var listener = new ActivityListener
            {
                // Callback when Activity is started.
                ActivityStarted = (activity) =>
                {
                    if (!activity.IsAllDataRequested)
                    {
                        return;
                    }

                    if (SuppressInstrumentationScope.IncrementIfTriggered() == 0)
                    {
                        activity.SetResource(this.resource);
                        this.processor?.OnStart(activity);
                    }
                },

                // Callback when Activity is stopped.
                ActivityStopped = (activity) =>
                {
                    if (!activity.IsAllDataRequested)
                    {
                        return;
                    }

                    if (SuppressInstrumentationScope.DecrementIfTriggered() == 0)
                    {
                        this.processor?.OnEnd(activity);
                    }
                },

                // Setting this to true means TraceId will be always
                // available in sampling callbacks and will be the actual
                // traceid used, if activity ends up getting created.
                AutoGenerateRootContextTraceId = true,
            };

            if (sampler is AlwaysOnSampler)
            {
                listener.GetRequestedDataUsingContext = (ref ActivityCreationOptions <ActivityContext> options) =>
                                                        !Sdk.SuppressInstrumentation ? ActivityDataRequest.AllDataAndRecorded : ActivityDataRequest.None;
            }
            else if (sampler is AlwaysOffSampler)
            {
                /*TODO: Change options.Parent.SpanId to options.Parent.TraceId
                 *      once AutoGenerateRootContextTraceId is removed.*/
                listener.GetRequestedDataUsingContext = (ref ActivityCreationOptions <ActivityContext> options) =>
                                                        !Sdk.SuppressInstrumentation ? PropagateOrIgnoreData(options.Parent.SpanId) : ActivityDataRequest.None;
            }
            else
            {
                // This delegate informs ActivitySource about sampling decision when the parent context is an ActivityContext.
                listener.GetRequestedDataUsingContext = (ref ActivityCreationOptions <ActivityContext> options) =>
                                                        !Sdk.SuppressInstrumentation ? ComputeActivityDataRequest(options, sampler) : ActivityDataRequest.None;
            }

            if (sources.Any())
            {
                // Sources can be null. This happens when user
                // is only interested in InstrumentationLibraries
                // which do not depend on ActivitySources.

                var wildcardMode = false;

                // Validation of source name is already done in builder.
                foreach (var name in sources)
                {
                    if (name.Contains('*'))
                    {
                        wildcardMode = true;
                    }
                }

                if (wildcardMode)
                {
                    var pattern = "^(" + string.Join("|", from name in sources select '(' + Regex.Escape(name).Replace("\\*", ".*") + ')') + ")$";
                    var regex   = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);

                    // Function which takes ActivitySource and returns true/false to indicate if it should be subscribed to
                    // or not.
                    listener.ShouldListenTo = (activitySource) => regex.IsMatch(activitySource.Name);
                }
                else
                {
                    var activitySources = new Dictionary <string, bool>(StringComparer.OrdinalIgnoreCase);

                    foreach (var name in sources)
                    {
                        activitySources[name] = true;
                    }

                    // Function which takes ActivitySource and returns true/false to indicate if it should be subscribed to
                    // or not.
                    listener.ShouldListenTo = (activitySource) => activitySources.ContainsKey(activitySource.Name);
                }
            }

            ActivitySource.AddActivityListener(listener);
            this.listener = listener;
        }
示例#23
0
        internal TracerProviderSdk(
            Resource resource,
            IEnumerable <string> sources,
            IEnumerable <TracerProviderBuilderSdk.DiagnosticSourceInstrumentationFactory> diagnosticSourceInstrumentationFactories,
            IEnumerable <TracerProviderBuilderSdk.InstrumentationFactory> instrumentationFactories,
            Sampler sampler,
            List <BaseProcessor <Activity> > processors)
        {
            this.Resource = resource;
            this.sampler  = sampler;

            foreach (var processor in processors)
            {
                this.AddProcessor(processor);
            }

            if (diagnosticSourceInstrumentationFactories.Any())
            {
                this.adapter = new ActivitySourceAdapter(sampler, this.processor);
                foreach (var instrumentationFactory in diagnosticSourceInstrumentationFactories)
                {
                    this.instrumentations.Add(instrumentationFactory.Factory(this.adapter));
                }
            }

            if (instrumentationFactories.Any())
            {
                foreach (var instrumentationFactory in instrumentationFactories)
                {
                    this.instrumentations.Add(instrumentationFactory.Factory());
                }
            }

            var listener = new ActivityListener
            {
                // Callback when Activity is started.
                ActivityStarted = (activity) =>
                {
                    OpenTelemetrySdkEventSource.Log.ActivityStarted(activity);

                    if (!activity.IsAllDataRequested)
                    {
                        return;
                    }

                    if (SuppressInstrumentationScope.IncrementIfTriggered() == 0)
                    {
                        this.processor?.OnStart(activity);
                    }
                },

                // Callback when Activity is stopped.
                ActivityStopped = (activity) =>
                {
                    OpenTelemetrySdkEventSource.Log.ActivityStopped(activity);

                    if (!activity.IsAllDataRequested)
                    {
                        return;
                    }

                    // Spec says IsRecording must be false once span ends.
                    // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#isrecording
                    // However, Activity has slightly different semantic
                    // than Span and we don't have strong reason to do this
                    // now, as Activity anyway allows read/write always.
                    // Intentionally commenting the following line.
                    // activity.IsAllDataRequested = false;

                    if (SuppressInstrumentationScope.DecrementIfTriggered() == 0)
                    {
                        this.processor?.OnEnd(activity);
                    }
                },
            };

            if (sampler is AlwaysOnSampler)
            {
                listener.Sample = (ref ActivityCreationOptions <ActivityContext> options) =>
                                  !Sdk.SuppressInstrumentation ? ActivitySamplingResult.AllDataAndRecorded : ActivitySamplingResult.None;
            }
            else if (sampler is AlwaysOffSampler)
            {
                listener.Sample = (ref ActivityCreationOptions <ActivityContext> options) =>
                                  !Sdk.SuppressInstrumentation ? PropagateOrIgnoreData(options.Parent.TraceId) : ActivitySamplingResult.None;
            }
            else
            {
                // This delegate informs ActivitySource about sampling decision when the parent context is an ActivityContext.
                listener.Sample = (ref ActivityCreationOptions <ActivityContext> options) =>
                                  !Sdk.SuppressInstrumentation ? ComputeActivitySamplingResult(options, sampler) : ActivitySamplingResult.None;
            }

            if (sources.Any())
            {
                // Sources can be null. This happens when user
                // is only interested in InstrumentationLibraries
                // which do not depend on ActivitySources.

                var wildcardMode = false;

                // Validation of source name is already done in builder.
                foreach (var name in sources)
                {
                    if (name.Contains('*'))
                    {
                        wildcardMode = true;
                    }
                }

                if (wildcardMode)
                {
                    var pattern = "^(" + string.Join("|", from name in sources select '(' + Regex.Escape(name).Replace("\\*", ".*") + ')') + ")$";
                    var regex   = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);

                    // Function which takes ActivitySource and returns true/false to indicate if it should be subscribed to
                    // or not.
                    listener.ShouldListenTo = (activitySource) => regex.IsMatch(activitySource.Name);
                }
                else
                {
                    var activitySources = new Dictionary <string, bool>(StringComparer.OrdinalIgnoreCase);

                    foreach (var name in sources)
                    {
                        activitySources[name] = true;
                    }

                    // Function which takes ActivitySource and returns true/false to indicate if it should be subscribed to
                    // or not.
                    listener.ShouldListenTo = (activitySource) => activitySources.ContainsKey(activitySource.Name);
                }
            }

            ActivitySource.AddActivityListener(listener);
            this.listener = listener;
        }