-
Notifications
You must be signed in to change notification settings - Fork 940
Issue 7869 - Support the new W3C random flag #8012
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 3 commits
768ad30
6939da3
e1785c0
329f4a0
5c03dfd
c32d6b0
c394ea7
92fceae
3d680aa
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 |
|---|---|---|
| @@ -1,2 +1,6 @@ | ||
| Comparing source compatibility of opentelemetry-api-1.59.0-SNAPSHOT.jar against opentelemetry-api-1.58.0.jar | ||
| No changes. | ||
| *** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.api.trace.TraceFlags (not serializable) | ||
| === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 | ||
| +++ NEW METHOD: PUBLIC(+) boolean isTraceIdRandom() | ||
| +++ NEW METHOD: PUBLIC(+) io.opentelemetry.api.trace.TraceFlags withRandomTraceIdBit() | ||
| +++ NEW METHOD: PUBLIC(+) io.opentelemetry.api.trace.TraceFlags withSampledBit() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,4 @@ | ||
| Comparing source compatibility of opentelemetry-sdk-trace-1.59.0-SNAPSHOT.jar against opentelemetry-sdk-trace-1.58.0.jar | ||
| No changes. | ||
| *** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.sdk.trace.IdGenerator (not serializable) | ||
| === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 | ||
| +++ NEW METHOD: PUBLIC(+) boolean generatesRandomTraceIds() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,8 +16,10 @@ | |
| import io.opentelemetry.api.trace.Span; | ||
| import io.opentelemetry.api.trace.SpanBuilder; | ||
| import io.opentelemetry.api.trace.SpanContext; | ||
| import io.opentelemetry.api.trace.SpanId; | ||
| import io.opentelemetry.api.trace.SpanKind; | ||
| import io.opentelemetry.api.trace.TraceFlags; | ||
| import io.opentelemetry.api.trace.TraceId; | ||
| import io.opentelemetry.api.trace.TraceState; | ||
| import io.opentelemetry.context.Context; | ||
| import io.opentelemetry.sdk.common.InstrumentationScopeInfo; | ||
|
|
@@ -39,6 +41,7 @@ class SdkSpanBuilder implements SpanBuilder { | |
| private final InstrumentationScopeInfo instrumentationScopeInfo; | ||
| private final TracerSharedState tracerSharedState; | ||
| private final SpanLimits spanLimits; | ||
| private final Context rootContextWithRandomTraceIdBit; | ||
|
|
||
| @Nullable private Context parent; // null means: Use current context. | ||
| private SpanKind spanKind = SpanKind.INTERNAL; | ||
|
|
@@ -56,6 +59,23 @@ class SdkSpanBuilder implements SpanBuilder { | |
| this.instrumentationScopeInfo = instrumentationScopeInfo; | ||
| this.tracerSharedState = tracerSharedState; | ||
| this.spanLimits = spanLimits; | ||
| this.rootContextWithRandomTraceIdBit = | ||
PeterF778 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| preparePrimordialContext( | ||
| Context.root(), | ||
| TraceFlags.getDefault().withRandomTraceIdBit(), | ||
| TraceState.getDefault()); | ||
| } | ||
|
|
||
| /* | ||
| * A primordial context can be passed as the parent context for a root span | ||
| * if a non-default TraceFlags or TraceState need to be passed to the sampler | ||
| */ | ||
| private static Context preparePrimordialContext( | ||
| Context parentContext, TraceFlags traceFlags, TraceState traceState) { | ||
|
||
| SpanContext spanContext = | ||
| SpanContext.create(TraceId.getInvalid(), SpanId.getInvalid(), traceFlags, traceState); | ||
| Span span = Span.wrap(spanContext); | ||
| return span.storeInContext(parentContext); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -170,14 +190,25 @@ public Span startSpan() { | |
| Span parentSpan = Span.fromContext(parentContext); | ||
| SpanContext parentSpanContext = parentSpan.getSpanContext(); | ||
| String traceId; | ||
| boolean isTraceIdRandom; | ||
| IdGenerator idGenerator = tracerSharedState.getIdGenerator(); | ||
| String spanId = idGenerator.generateSpanId(); | ||
|
|
||
| Context parentContextForSampler = parentContext; | ||
| if (!parentSpanContext.isValid()) { | ||
| // New root span. | ||
| traceId = idGenerator.generateTraceId(); | ||
| if (idGenerator.generatesRandomTraceIds()) { | ||
| isTraceIdRandom = true; | ||
| // Replace parentContext for sampling with one with RANDOM_TRACE_ID bit set | ||
| parentContextForSampler = rootContextWithRandomTraceIdBit; | ||
| } else { | ||
| isTraceIdRandom = false; | ||
| } | ||
| } else { | ||
| // New child span. | ||
| traceId = parentSpanContext.getTraceId(); | ||
| isTraceIdRandom = parentSpanContext.getTraceFlags().isTraceIdRandom(); | ||
| } | ||
| List<LinkData> currentLinks = links; | ||
| List<LinkData> immutableLinks = | ||
|
|
@@ -190,7 +221,12 @@ public Span startSpan() { | |
| tracerSharedState | ||
| .getSampler() | ||
| .shouldSample( | ||
| parentContext, traceId, spanName, spanKind, immutableAttributes, immutableLinks); | ||
| parentContextForSampler, | ||
| traceId, | ||
| spanName, | ||
| spanKind, | ||
| immutableAttributes, | ||
| immutableLinks); | ||
| SamplingDecision samplingDecision = samplingResult.getDecision(); | ||
|
|
||
| TraceState samplingResultTraceState = | ||
|
|
@@ -199,7 +235,7 @@ public Span startSpan() { | |
| ImmutableSpanContext.create( | ||
| traceId, | ||
| spanId, | ||
| isSampled(samplingDecision) ? TraceFlags.getSampled() : TraceFlags.getDefault(), | ||
| newTraceFlags(isTraceIdRandom, isSampled(samplingDecision)), | ||
jack-berg marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| samplingResultTraceState, | ||
| /* remote= */ false, | ||
| tracerSharedState.isIdGeneratorSafeToSkipIdValidation()); | ||
|
|
@@ -239,6 +275,17 @@ public Span startSpan() { | |
| recordEndSpanMetrics); | ||
| } | ||
|
|
||
| private static TraceFlags newTraceFlags(boolean randomTraceId, boolean sampled) { | ||
PeterF778 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| TraceFlags traceFlags = TraceFlags.getDefault(); | ||
| if (randomTraceId) { | ||
| traceFlags = traceFlags.withRandomTraceIdBit(); | ||
| } | ||
| if (sampled) { | ||
| traceFlags = traceFlags.withSampledBit(); | ||
| } | ||
| return traceFlags; | ||
| } | ||
|
|
||
| private AttributesMap attributes() { | ||
| AttributesMap attributes = this.attributes; | ||
| if (attributes == null) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Taking another look at this, I think these need to be static helpers with signatures of the form
static TraceFlags with{Param}(TraceFlags traceFlags, boolean {param}) { ...}.The instance levels make for nice UX, but are overridable, which I believe is never needed and would lead to bad / hard-to-debug behavior.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we do not want them to be overridden. I definitely considered the static methods, and ultimately opted out of them: the usage is less convenient, and even though TraceFlags is an interface, it is really tightly coupled with ImmutableTraceFlags (see fromHex(), and fromByte()), so in practice developing a different implementation would be very inconvenient, if not impossible.
Another thing is about being able to reset some bits. I consciously did not provide this functionality. W3C Trace Context specification effectively says that any set bit from the upstream TraceFlags has to be cleared if the current implementation does not recognize it. I read this as a requirement to always build TraceFlags from scratch. Providing the capability to take (potentially unknown) TraceFlags and clear selected bits could confuse the users into thinking that they can do this with incoming TraceFlags.