-
Notifications
You must be signed in to change notification settings - Fork 887
Initial ideal how to refactor provider #1008
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4f1f998
127bc8b
d025c22
c18dce3
7e83d6a
dc47715
f8bcb50
3db33ae
65fce94
18b78a1
0736c08
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,7 @@ | |
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
| // </copyright> | ||
|
|
||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Diagnostics; | ||
|
|
@@ -22,6 +23,7 @@ | |
| using OpenTelemetry.Context; | ||
| using OpenTelemetry.Metrics; | ||
| using OpenTelemetry.Metrics.Export; | ||
| using OpenTelemetry.Resources; | ||
| using OpenTelemetry.Trace; | ||
| using OpenTelemetry.Trace.Internal; | ||
| using OpenTelemetry.Trace.Samplers; | ||
|
|
@@ -161,30 +163,85 @@ public static TracerProvider CreateTracerProvider(Action<TracerProviderBuilder> | |
| return tracerProviderSdk; | ||
| } | ||
|
|
||
| public static TracerProvider CreateTracerProvider(IEnumerable<string> sources, Sampler sampler = null, Resource resource = null) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @reyang @cijothomas Can you still call
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it depends on what do we expect
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @CodeBlanch as you can see from the commit history, initially I was thinking of having both
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry I'm kind of out of the loop on the pattern we're going for. If it was a builder, you create the instance. Then you build it up. At the end you call .Build and you get the final thing. So I would expect to be able to modify it up until the point build is called, after which I would expect you cannot modify it again. That help?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @CodeBlanch correct, the builder approach works in the exact way you've describe.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we still need some kind of builder. So that exporter authors, instrumentation authors, etc., can add in "Use/Add" extensions. Those are super user friendly! In my mind, the pattern is: using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.SetResource(ResourceTags);
.AddActivitySource("MySource")
.AddHttpClientInstrumentation()
.UseJaegerExporter()
.UseProbabilitySampler(0.5)
.Build();Build gives you a fully functioning TracerProvider aka pipeline.
Spec seems to say it's up to us if we want to allow the tracerProvider.AddProcessor(new MyProcessor());Which you could do after Build has been called. 🤷
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Totally, the way I think about this problem - we need the primitive low level APIs that are orthogonal, and user friendly APIs (e.g. builder pattern) that are expressive, make people's life easier + support other patterns such like dependency injection. The current approach is different, it gives the higher level APIs that are not orthogonal, and make it hard for people who want to access low level functionalities, that's something I'm trying to make a change. |
||
| { | ||
| var activitySources = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase); | ||
|
|
||
| foreach (var name in sources) | ||
| { | ||
| activitySources[name] = true; | ||
| } | ||
|
|
||
| var provider = new TracerProviderSdk | ||
| { | ||
| Resource = resource, | ||
| Sampler = sampler, | ||
| }; | ||
|
|
||
| provider.ActivityListener = new ActivityListener | ||
| { | ||
| // Callback when Activity is started. | ||
| ActivityStarted = (activity) => | ||
| { | ||
| if (activity.IsAllDataRequested) | ||
| { | ||
| activity.SetResource(resource); | ||
| } | ||
|
|
||
| provider.ActivityProcessor?.OnStart(activity); | ||
| }, | ||
|
|
||
| // Callback when Activity is stopped. | ||
| ActivityStopped = (activity) => | ||
| { | ||
| provider.ActivityProcessor?.OnEnd(activity); | ||
| }, | ||
|
|
||
| // Function which takes ActivitySource and returns true/false to indicate if it should be subscribed to | ||
| // or not. | ||
| ShouldListenTo = (activitySource) => activitySources.ContainsKey(activitySource.Name), | ||
|
|
||
| // 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, | ||
|
|
||
| // This delegate informs ActivitySource about sampling decision when the parent context is an ActivityContext. | ||
| GetRequestedDataUsingContext = (ref ActivityCreationOptions<ActivityContext> options) => ComputeActivityDataRequest(options, sampler), | ||
| }; | ||
|
|
||
| ActivitySource.AddActivityListener(provider.ActivityListener); | ||
|
|
||
| return provider; | ||
| } | ||
|
|
||
| internal static ActivityDataRequest ComputeActivityDataRequest( | ||
| in ActivityCreationOptions<ActivityContext> options, | ||
| Sampler sampler) | ||
| { | ||
| var isRootSpan = /*TODO: Put back once AutoGenerateRootContextTraceId is removed. | ||
| options.Parent.TraceId == default ||*/ options.Parent.SpanId == default; | ||
|
|
||
| // As we set ActivityListener.AutoGenerateRootContextTraceId = true, | ||
| // Parent.TraceId will always be the TraceId of the to-be-created Activity, | ||
| // if it get created. | ||
| ActivityTraceId traceId = options.Parent.TraceId; | ||
|
|
||
| var samplingParameters = new SamplingParameters( | ||
| options.Parent, | ||
| traceId, | ||
| options.Name, | ||
| options.Kind, | ||
| options.Tags, | ||
| options.Links); | ||
|
|
||
| var shouldSample = sampler.ShouldSample(samplingParameters); | ||
| if (shouldSample.IsSampled) | ||
| if (sampler != null) | ||
| { | ||
| return ActivityDataRequest.AllDataAndRecorded; | ||
| // As we set ActivityListener.AutoGenerateRootContextTraceId = true, | ||
| // Parent.TraceId will always be the TraceId of the to-be-created Activity, | ||
| // if it get created. | ||
| ActivityTraceId traceId = options.Parent.TraceId; | ||
|
|
||
| var samplingParameters = new SamplingParameters( | ||
| options.Parent, | ||
| traceId, | ||
| options.Name, | ||
| options.Kind, | ||
| options.Tags, | ||
| options.Links); | ||
|
|
||
| var shouldSample = sampler.ShouldSample(samplingParameters); | ||
| if (shouldSample.IsSampled) | ||
| { | ||
| return ActivityDataRequest.AllDataAndRecorded; | ||
| } | ||
| } | ||
|
|
||
| // If it is the root span select PropagationData so the trace ID is preserved | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.