diff --git a/ddtrace/tracer/payload_test.go b/ddtrace/tracer/payload_test.go index 3dad5dd2fa..99674dba45 100644 --- a/ddtrace/tracer/payload_test.go +++ b/ddtrace/tracer/payload_test.go @@ -174,6 +174,32 @@ func TestPayloadV1Decode(t *testing.T) { assert.Equal(p.chunks[0].spans[0].spanID, got.chunks[0].spans[0].spanID) assert.Equal(got.chunks[0].attributes["service"].value, "golden") }) + + // Test that a span with no decision maker does not error + t.Run("no decision maker", func(t *testing.T) { + var ( + assert = assert.New(t) + p = newPayloadV1() + ) + + s := newBasicSpan("span.list") + s.context.trace.propagatingTags = map[string]string{"keyDecisionMaker": ""} + p.push([]*Span{s}) + encoded, err := io.ReadAll(p) + assert.NoError(err) + + got := newPayloadV1() + buf := bytes.NewBuffer(encoded) + _, err = buf.WriteTo(got) + assert.NoError(err) + + o, err := got.decodeBuffer() + assert.NoError(err) + assert.Empty(o) + assert.Greater(len(got.chunks), 0) + assert.Equal(p.chunks[0].traceID, got.chunks[0].traceID) + assert.Equal(p.chunks[0].spans[0].spanID, got.chunks[0].spans[0].spanID) + }) } } diff --git a/ddtrace/tracer/payload_v1.go b/ddtrace/tracer/payload_v1.go index 06decad29b..b73dd6d327 100644 --- a/ddtrace/tracer/payload_v1.go +++ b/ddtrace/tracer/payload_v1.go @@ -118,18 +118,33 @@ func (p *payloadV1) push(t spanList) (stats payloadStats, err error) { if span == nil { continue } + + if span.Context() == nil { + continue + } + // If we haven't seen the service yet, we set it blindly assuming that all the spans created by // a service must share the same value. if _, ok := attr["service"]; !ok { attr["service"] = anyValue{valueType: StringValueType, value: span.Root().service} } + binary.BigEndian.PutUint64(traceID[:8], span.Context().traceID.Upper()) binary.BigEndian.PutUint64(traceID[8:], span.Context().traceID.Lower()) - if prio, ok := span.Context().SamplingPriority(); ok { - origin = span.Context().origin // TODO(darccio): are we sure that origin will be shared across all the spans in the chunk? - priority = prio // TODO(darccio): the same goes for priority. - dm := span.context.trace.propagatingTag(keyDecisionMaker) + if span.context.trace == nil { + continue + } + + // TODO(darccio): are we sure that priority will be shared across all the spans in the chunk? + if prio, ok := span.context.trace.samplingPriority(); ok { + priority = prio + } + + // TODO(darccio): are we sure that origin will be shared across all the spans in the chunk? + origin = span.Context().origin + + if dm := span.context.trace.propagatingTag(keyDecisionMaker); dm != "" { if v, err := strconv.ParseInt(dm, 10, 32); err == nil { if v < 0 { v = -v