Skip to content
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

Spec Conformance Review: SDK Span creation #1648

Closed
4 tasks done
MrAlias opened this issue Mar 5, 2021 · 2 comments · Fixed by open-telemetry/opentelemetry-specification#1545
Closed
4 tasks done
Labels
area:trace Part of OpenTelemetry tracing pkg:SDK Related to an SDK package
Milestone

Comments

@MrAlias
Copy link
Contributor

MrAlias commented Mar 5, 2021

  • Review SDK Span creation section of the specification and identify all normative requirements it contains.
  • Validate our implementation of the specification to conform or not. If it conforms, document the conformity here. If it does not open an Issue or PR track the work.
  • Review the Traces/New Span ID created also for non-recording Spans section of the Spec Compliance Matrix.
  • Update the matrix with the current state of Go (existing entries for Go should be ignored). If Go does not provide support for an item listed be sure to link to the Issue/PR tracking the work to support it.
@MrAlias MrAlias added pkg:SDK Related to an SDK package area:trace Part of OpenTelemetry tracing labels Mar 5, 2021
@MrAlias
Copy link
Contributor Author

MrAlias commented Mar 12, 2021

SDK Span creation

When asked to create a Span, the SDK MUST act as if doing the following in order:

  1. If there is a valid parent trace ID, use it. Otherwise generate a new trace ID
    (note: this must be done before calling ShouldSample, because it expects
    a valid trace ID as input).

if hasEmptySpanContext(parent) {
// Generate both TraceID and SpanID
tid, sid = cfg.IDGenerator.NewIDs(ctx)
} else {
// TraceID already exists, just generate a SpanID
tid = parent.TraceID()
sid = cfg.IDGenerator.NewSpanID(ctx, tid)
}

  1. Query the Sampler's ShouldSample method
    (Note that the built-in ParentBasedSampler can be used to
    use the sampling decision of the parent,
    translating a set SampledFlag to RECORD and an unset one to DROP).

samplingResult := makeSamplingDecision(data)

  1. Generate a new span ID for the Span, independently of the sampling decision.
    This is done so other components (such as logs or exception handling) can rely on
    a unique span ID, even if the Span is a non-recording instance.

A new span ID is generated here:

var tid trace.TraceID
var sid trace.SpanID
if hasEmptySpanContext(parent) {
// Generate both TraceID and SpanID
tid, sid = cfg.IDGenerator.NewIDs(ctx)
} else {
// TraceID already exists, just generate a SpanID
tid = parent.TraceID()
sid = cfg.IDGenerator.NewSpanID(ctx, tid)
}
span.spanContext = trace.NewSpanContext(trace.SpanContextConfig{
TraceID: tid,
SpanID: sid,
TraceFlags: parent.TraceFlags(),
TraceState: parent.TraceState(),
})

it is done prior step 2, but step 2 has no influence on the Span ID value:

func makeSamplingDecision(data samplingData) SamplingResult {
sampler := data.cfg.DefaultSampler
return sampler.ShouldSample(SamplingParameters{
ParentContext: data.parent,
TraceID: data.span.spanContext.TraceID(),
Name: data.name,
HasRemoteParent: data.remoteParent,
Kind: data.kind,
Attributes: data.attributes,
Links: data.links,
})
}

In this sense it is "act[ing] as if doing" the step in order.

  1. Create a span depending on the decision returned by ShouldSample:
    see description of ShouldSample's return value below
    for how to set IsRecording and Sampled on the Span,
    and the table above on whether
    to pass the Span to SpanProcessors.
    A non-recording span MAY be implemented using the same mechanism as when a
    Span is created without an SDK installed or as described in
    wrapping a SpanContext in a Span.

if isSampled(samplingResult) {
span.spanContext = span.spanContext.WithTraceFlags(span.spanContext.TraceFlags() | trace.FlagsSampled)
} else {
span.spanContext = span.spanContext.WithTraceFlags(span.spanContext.TraceFlags() &^ trace.FlagsSampled)
}
span.spanContext = span.spanContext.WithTraceState(samplingResult.Tracestate)
if !isRecording(samplingResult) {
return span
}
startTime := o.Timestamp
if startTime.IsZero() {
startTime = time.Now()
}
span.startTime = startTime
span.spanKind = trace.ValidateSpanKind(o.SpanKind)
span.name = name
span.hasRemoteParent = remoteParent
span.resource = cfg.Resource
span.instrumentationLibrary = tr.instrumentationLibrary
span.SetAttributes(samplingResult.Attributes...)
span.parent = parent

@MrAlias
Copy link
Contributor Author

MrAlias commented Mar 12, 2021

spec-compliance-matrix

Feature Go
New Span ID created also for non-recording Spans +

New Span IDs are created for all spans.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:trace Part of OpenTelemetry tracing pkg:SDK Related to an SDK package
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants