Пример #1
0
        /// <summary>
        /// Enables OpenTelemetry.
        /// </summary>
        /// <param name="configureOpenTelemetryBuilder">Function that configures OpenTelemetryBuilder.</param>
        /// <returns><see cref="OpenTelemetrySdk"/> instance which can be disposed on application shutdown.</returns>
        /// <remarks>
        /// Basic implementation only. Most logic from TracerBuilder will be ported here.
        /// </remarks>
        public static OpenTelemetrySdk EnableOpenTelemetry(Action <OpenTelemetryBuilder> configureOpenTelemetryBuilder)
        {
            var openTelemetryBuilder = new OpenTelemetryBuilder();

            configureOpenTelemetryBuilder(openTelemetryBuilder);

            var             openTelemetrySDK = new OpenTelemetrySdk();
            ActivitySampler sampler          = openTelemetryBuilder.Sampler ?? new AlwaysOnActivitySampler();

            ActivityProcessor activityProcessor;

            if (openTelemetryBuilder.ProcessingPipeline == null)
            {
                // if there are no pipelines are configured, use noop processor
                activityProcessor = new NoopActivityProcessor();
            }
            else
            {
                activityProcessor = openTelemetryBuilder.ProcessingPipeline.Build();
            }

            if (openTelemetryBuilder.InstrumentationFactories != null)
            {
                foreach (var instrumentation in openTelemetryBuilder.InstrumentationFactories)
                {
                    openTelemetrySDK.instrumentations.Add(instrumentation.Factory());
                }
            }

            // This is what subscribes to Activities.
            // Think of this as the replacement for DiagnosticListener.AllListeners.Subscribe(onNext => diagnosticListener.Subscribe(..));
            openTelemetrySDK.listener = new ActivityListener
            {
                // Callback when Activity is started.
                ActivityStarted = activityProcessor.OnStart,

                // Callback when Activity is started.
                ActivityStopped = activityProcessor.OnEnd,

                // Function which takes ActivitySource and returns true/false to indicate if it should be subscribed to
                // or not
                ShouldListenTo = (activitySource) => openTelemetryBuilder.ActivitySourceNames?.Contains(activitySource.Name.ToUpperInvariant()) ?? false,

                // The following parameter is not used now.
                GetRequestedDataUsingParentId = (ref ActivityCreationOptions <string> options) => ActivityDataRequest.AllData,

                // This delegate informs ActivitySource about sampling decision when the parent context is an ActivityContext.
                GetRequestedDataUsingContext = (ref ActivityCreationOptions <ActivityContext> options) => ComputeActivityDataRequest(options, sampler),
            };

            ActivitySource.AddActivityListener(openTelemetrySDK.listener);
            return(openTelemetrySDK);
        }
Пример #2
0
        internal ActivityProcessor Build()
        {
            this.Processors = new List <ActivityProcessor>();

            ActivityProcessor exportingProcessor = null;

            // build or create default exporting processor
            if (this.lastProcessorFactory != null)
            {
                exportingProcessor = this.lastProcessorFactory.Invoke(this.Exporter);
                this.Processors.Add(exportingProcessor);
            }
            else if (this.Exporter != null)
            {
                // TODO: Make this BatchingActivityProcessor once its available.
                exportingProcessor = new SimpleActivityProcessor(this.Exporter);
                this.Processors.Add(exportingProcessor);
            }

            if (this.processorChain == null)
            {
                // if there is no chain, return exporting processor.
                if (exportingProcessor == null)
                {
                    exportingProcessor = new NoopActivityProcessor();
                    this.Processors.Add(exportingProcessor);
                }

                return(exportingProcessor);
            }

            var next = exportingProcessor;

            // build chain from the end to the beginning
            for (int i = this.processorChain.Count - 1; i >= 0; i--)
            {
                next = this.processorChain[i].Invoke(next);
                this.Processors.Add(next);
            }

            // return the last processor in the chain - it will be called first
            return(this.Processors[this.Processors.Count - 1]);
        }
