Skip to content

Commit

Permalink
trace: Add Span.AddLink method (#5032)
Browse files Browse the repository at this point in the history
  • Loading branch information
q-cheng committed Mar 28, 2024
1 parent 321219b commit 554282d
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

### Added

- Add `AddLink` method to the `Span` interface in `go.opentelemetry.io/otel/trace`. (#5032)

This comment has been minimized.

Copy link
@SOF3

SOF3 May 21, 2024

This change is actually a BC break.

This comment has been minimized.

Copy link
@dmathieu

dmathieu May 21, 2024

Member

The API interface may have additional method added to them without a breaking change, as you're expected to embed the proper struct in your implementation.

See https://pkg.go.dev/go.opentelemetry.io/otel/trace#hdr-API_Implementations

- Add `WithProxy` option in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#4906)
- Add `WithProxy` option in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlptracehttp`. (#4906)
- The `Enabled` method is added to the `Logger` interface in `go.opentelemetry.io/otel/log`.
Expand Down
13 changes: 13 additions & 0 deletions bridge/opentracing/internal/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ type MockEvent struct {
Attributes []attribute.KeyValue
}

type MockLink struct {
SpanContext trace.SpanContext
Attributes []attribute.KeyValue
}

type MockSpan struct {
embedded.Span

Expand All @@ -190,6 +195,7 @@ type MockSpan struct {
EndTime time.Time
ParentSpanID trace.SpanID
Events []MockEvent
Links []MockLink
}

var (
Expand Down Expand Up @@ -286,6 +292,13 @@ func (s *MockSpan) AddEvent(name string, o ...trace.EventOption) {
})
}

func (s *MockSpan) AddLink(link trace.Link) {
s.Links = append(s.Links, MockLink{
SpanContext: link.SpanContext,
Attributes: link.Attributes,
})
}

func (s *MockSpan) OverrideTracer(tracer trace.Tracer) {
s.officialTracer = tracer
}
Expand Down
3 changes: 3 additions & 0 deletions internal/global/trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ func (nonRecordingSpan) RecordError(error, ...trace.EventOption) {}
// AddEvent does nothing.
func (nonRecordingSpan) AddEvent(string, ...trace.EventOption) {}

// AddLink does nothing.
func (nonRecordingSpan) AddLink(trace.Link) {}

// SetName does nothing.
func (nonRecordingSpan) SetName(string) {}

Expand Down
5 changes: 4 additions & 1 deletion sdk/trace/span.go
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ func (s *recordingSpan) Resource() *resource.Resource {
return s.tracer.provider.resource
}

func (s *recordingSpan) addLink(link trace.Link) {
func (s *recordingSpan) AddLink(link trace.Link) {
if !s.IsRecording() || !link.SpanContext.IsValid() {
return
}
Expand Down Expand Up @@ -803,6 +803,9 @@ func (nonRecordingSpan) RecordError(error, ...trace.EventOption) {}
// AddEvent does nothing.
func (nonRecordingSpan) AddEvent(string, ...trace.EventOption) {}

// AddLink does nothing.
func (nonRecordingSpan) AddLink(trace.Link) {}

// SetName does nothing.
func (nonRecordingSpan) SetName(string) {}

Expand Down
78 changes: 78 additions & 0 deletions sdk/trace/trace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1976,3 +1976,81 @@ func TestEmptyRecordingSpanAttributes(t *testing.T) {
func TestEmptyRecordingSpanDroppedAttributes(t *testing.T) {
assert.Equal(t, 0, (&recordingSpan{}).DroppedAttributes())
}

func TestAddLinkWithInvalidSpanContext(t *testing.T) {
te := NewTestExporter()
sl := NewSpanLimits()
tp := NewTracerProvider(
WithSpanLimits(sl),
WithSyncer(te),
WithResource(resource.Empty()),
)
span := startSpan(tp, "AddSpanWithInvalidSpanContext")
inValidContext := trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID([16]byte{}),
SpanID: [8]byte{},
})
attrs := []attribute.KeyValue{{Key: "k", Value: attribute.StringValue("v")}}
span.AddLink(trace.Link{
SpanContext: inValidContext,
Attributes: attrs,
})

want := &snapshot{
name: "span0",
spanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: tid,
TraceFlags: 0x1,
}),
parent: sc.WithRemote(true),
links: nil,
spanKind: trace.SpanKindInternal,
instrumentationScope: instrumentation.Scope{Name: "AddSpanWithInvalidSpanContext"},
}
got, err := endSpan(te, span)
if err != nil {
t.Fatal(err)
}
if diff := cmpDiff(got, want); diff != "" {
t.Errorf("AddLinkWithInvalidSpanContext: -got +want %s", diff)
}
}

func TestAddLink(t *testing.T) {
te := NewTestExporter()
sl := NewSpanLimits()
tp := NewTracerProvider(
WithSpanLimits(sl),
WithSyncer(te),
WithResource(resource.Empty()),
)
attrs := []attribute.KeyValue{{Key: "k", Value: attribute.StringValue("v")}}
span := startSpan(tp, "AddSpan")

link := trace.Link{SpanContext: sc, Attributes: attrs}
span.AddLink(link)

want := &snapshot{
name: "span0",
spanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: tid,
TraceFlags: 0x1,
}),
parent: sc.WithRemote(true),
links: []Link{
{
SpanContext: sc,
Attributes: attrs,
},
},
spanKind: trace.SpanKindInternal,
instrumentationScope: instrumentation.Scope{Name: "AddSpan"},
}
got, err := endSpan(te, span)
if err != nil {
t.Fatal(err)
}
if diff := cmpDiff(got, want); diff != "" {
t.Errorf("AddLink: -got +want %s", diff)
}
}
2 changes: 1 addition & 1 deletion sdk/trace/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func (tr *tracer) newRecordingSpan(psc, sc trace.SpanContext, name string, sr Sa
}

for _, l := range config.Links() {
s.addLink(l)
s.AddLink(l)
}

s.SetAttributes(sr.Attributes...)
Expand Down
3 changes: 3 additions & 0 deletions trace/noop.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ func (noopSpan) RecordError(error, ...EventOption) {}
// AddEvent does nothing.
func (noopSpan) AddEvent(string, ...EventOption) {}

// AddLink does nothing.
func (noopSpan) AddLink(Link) {}

// SetName does nothing.
func (noopSpan) SetName(string) {}

Expand Down
3 changes: 3 additions & 0 deletions trace/noop/noop.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ func (Span) RecordError(error, ...trace.EventOption) {}
// AddEvent does nothing.
func (Span) AddEvent(string, ...trace.EventOption) {}

// AddLink does nothing.
func (Span) AddLink(trace.Link) {}

// SetName does nothing.
func (Span) SetName(string) {}

Expand Down
6 changes: 6 additions & 0 deletions trace/trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,12 @@ type Span interface {
// AddEvent adds an event with the provided name and options.
AddEvent(name string, options ...EventOption)

// AddLink adds a link.
// Adding links at span creation using WithLinks is preferred to calling AddLink
// later, for contexts that are available during span creation, because head
// sampling decisions can only consider information present during span creation.
AddLink(link Link)

// IsRecording returns the recording state of the Span. It will return
// true if the Span is active and events can be recorded.
IsRecording() bool
Expand Down

0 comments on commit 554282d

Please sign in to comment.