Skip to content

Commit 439cd31

Browse files
matej-gMrAlias
andauthored
Add TraceState to SpanContext in API (#1340)
* Add TraceState to API * Add tests for TraceState * Update related tests - stdout exporter test - SDK test * Update OTLP span transform * Update CHANGELOG * Change TraceState to struct instead of pointer - Adjust tests for trace API - Adjust adjacent parts of codebase (test utils, SDK etc.) * Add methods to assert equality - for type SpanContext, if SpanID, TraceID, TraceFlag and TraceState are equal - for type TraceState, if entries of both respective trace states are equal Signed-off-by: Matej Gera <[email protected]> * Copy values for new TraceState, adjust tests * Use IsEqualWith in remaining tests instead of assertion func * Further feedback, minor improvements - Move IsEqualWith method to be only in test package - Minor improvements, typos etc. Co-authored-by: Tyler Yahn <[email protected]>
1 parent 3521526 commit 439cd31

File tree

14 files changed

+573
-64
lines changed

14 files changed

+573
-64
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
5454
- An `EventOption` and the related `NewEventConfig` function are added to the `go.opentelemetry.io/otel` package to configure Span events. (#1254)
5555
- A `TextMapPropagator` and associated `TextMapCarrier` are added to the `go.opentelemetry.io/otel/oteltest` package to test `TextMap` type propagators and their use. (#1259)
5656
- `SpanContextFromContext` returns `SpanContext` from context. (#1255)
57+
- `TraceState` has been added to `SpanContext`. (#1340)
5758
- `DeploymentEnvironmentKey` added to `go.opentelemetry.io/otel/semconv` package. (#1323)
5859
- Add an OpenCensus to OpenTelemetry tracing bridge. (#1305)
5960
- Add a parent context argument to `SpanProcessor.OnStart` to follow the specification. (#1333)

bridge/opencensus/utils/utils_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,9 @@ func TestOCSpanContextToOTel(t *testing.T) {
130130
} {
131131
t.Run(tc.description, func(t *testing.T) {
132132
output := OCSpanContextToOTel(tc.input)
133-
if output != tc.expected {
133+
if output.SpanID != tc.expected.SpanID ||
134+
output.TraceID != tc.expected.TraceID ||
135+
output.TraceFlags != tc.expected.TraceFlags {
134136
t.Fatalf("Got %+v spancontext, exepected %+v.", output, tc.expected)
135137
}
136138
})

exporters/otlp/internal/transform/span.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -102,17 +102,17 @@ func span(sd *export.SpanSnapshot) *tracepb.Span {
102102
}
103103

104104
s := &tracepb.Span{
105-
TraceId: sd.SpanContext.TraceID[:],
106-
SpanId: sd.SpanContext.SpanID[:],
107-
Status: status(sd.StatusCode, sd.StatusMessage),
108-
StartTimeUnixNano: uint64(sd.StartTime.UnixNano()),
109-
EndTimeUnixNano: uint64(sd.EndTime.UnixNano()),
110-
Links: links(sd.Links),
111-
Kind: spanKind(sd.SpanKind),
112-
Name: sd.Name,
113-
Attributes: Attributes(sd.Attributes),
114-
Events: spanEvents(sd.MessageEvents),
115-
// TODO (rghetia): Add Tracestate: when supported.
105+
TraceId: sd.SpanContext.TraceID[:],
106+
SpanId: sd.SpanContext.SpanID[:],
107+
TraceState: sd.SpanContext.TraceState.String(),
108+
Status: status(sd.StatusCode, sd.StatusMessage),
109+
StartTimeUnixNano: uint64(sd.StartTime.UnixNano()),
110+
EndTimeUnixNano: uint64(sd.EndTime.UnixNano()),
111+
Links: links(sd.Links),
112+
Kind: spanKind(sd.SpanKind),
113+
Name: sd.Name,
114+
Attributes: Attributes(sd.Attributes),
115+
Events: spanEvents(sd.MessageEvents),
116116
DroppedAttributesCount: uint32(sd.DroppedAttributeCount),
117117
DroppedEventsCount: uint32(sd.DroppedMessageEventCount),
118118
DroppedLinksCount: uint32(sd.DroppedLinkCount),

exporters/otlp/internal/transform/span_test.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,12 @@ func TestSpanData(t *testing.T) {
199199
// March 31, 2020 5:01:26 1234nanos (UTC)
200200
startTime := time.Unix(1585674086, 1234)
201201
endTime := startTime.Add(10 * time.Second)
202+
traceState, _ := trace.TraceStateFromKeyValues(label.String("key1", "val1"), label.String("key2", "val2"))
202203
spanData := &export.SpanSnapshot{
203204
SpanContext: trace.SpanContext{
204-
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
205-
SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
205+
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
206+
SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
207+
TraceState: traceState,
206208
},
207209
SpanKind: trace.SpanKindServer,
208210
ParentSpanID: trace.SpanID{0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8},
@@ -266,6 +268,7 @@ func TestSpanData(t *testing.T) {
266268
TraceId: []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
267269
SpanId: []byte{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
268270
ParentSpanId: []byte{0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8},
271+
TraceState: "key1=val1,key2=val2",
269272
Name: spanData.Name,
270273
Kind: tracepb.Span_SPAN_KIND_SERVER,
271274
StartTimeUnixNano: uint64(startTime.UnixNano()),

exporters/stdout/trace_test.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,16 @@ func TestExporter_ExportSpan(t *testing.T) {
4242
now := time.Now()
4343
traceID, _ := trace.TraceIDFromHex("0102030405060708090a0b0c0d0e0f10")
4444
spanID, _ := trace.SpanIDFromHex("0102030405060708")
45+
traceState, _ := trace.TraceStateFromKeyValues(label.String("key", "val"))
4546
keyValue := "value"
4647
doubleValue := 123.456
4748
resource := resource.NewWithAttributes(label.String("rk1", "rv11"))
4849

4950
testSpan := &export.SpanSnapshot{
5051
SpanContext: trace.SpanContext{
51-
TraceID: traceID,
52-
SpanID: spanID,
52+
TraceID: traceID,
53+
SpanID: spanID,
54+
TraceState: traceState,
5355
},
5456
Name: "/foo",
5557
StartTime: now,
@@ -76,7 +78,12 @@ func TestExporter_ExportSpan(t *testing.T) {
7678
got := b.String()
7779
expectedOutput := `[{"SpanContext":{` +
7880
`"TraceID":"0102030405060708090a0b0c0d0e0f10",` +
79-
`"SpanID":"0102030405060708","TraceFlags":0},` +
81+
`"SpanID":"0102030405060708","TraceFlags":0,` +
82+
`"TraceState":[` +
83+
`{` +
84+
`"Key":"key",` +
85+
`"Value":{"Type":"STRING","Value":"val"}` +
86+
`}]},` +
8087
`"ParentSpanID":"0000000000000000",` +
8188
`"SpanKind":1,` +
8289
`"Name":"/foo",` +

oteltest/span.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ type Span struct {
4747
statusMessage string
4848
attributes map[label.Key]label.Value
4949
events []Event
50-
links map[trace.SpanContext][]label.KeyValue
50+
links []trace.Link
5151
spanKind trace.SpanKind
5252
}
5353

@@ -206,15 +206,7 @@ func (s *Span) Events() []Event { return s.events }
206206

207207
// Links returns the links set on s at creation time. If multiple links for
208208
// the same SpanContext were set, the last link will be used.
209-
func (s *Span) Links() map[trace.SpanContext][]label.KeyValue {
210-
links := make(map[trace.SpanContext][]label.KeyValue)
211-
212-
for sc, attributes := range s.links {
213-
links[sc] = append([]label.KeyValue{}, attributes...)
214-
}
215-
216-
return links
217-
}
209+
func (s *Span) Links() []trace.Link { return s.links }
218210

219211
// StartTime returns the time at which s was started. This will be the
220212
// wall-clock time unless a specific start time was provided.

oteltest/tracer.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func (t *Tracer) Start(ctx context.Context, name string, opts ...trace.SpanOptio
4747
tracer: t,
4848
startTime: startTime,
4949
attributes: make(map[label.Key]label.Value),
50-
links: make(map[trace.SpanContext][]label.KeyValue),
50+
links: []trace.Link{},
5151
spanKind: c.SpanKind,
5252
}
5353

@@ -56,10 +56,16 @@ func (t *Tracer) Start(ctx context.Context, name string, opts ...trace.SpanOptio
5656

5757
iodKey := label.Key("ignored-on-demand")
5858
if lsc := trace.SpanContextFromContext(ctx); lsc.IsValid() {
59-
span.links[lsc] = []label.KeyValue{iodKey.String("current")}
59+
span.links = append(span.links, trace.Link{
60+
SpanContext: lsc,
61+
Attributes: []label.KeyValue{iodKey.String("current")},
62+
})
6063
}
6164
if rsc := trace.RemoteSpanContextFromContext(ctx); rsc.IsValid() {
62-
span.links[rsc] = []label.KeyValue{iodKey.String("remote")}
65+
span.links = append(span.links, trace.Link{
66+
SpanContext: rsc,
67+
Attributes: []label.KeyValue{iodKey.String("remote")},
68+
})
6369
}
6470
} else {
6571
span.spanContext = t.config.SpanContextFunc(ctx)
@@ -73,7 +79,16 @@ func (t *Tracer) Start(ctx context.Context, name string, opts ...trace.SpanOptio
7379
}
7480

7581
for _, link := range c.Links {
76-
span.links[link.SpanContext] = link.Attributes
82+
for i, sl := range span.links {
83+
if sl.SpanContext.SpanID == link.SpanContext.SpanID &&
84+
sl.SpanContext.TraceID == link.SpanContext.TraceID &&
85+
sl.SpanContext.TraceFlags == link.SpanContext.TraceFlags &&
86+
sl.SpanContext.TraceState.String() == link.SpanContext.TraceState.String() {
87+
span.links[i].Attributes = link.Attributes
88+
break
89+
}
90+
}
91+
span.links = append(span.links, link)
7792
}
7893

7994
span.SetName(name)

oteltest/tracer_test.go

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -211,14 +211,7 @@ func TestTracer(t *testing.T) {
211211
},
212212
},
213213
}
214-
tsLinks := testSpan.Links()
215-
gotLinks := make([]trace.Link, 0, len(tsLinks))
216-
for sc, attributes := range tsLinks {
217-
gotLinks = append(gotLinks, trace.Link{
218-
SpanContext: sc,
219-
Attributes: attributes,
220-
})
221-
}
214+
gotLinks := testSpan.Links()
222215
e.Expect(gotLinks).ToMatchInAnyOrder(expectedLinks)
223216
})
224217

@@ -251,8 +244,8 @@ func TestTracer(t *testing.T) {
251244
e.Expect(ok).ToBeTrue()
252245

253246
links := testSpan.Links()
254-
e.Expect(links[link1.SpanContext]).ToEqual(link1.Attributes)
255-
e.Expect(links[link2.SpanContext]).ToEqual(link2.Attributes)
247+
e.Expect(links[0].Attributes).ToEqual(link1.Attributes)
248+
e.Expect(links[1].Attributes).ToEqual(link2.Attributes)
256249
})
257250
})
258251
}

propagation/trace_context_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ func TestExtractValidTraceContextFromHTTPReq(t *testing.T) {
113113
ctx := context.Background()
114114
ctx = prop.Extract(ctx, req.Header)
115115
gotSc := trace.RemoteSpanContextFromContext(ctx)
116-
if diff := cmp.Diff(gotSc, tt.wantSc); diff != "" {
116+
if diff := cmp.Diff(gotSc, tt.wantSc, cmp.AllowUnexported(trace.TraceState{})); diff != "" {
117117
t.Errorf("Extract Tracecontext: %s: -got +want %s", tt.name, diff)
118118
}
119119
})
@@ -201,7 +201,7 @@ func TestExtractInvalidTraceContextFromHTTPReq(t *testing.T) {
201201
ctx := context.Background()
202202
ctx = prop.Extract(ctx, req.Header)
203203
gotSc := trace.RemoteSpanContextFromContext(ctx)
204-
if diff := cmp.Diff(gotSc, wantSc); diff != "" {
204+
if diff := cmp.Diff(gotSc, wantSc, cmp.AllowUnexported(trace.TraceState{})); diff != "" {
205205
t.Errorf("Extract Tracecontext: %s: -got +want %s", tt.name, diff)
206206
}
207207
})

sdk/trace/span.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ func startSpanInternal(ctx context.Context, tr *tracer, name string, parent trac
473473

474474
cfg := tr.provider.config.Load().(*Config)
475475

476-
if parent == emptySpanContext {
476+
if hasEmptySpanContext(parent) {
477477
// Generate both TraceID and SpanID
478478
span.spanContext.TraceID, span.spanContext.SpanID = cfg.IDGenerator.NewIDs(ctx)
479479
} else {
@@ -486,7 +486,7 @@ func startSpanInternal(ctx context.Context, tr *tracer, name string, parent trac
486486
span.links = newEvictedQueue(cfg.MaxLinksPerSpan)
487487

488488
data := samplingData{
489-
noParent: parent == emptySpanContext,
489+
noParent: hasEmptySpanContext(parent),
490490
remoteParent: remoteParent,
491491
parent: parent,
492492
name: name,
@@ -521,6 +521,13 @@ func startSpanInternal(ctx context.Context, tr *tracer, name string, parent trac
521521
return span
522522
}
523523

524+
func hasEmptySpanContext(parent trace.SpanContext) bool {
525+
return parent.SpanID == emptySpanContext.SpanID &&
526+
parent.TraceID == emptySpanContext.TraceID &&
527+
parent.TraceFlags == emptySpanContext.TraceFlags &&
528+
parent.TraceState.IsEmpty()
529+
}
530+
524531
type samplingData struct {
525532
noParent bool
526533
remoteParent bool

0 commit comments

Comments
 (0)