Пример #3
0
        /// <summary>
        /// Enables OpenTelemetry.
        /// </summary>
        /// <param name="configureOpenTelemetryBuilder">Function that configures OpenTelemetryBuilder.</param>
        /// <remarks>
        /// Basic implementation only. Most logic from TracerBuilder will be ported here.
        /// </remarks>
        public static void EnableOpenTelemetry(Action <OpenTelemetryBuilder> configureOpenTelemetryBuilder)
        {
            var openTelemetryBuilder = new OpenTelemetryBuilder();

            configureOpenTelemetryBuilder(openTelemetryBuilder);

            ActivityProcessor activityProcessor;

            if (openTelemetryBuilder.ProcessingPipeline == null)
            {
                // if there are no pipelines are configured, use noop processor
                activityProcessor = new NoopActivityProcessor();
            }
            else
            {
                activityProcessor = openTelemetryBuilder.ProcessingPipeline.Build();
            }

            // This is what subscribes to Activities.
            // Think of this as the replacement for DiagnosticListener.AllListeners.Subscribe(onNext => diagnosticListener.Subscribe(..));
            ActivityListener listener = new ActivityListener
            {
                // Callback when Activity is started.
                ActivityStarted = activityProcessor.OnStart,

                // Callback when Activity is started.
                ActivityStopped = activityProcessor.OnEnd,

                // Function which takes ActivitySource and returns true/false to indicate if it should be subscribed to
                // or not
                ShouldListenTo = (activitySource) => openTelemetryBuilder.ActivitySourceNames.Contains(activitySource.Name.ToUpperInvariant()),

                // The following parameters are not used now.
                GetRequestedDataUsingParentId = (ref ActivityCreationOptions <string> options) => ActivityDataRequest.AllData,
                GetRequestedDataUsingContext  = (ref ActivityCreationOptions <ActivityContext> options) => ActivityDataRequest.AllData,
            };

            ActivitySource.AddActivityListener(listener);
        }
