Skip to content

Commit cbcd4b1

Browse files
authored
Redefine ExportSpans of SpanExporter with ReadOnlySpan (#1873)
* Remove TODO from ReadOnlySpan interface * Remove the Tracer method from the ReadOnlySpan This is not required by the specification nor the use of this interface. * Remove IsRecording from the ReadOnlySpan interface A read-only span value does not need to know if updates to it will be recorded. It by definition cannot be updated so no point in communicating if an update would be recorded. * Document the ReadOnlySpan interface * Rename messageEvent* to just event* * Move the SpanSnapshot into its own file * Update ReadOnlySpan interface with meta info methods Add the DroppedAttributes, DroppedLinks, DroppedEvents, and ChildSpanCount methods to the interface to return additional information about the span not specified by the specification, but that we are already providing. * Add SpanStub to the sdk/trace/tracetest pkg * Redefine ExportSpans of SpanExporter with ReadOnlySpan * Rename SpanSnapshot to snapshot and purge docs * Remove Snapshot method from snapshot type This method is a hold-over from previous version of the ReadOnlySpan interface is not needed. * Update CHANGELOG with changes
1 parent c99d5e9 commit cbcd4b1

34 files changed

+1046
-675
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
2222
| 14 | Unavailable |
2323
| 15 | Data Loss |
2424
- The `Status` type was added to the `go.opentelemetry.io/otel/sdk/trace` package to represent the status of a span. (#1874)
25+
- The `SpanStub` type and its associated functions were added to the `go.opentelemetry.io/otel/sdk/trace/tracetest` package.
26+
This type can be used as a testing replacement for the `SpanSnapshot` that was removed from the `go.opentelemetry.io/otel/sdk/trace` package. (#1873)
2527

2628
### Changed
2729

@@ -34,6 +36,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
3436
- Renamed `CloudZoneKey` to `CloudAvailabilityZoneKey` in Resource semantic conventions according to spec. (#1871)
3537
- The `StatusCode` and `StatusMessage` methods of the `ReadOnlySpan` interface and the `Span` produced by the `go.opentelemetry.io/otel/sdk/trace` package have been replaced with a single `Status` method.
3638
This method returns the status of a span using the new `Status` type. (#1874)
39+
- The `ExportSpans` method of the`SpanExporter` interface type was updated to accept `ReadOnlySpan`s instead of the removed `SpanSnapshot`.
40+
This brings the export interface into compliance with the specification in that it now accepts an explicitly immutable type instead of just an implied one. (#1873)
3741
- Unembed `SpanContext` in `Link`. (#1877)
3842

3943
### Deprecated
@@ -42,6 +46,14 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
4246

4347
- Remove `resource.WithoutBuiltin()`. Use `resource.New()`. (#1810)
4448
- Unexported types `resource.FromEnv`, `resource.Host`, and `resource.TelemetrySDK`, Use the corresponding `With*()` to use individually. (#1810)
49+
- Removed the `Tracer` and `IsRecording` method from the `ReadOnlySpan` in the `go.opentelemetry.io/otel/sdk/trace`.
50+
The `Tracer` method is not a required to be included in this interface and given the mutable nature of the tracer that is associated with a span, this method is not appropriate.
51+
The `IsRecording` method returns if the span is recording or not.
52+
A read-only span value does not need to know if updates to it will be recorded or not.
53+
By definition, it cannot be updated so there is no point in communicating if an update is recorded. (#1873)
54+
- Removed the `SpanSnapshot` type from the `go.opentelemetry.io/otel/sdk/trace` package.
55+
The use of this type has been replaced with the use of the explicitly immutable `ReadOnlySpan` type.
56+
When a concrete representation of a read-only span is needed for testing, the newly added `SpanStub` in the `go.opentelemetry.io/otel/sdk/trace/tracetest` package should be used. (#1873)
4557

4658
### Fixed
4759

exporters/otlp/internal/otlptest/data.go

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"go.opentelemetry.io/otel/sdk/metric/aggregator/sum"
2929
"go.opentelemetry.io/otel/sdk/resource"
3030
tracesdk "go.opentelemetry.io/otel/sdk/trace"
31+
"go.opentelemetry.io/otel/sdk/trace/tracetest"
3132
"go.opentelemetry.io/otel/trace"
3233
)
3334

@@ -78,39 +79,40 @@ func (OneRecordCheckpointSet) ForEach(kindSelector exportmetric.ExportKindSelect
7879
return recordFunc(rec)
7980
}
8081

81-
// SingleSpanSnapshot returns a one-element slice with a snapshot. It
82+
// SingleReadOnlySpan returns a one-element slice with a read-only span. It
8283
// may be useful for testing driver's trace export.
83-
func SingleSpanSnapshot() []*tracesdk.SpanSnapshot {
84-
sd := &tracesdk.SpanSnapshot{
85-
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
86-
TraceID: trace.TraceID{2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4, 5, 6, 7, 8, 9},
87-
SpanID: trace.SpanID{3, 4, 5, 6, 7, 8, 9, 0},
88-
TraceFlags: trace.FlagsSampled,
89-
}),
90-
Parent: trace.NewSpanContext(trace.SpanContextConfig{
91-
TraceID: trace.TraceID{2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4, 5, 6, 7, 8, 9},
92-
SpanID: trace.SpanID{1, 2, 3, 4, 5, 6, 7, 8},
93-
TraceFlags: trace.FlagsSampled,
94-
}),
95-
SpanKind: trace.SpanKindInternal,
96-
Name: "foo",
97-
StartTime: time.Date(2020, time.December, 8, 20, 23, 0, 0, time.UTC),
98-
EndTime: time.Date(2020, time.December, 0, 20, 24, 0, 0, time.UTC),
99-
Attributes: []attribute.KeyValue{},
100-
MessageEvents: []tracesdk.Event{},
101-
Links: []trace.Link{},
102-
Status: tracesdk.Status{Code: codes.Ok},
103-
DroppedAttributeCount: 0,
104-
DroppedMessageEventCount: 0,
105-
DroppedLinkCount: 0,
106-
ChildSpanCount: 0,
107-
Resource: resource.NewWithAttributes(attribute.String("a", "b")),
108-
InstrumentationLibrary: instrumentation.Library{
109-
Name: "bar",
110-
Version: "0.0.0",
84+
func SingleReadOnlySpan() []tracesdk.ReadOnlySpan {
85+
return tracetest.SpanStubs{
86+
{
87+
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
88+
TraceID: trace.TraceID{2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4, 5, 6, 7, 8, 9},
89+
SpanID: trace.SpanID{3, 4, 5, 6, 7, 8, 9, 0},
90+
TraceFlags: trace.FlagsSampled,
91+
}),
92+
Parent: trace.NewSpanContext(trace.SpanContextConfig{
93+
TraceID: trace.TraceID{2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4, 5, 6, 7, 8, 9},
94+
SpanID: trace.SpanID{1, 2, 3, 4, 5, 6, 7, 8},
95+
TraceFlags: trace.FlagsSampled,
96+
}),
97+
SpanKind: trace.SpanKindInternal,
98+
Name: "foo",
99+
StartTime: time.Date(2020, time.December, 8, 20, 23, 0, 0, time.UTC),
100+
EndTime: time.Date(2020, time.December, 0, 20, 24, 0, 0, time.UTC),
101+
Attributes: []attribute.KeyValue{},
102+
Events: []tracesdk.Event{},
103+
Links: []trace.Link{},
104+
Status: tracesdk.Status{Code: codes.Ok},
105+
DroppedAttributes: 0,
106+
DroppedEvents: 0,
107+
DroppedLinks: 0,
108+
ChildSpanCount: 0,
109+
Resource: resource.NewWithAttributes(attribute.String("a", "b")),
110+
InstrumentationLibrary: instrumentation.Library{
111+
Name: "bar",
112+
Version: "0.0.0",
113+
},
111114
},
112-
}
113-
return []*tracesdk.SpanSnapshot{sd}
115+
}.Snapshots()
114116
}
115117

116118
// EmptyCheckpointSet is a checkpointer that has no records at all.

exporters/otlp/internal/transform/span.go

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ import (
2525
)
2626

2727
const (
28-
maxMessageEventsPerSpan = 128
28+
maxEventsPerSpan = 128
2929
)
3030

31-
// SpanData transforms a slice of SpanSnapshot into a slice of OTLP
31+
// Spans transforms a slice of OpenTelemetry spans into a slice of OTLP
3232
// ResourceSpans.
33-
func SpanData(sdl []*tracesdk.SpanSnapshot) []*tracepb.ResourceSpans {
33+
func Spans(sdl []tracesdk.ReadOnlySpan) []*tracepb.ResourceSpans {
3434
if len(sdl) == 0 {
3535
return nil
3636
}
@@ -49,16 +49,16 @@ func SpanData(sdl []*tracesdk.SpanSnapshot) []*tracepb.ResourceSpans {
4949
continue
5050
}
5151

52-
rKey := sd.Resource.Equivalent()
52+
rKey := sd.Resource().Equivalent()
5353
iKey := ilsKey{
5454
r: rKey,
55-
il: sd.InstrumentationLibrary,
55+
il: sd.InstrumentationLibrary(),
5656
}
5757
ils, iOk := ilsm[iKey]
5858
if !iOk {
5959
// Either the resource or instrumentation library were unknown.
6060
ils = &tracepb.InstrumentationLibrarySpans{
61-
InstrumentationLibrary: instrumentationLibrary(sd.InstrumentationLibrary),
61+
InstrumentationLibrary: instrumentationLibrary(sd.InstrumentationLibrary()),
6262
Spans: []*tracepb.Span{},
6363
}
6464
}
@@ -70,7 +70,7 @@ func SpanData(sdl []*tracesdk.SpanSnapshot) []*tracepb.ResourceSpans {
7070
resources++
7171
// The resource was unknown.
7272
rs = &tracepb.ResourceSpans{
73-
Resource: Resource(sd.Resource),
73+
Resource: Resource(sd.Resource()),
7474
InstrumentationLibrarySpans: []*tracepb.InstrumentationLibrarySpans{ils},
7575
}
7676
rsm[rKey] = rs
@@ -96,32 +96,32 @@ func SpanData(sdl []*tracesdk.SpanSnapshot) []*tracepb.ResourceSpans {
9696
}
9797

9898
// span transforms a Span into an OTLP span.
99-
func span(sd *tracesdk.SpanSnapshot) *tracepb.Span {
99+
func span(sd tracesdk.ReadOnlySpan) *tracepb.Span {
100100
if sd == nil {
101101
return nil
102102
}
103103

104-
tid := sd.SpanContext.TraceID()
105-
sid := sd.SpanContext.SpanID()
104+
tid := sd.SpanContext().TraceID()
105+
sid := sd.SpanContext().SpanID()
106106

107107
s := &tracepb.Span{
108108
TraceId: tid[:],
109109
SpanId: sid[:],
110-
TraceState: sd.SpanContext.TraceState().String(),
111-
Status: status(sd.Status.Code, sd.Status.Description),
112-
StartTimeUnixNano: uint64(sd.StartTime.UnixNano()),
113-
EndTimeUnixNano: uint64(sd.EndTime.UnixNano()),
114-
Links: links(sd.Links),
115-
Kind: spanKind(sd.SpanKind),
116-
Name: sd.Name,
117-
Attributes: Attributes(sd.Attributes),
118-
Events: spanEvents(sd.MessageEvents),
119-
DroppedAttributesCount: uint32(sd.DroppedAttributeCount),
120-
DroppedEventsCount: uint32(sd.DroppedMessageEventCount),
121-
DroppedLinksCount: uint32(sd.DroppedLinkCount),
110+
TraceState: sd.SpanContext().TraceState().String(),
111+
Status: status(sd.Status().Code, sd.Status().Description),
112+
StartTimeUnixNano: uint64(sd.StartTime().UnixNano()),
113+
EndTimeUnixNano: uint64(sd.EndTime().UnixNano()),
114+
Links: links(sd.Links()),
115+
Kind: spanKind(sd.SpanKind()),
116+
Name: sd.Name(),
117+
Attributes: Attributes(sd.Attributes()),
118+
Events: spanEvents(sd.Events()),
119+
DroppedAttributesCount: uint32(sd.DroppedAttributes()),
120+
DroppedEventsCount: uint32(sd.DroppedEvents()),
121+
DroppedLinksCount: uint32(sd.DroppedLinks()),
122122
}
123123

124-
if psid := sd.Parent.SpanID(); psid.IsValid() {
124+
if psid := sd.Parent().SpanID(); psid.IsValid() {
125125
s.ParentSpanId = psid[:]
126126
}
127127

@@ -174,18 +174,18 @@ func spanEvents(es []tracesdk.Event) []*tracepb.Span_Event {
174174
}
175175

176176
evCount := len(es)
177-
if evCount > maxMessageEventsPerSpan {
178-
evCount = maxMessageEventsPerSpan
177+
if evCount > maxEventsPerSpan {
178+
evCount = maxEventsPerSpan
179179
}
180180
events := make([]*tracepb.Span_Event, 0, evCount)
181-
messageEvents := 0
181+
nEvents := 0
182182

183183
// Transform message events
184184
for _, e := range es {
185-
if messageEvents >= maxMessageEventsPerSpan {
185+
if nEvents >= maxEventsPerSpan {
186186
break
187187
}
188-
messageEvents++
188+
nEvents++
189189
events = append(events,
190190
&tracepb.Span_Event{
191191
Name: e.Name,

exporters/otlp/internal/transform/span_test.go

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"go.opentelemetry.io/otel/sdk/instrumentation"
3333
"go.opentelemetry.io/otel/sdk/resource"
3434
tracesdk "go.opentelemetry.io/otel/sdk/trace"
35+
"go.opentelemetry.io/otel/sdk/trace/tracetest"
3536
)
3637

3738
func TestSpanKind(t *testing.T) {
@@ -101,15 +102,15 @@ func TestSpanEvent(t *testing.T) {
101102
}
102103

103104
func TestExcessiveSpanEvents(t *testing.T) {
104-
e := make([]tracesdk.Event, maxMessageEventsPerSpan+1)
105-
for i := 0; i < maxMessageEventsPerSpan+1; i++ {
105+
e := make([]tracesdk.Event, maxEventsPerSpan+1)
106+
for i := 0; i < maxEventsPerSpan+1; i++ {
106107
e[i] = tracesdk.Event{Name: strconv.Itoa(i)}
107108
}
108-
assert.Len(t, e, maxMessageEventsPerSpan+1)
109+
assert.Len(t, e, maxEventsPerSpan+1)
109110
got := spanEvents(e)
110-
assert.Len(t, got, maxMessageEventsPerSpan)
111+
assert.Len(t, got, maxEventsPerSpan)
111112
// Ensure the drop order.
112-
assert.Equal(t, strconv.Itoa(maxMessageEventsPerSpan-1), got[len(got)-1].Name)
113+
assert.Equal(t, strconv.Itoa(maxEventsPerSpan-1), got[len(got)-1].Name)
113114
}
114115

115116
func TestNilLinks(t *testing.T) {
@@ -185,11 +186,11 @@ func TestNilSpan(t *testing.T) {
185186
}
186187

187188
func TestNilSpanData(t *testing.T) {
188-
assert.Nil(t, SpanData(nil))
189+
assert.Nil(t, Spans(nil))
189190
}
190191

191192
func TestEmptySpanData(t *testing.T) {
192-
assert.Nil(t, SpanData(nil))
193+
assert.Nil(t, Spans(nil))
193194
}
194195

195196
func TestSpanData(t *testing.T) {
@@ -199,7 +200,7 @@ func TestSpanData(t *testing.T) {
199200
startTime := time.Unix(1585674086, 1234)
200201
endTime := startTime.Add(10 * time.Second)
201202
traceState, _ := trace.TraceStateFromKeyValues(attribute.String("key1", "val1"), attribute.String("key2", "val2"))
202-
spanData := &tracesdk.SpanSnapshot{
203+
spanData := tracetest.SpanStub{
203204
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
204205
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
205206
SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
@@ -215,15 +216,15 @@ func TestSpanData(t *testing.T) {
215216
Name: "span data to span data",
216217
StartTime: startTime,
217218
EndTime: endTime,
218-
MessageEvents: []tracesdk.Event{
219+
Events: []tracesdk.Event{
219220
{Time: startTime,
220221
Attributes: []attribute.KeyValue{
221222
attribute.Int64("CompressedByteSize", 512),
222223
},
223224
},
224225
{Time: endTime,
225226
Attributes: []attribute.KeyValue{
226-
attribute.String("MessageEventType", "Recv"),
227+
attribute.String("EventType", "Recv"),
227228
},
228229
},
229230
},
@@ -256,10 +257,10 @@ func TestSpanData(t *testing.T) {
256257
Attributes: []attribute.KeyValue{
257258
attribute.Int64("timeout_ns", 12e9),
258259
},
259-
DroppedAttributeCount: 1,
260-
DroppedMessageEventCount: 2,
261-
DroppedLinkCount: 3,
262-
Resource: resource.NewWithAttributes(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5)),
260+
DroppedAttributes: 1,
261+
DroppedEvents: 2,
262+
DroppedLinks: 3,
263+
Resource: resource.NewWithAttributes(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5)),
263264
InstrumentationLibrary: instrumentation.Library{
264265
Name: "go.opentelemetry.io/test/otel",
265266
Version: "v0.0.1",
@@ -279,15 +280,15 @@ func TestSpanData(t *testing.T) {
279280
StartTimeUnixNano: uint64(startTime.UnixNano()),
280281
EndTimeUnixNano: uint64(endTime.UnixNano()),
281282
Status: status(spanData.Status.Code, spanData.Status.Description),
282-
Events: spanEvents(spanData.MessageEvents),
283+
Events: spanEvents(spanData.Events),
283284
Links: links(spanData.Links),
284285
Attributes: Attributes(spanData.Attributes),
285286
DroppedAttributesCount: 1,
286287
DroppedEventsCount: 2,
287288
DroppedLinksCount: 3,
288289
}
289290

290-
got := SpanData([]*tracesdk.SpanSnapshot{spanData})
291+
got := Spans(tracetest.SpanStubs{spanData}.Snapshots())
291292
require.Len(t, got, 1)
292293

293294
assert.Equal(t, got[0].GetResource(), Resource(spanData.Resource))
@@ -304,7 +305,7 @@ func TestSpanData(t *testing.T) {
304305

305306
// Empty parent span ID should be treated as root span.
306307
func TestRootSpanData(t *testing.T) {
307-
sd := SpanData([]*tracesdk.SpanSnapshot{{}})
308+
sd := Spans(tracetest.SpanStubs{{}}.Snapshots())
308309
require.Len(t, sd, 1)
309310
rs := sd[0]
310311
got := rs.GetInstrumentationLibrarySpans()[0].GetSpans()[0].GetParentSpanId()
@@ -314,5 +315,5 @@ func TestRootSpanData(t *testing.T) {
314315
}
315316

316317
func TestSpanDataNilResource(t *testing.T) {
317-
assert.NotPanics(t, func() { SpanData([]*tracesdk.SpanSnapshot{{}}) })
318+
assert.NotPanics(t, func() { Spans(tracetest.SpanStubs{{}}.Snapshots()) })
318319
}

exporters/otlp/otlp.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,10 @@ func (e *Exporter) ExportKindFor(desc *metric.Descriptor, kind aggregation.Kind)
129129
return e.cfg.exportKindSelector.ExportKindFor(desc, kind)
130130
}
131131

132-
// ExportSpans transforms and batches trace SpanSnapshots into OTLP Trace and
132+
// ExportSpans transforms and batches OpenTelemetry spans into OTLP Trace and
133133
// transmits them to the configured collector.
134-
func (e *Exporter) ExportSpans(ctx context.Context, ss []*tracesdk.SpanSnapshot) error {
135-
return e.driver.ExportTraces(ctx, ss)
134+
func (e *Exporter) ExportSpans(ctx context.Context, spans []tracesdk.ReadOnlySpan) error {
135+
return e.driver.ExportTraces(ctx, spans)
136136
}
137137

138138
// NewExportPipeline sets up a complete export pipeline

0 commit comments

Comments
 (0)