/// <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); }
/// <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.ProcessingPipelines == null || !openTelemetryBuilder.ProcessingPipelines.Any()) { // if there are no pipelines are configured, use noop processor activityProcessor = new NoopActivityProcessor(); } else if (openTelemetryBuilder.ProcessingPipelines.Count == 1) { // if there is only one pipeline - use it's outer processor as a // single processor on the tracerSdk. var processorFactory = openTelemetryBuilder.ProcessingPipelines[0]; activityProcessor = processorFactory.Build(); } else { // if there are more pipelines, use processor that will broadcast to all pipelines var processors = new ActivityProcessor[openTelemetryBuilder.ProcessingPipelines.Count]; for (int i = 0; i < openTelemetryBuilder.ProcessingPipelines.Count; i++) { processors[i] = openTelemetryBuilder.ProcessingPipelines[i].Build(); } activityProcessor = new BroadcastActivityProcessor(processors); } openTelemetrySDK.resource = openTelemetryBuilder.Resource; var activitySource = new ActivitySourceAdapter(sampler, activityProcessor, openTelemetrySDK.resource); if (openTelemetryBuilder.InstrumentationFactories != null) { foreach (var instrumentation in openTelemetryBuilder.InstrumentationFactories) { openTelemetrySDK.instrumentations.Add(instrumentation.Factory(activitySource)); } } // 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 = (activity) => { if (activity.IsAllDataRequested) { activity.SetResource(openTelemetrySDK.resource); } activityProcessor.OnStart(activity); }, // 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); openTelemetrySDK.activityProcessor = activityProcessor; return(openTelemetrySDK); }
/// <summary> /// Configures sampler. /// </summary> /// <param name="sampler">Sampler instance.</param> /// <returns>Returns <see cref="OpenTelemetryBuilder"/> for chaining.</returns> public OpenTelemetryBuilder SetSampler(ActivitySampler sampler) { this.Sampler = sampler ?? throw new ArgumentNullException(nameof(sampler)); return(this); }
/// <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); }