Пример #4
0
        /// <summary>
        /// Creates TracerProvider with the configuration provided.
        /// This sets up listeners for all configured ActivitySources and
        /// sends activities to the pipeline of Sampler, Processor and Exporter.
        /// </summary>
        /// <param name="configureTracerProviderBuilder">Action to configure TracerProviderBuilder.</param>
        /// <returns>TracerProvider instance, which must be disposed upon shutdown.</returns>
        public static TracerProvider CreateTracerProvider(Action <TracerProviderBuilder> configureTracerProviderBuilder)
        {
            var tracerProviderBuilder = new TracerProviderBuilder();

            configureTracerProviderBuilder?.Invoke(tracerProviderBuilder);

            var     tracerProviderSdk = new TracerProviderSdk();
            Sampler sampler           = tracerProviderBuilder.Sampler ?? new AlwaysOnSampler();

            ActivityProcessor activityProcessor;

            if (tracerProviderBuilder.ProcessingPipelines == null || !tracerProviderBuilder.ProcessingPipelines.Any())
            {
                // if there are no pipelines are configured, use noop processor
                activityProcessor = new NoopActivityProcessor();
            }
            else if (tracerProviderBuilder.ProcessingPipelines.Count == 1)
            {
                // if there is only one pipeline - use it's outer processor as a
                // single processor on the tracerSdk.
                var processorFactory = tracerProviderBuilder.ProcessingPipelines[0];
                activityProcessor = processorFactory.Build();
            }
            else
            {
                // if there are more pipelines, use processor that will broadcast to all pipelines
                var processors = new ActivityProcessor[tracerProviderBuilder.ProcessingPipelines.Count];

                for (int i = 0; i < tracerProviderBuilder.ProcessingPipelines.Count; i++)
                {
                    processors[i] = tracerProviderBuilder.ProcessingPipelines[i].Build();
                }

                activityProcessor = new BroadcastActivityProcessor(processors);
            }

            tracerProviderSdk.Resource = tracerProviderBuilder.Resource;

            var activitySource = new ActivitySourceAdapter(sampler, activityProcessor, tracerProviderSdk.Resource);

            if (tracerProviderBuilder.InstrumentationFactories != null)
            {
                foreach (var instrumentation in tracerProviderBuilder.InstrumentationFactories)
                {
                    tracerProviderSdk.Instrumentations.Add(instrumentation.Factory(activitySource));
                }
            }

            // This is what subscribes to Activities.
            // Think of this as the replacement for DiagnosticListener.AllListeners.Subscribe(onNext => diagnosticListener.Subscribe(..));
            tracerProviderSdk.ActivityListener = new ActivityListener
            {
                // Callback when Activity is started.
                ActivityStarted = (activity) =>
                {
                    if (activity.IsAllDataRequested)
                    {
                        activity.SetResource(tracerProviderSdk.Resource);
                    }

                    activityProcessor.OnStart(activity);
                },

                // Callback when Activity is stopped.
                ActivityStopped = activityProcessor.OnEnd,

                // Function which takes ActivitySource and returns true/false to indicate if it should be subscribed to
                // or not
                ShouldListenTo = (activitySource) => tracerProviderBuilder.ActivitySourceNames?.Contains(activitySource.Name.ToUpperInvariant()) ?? false,

                // The following parameter is not used now.
                GetRequestedDataUsingParentId = (ref ActivityCreationOptions <string> options) => ActivityDataRequest.AllData,

                // This delegate informs ActivitySource about sampling decision when the parent context is an ActivityContext.
                GetRequestedDataUsingContext = (ref ActivityCreationOptions <ActivityContext> options) => ComputeActivityDataRequest(options, sampler),
            };

            ActivitySource.AddActivityListener(tracerProviderSdk.ActivityListener);
            tracerProviderSdk.ActivityProcessor = activityProcessor;
            return(tracerProviderSdk);
        }
        /// <summary>
        /// Enables OpenTelemetry.
        /// </summary>
        /// <param name="configureOpenTelemetryBuilder">Function that configures OpenTelemetryBuilder.</param>
        /// <remarks>
        /// Basic implementation only. Most logic from TracerBuilder will be ported here.
        /// </remarks>
        public static void EnableOpenTelemetry(Action <OpenTelemetryBuilder> configureOpenTelemetryBuilder)
        {
            var openTelemetryBuilder = new OpenTelemetryBuilder();

            configureOpenTelemetryBuilder(openTelemetryBuilder);

            ActivitySampler sampler = openTelemetryBuilder.Sampler ?? new AlwaysOnActivitySampler();

            ActivityProcessor activityProcessor;

            if (openTelemetryBuilder.ProcessingPipeline == null)
            {
                // if there are no pipelines are configured, use noop processor
                activityProcessor = new NoopActivityProcessor();
            }
            else
            {
                activityProcessor = openTelemetryBuilder.ProcessingPipeline.Build();
            }

            // This is what subscribes to Activities.
            // Think of this as the replacement for DiagnosticListener.AllListeners.Subscribe(onNext => diagnosticListener.Subscribe(..));
            ActivityListener listener = new ActivityListener
            {
                // Callback when Activity is started.
                ActivityStarted = activityProcessor.OnStart,

                // Callback when Activity is started.
                ActivityStopped = activityProcessor.OnEnd,

                // Function which takes ActivitySource and returns true/false to indicate if it should be subscribed to
                // or not
                ShouldListenTo = (activitySource) => openTelemetryBuilder.ActivitySourceNames.Contains(activitySource.Name.ToUpperInvariant()),

                // The following parameter is not used now.
                GetRequestedDataUsingParentId = (ref ActivityCreationOptions <string> options) => ActivityDataRequest.AllData,

                // This delegate informs ActivitySource about sampling decision.
                // Following simple behavior is enabled now:
                // If Sampler returns IsSampled as true, returns ActivityDataRequest.AllDataAndRecorded
                // This creates Activity and sets its IsAllDataRequested to true.
                // Library authors can check activity.IsAllDataRequested and avoid
                // doing any additional telemetry population.
                // Activity.IsAllDataRequested is the equivalent of Span.IsRecording
                //
                // If Sampler returns IsSampled as false, returns ActivityDataRequest.None
                // This prevents Activity from being created at all.
                GetRequestedDataUsingContext = (ref ActivityCreationOptions <ActivityContext> options) =>
                {
                    var shouldSample = sampler.ShouldSample(
                        options.Parent,
                        options.Parent.TraceId,
                        default(ActivitySpanId), // Passing default SpanId here. The actual SpanId is not known before actual Activity creation
                        options.Name,
                        options.Kind,
                        options.Tags,
                        options.Links);
                    if (shouldSample.IsSampled)
                    {
                        return(ActivityDataRequest.AllDataAndRecorded);
                    }
                    else
                    {
                        return(ActivityDataRequest.None);
                    }

                    // TODO: Improve this to properly use ActivityDataRequest.AllData, PropagationData as well.
                },
            };

            ActivitySource.AddActivityListener(listener);
        }