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

[OpenTracing bridge] Support setting span kind tag after the creation of span #3997

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ See our [versioning policy](VERSIONING.md) for more information about these stab
- The `Observer.ObserveInt64` method now accepts `...ObserveOption`
- The `Observer.ObserveFloat64` method now accepts `...ObserveOption`
- Move global metric back to `go.opentelemetry.io/otel/metric/global` from `go.opentelemetry.io/otel`. (#3986)
- Allow to set span kind tag after a span is created in OpenTracing bridge (#3997).

### Fixed

Expand Down
10 changes: 9 additions & 1 deletion bridge/opentracing/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,15 @@ func (s *bridgeSpan) SetOperationName(operationName string) ot.Span {
func (s *bridgeSpan) SetTag(key string, value interface{}) ot.Span {
switch key {
case string(otext.SpanKind):
// TODO: Should we ignore it?
type readSpanKindSpan interface {
SpanKind() trace.SpanKind
}
// only add span kind tag when otel span kind is unset or bridge default (internal)
if span, ok := s.otelSpan.(readSpanKindSpan); ok {
if span.SpanKind() == trace.SpanKindUnspecified || span.SpanKind() == trace.SpanKindInternal {
s.otelSpan.SetAttributes(otTagToOTelAttr(key, value))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will cause the span.kind to be duplicated at the exporter level. This will set it in the attributes, but the recordingSpan.spanKind will also be set to the default internal - both of these seem to get sent via the exporter. I've tested this with go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc sending to Jaeger collector.

}
}
case string(otext.Error):
if b, ok := value.(bool); ok && b {
s.otelSpan.SetStatus(codes.Error, "")
Expand Down
58 changes: 57 additions & 1 deletion bridge/opentracing/bridge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ func Test_otTagsToOTelAttributesKindAndError(t *testing.T) {
b, _ := NewTracerPair(tracer)

s := b.StartSpan(tc.name, tc.opt...)
assert.Equal(t, s.(*bridgeSpan).otelSpan.(*internal.MockSpan).SpanKind, tc.expected)
assert.Equal(t, s.(*bridgeSpan).otelSpan.(*internal.MockSpan).SpanKind(), tc.expected)
})
}
}
Expand Down Expand Up @@ -576,3 +576,59 @@ func TestBridgeSpanContextPromotedMethods(t *testing.T) {
assert.True(t, spanContext.(spanContextProvider).HasTraceID())
})
}

func TestBridgeSpan_SetSpanKindTag(t *testing.T) {
testCases := []struct {
name string
inputSpanKind interface{}
setSpanKind interface{}
expectedAttributes []attribute.KeyValue
}{
{
name: "set span kind tag to client for OTel span without span kind specified",
inputSpanKind: nil,
setSpanKind: ext.SpanKindRPCClientEnum,
expectedAttributes: []attribute.KeyValue{attribute.String(string(ext.SpanKind), string(ext.SpanKindRPCClientEnum))},
},
{
name: "set span kind tag to server for OTel span without span kind specified",
inputSpanKind: nil,
setSpanKind: ext.SpanKindRPCServerEnum,
expectedAttributes: []attribute.KeyValue{attribute.String(string(ext.SpanKind), string(ext.SpanKindRPCServerEnum))},
},
{
name: "allow to set span kind tag to non-standard span kind",
inputSpanKind: nil,
setSpanKind: "non-standard span kind",
expectedAttributes: []attribute.KeyValue{attribute.String(string(ext.SpanKind), "non-standard span kind")},
},
{
name: "set span kind tag to client for OTel span with span kind specified",
inputSpanKind: ext.SpanKindRPCServerEnum,
setSpanKind: ext.SpanKindRPCClientEnum,
expectedAttributes: nil,
},
{
name: "set span kind tag to server for OTel span with span kind specified",
inputSpanKind: ext.SpanKindRPCClientEnum,
setSpanKind: ext.SpanKindRPCServerEnum,
expectedAttributes: nil,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
otelMockTracer := internal.NewMockTracer()
bridgeTracer, _ := NewTracerPair(otelMockTracer)
startOption := ot.Tags{}
if tc.inputSpanKind != nil {
startOption = ot.Tags{string(ext.SpanKind): tc.inputSpanKind}
}
span := bridgeTracer.StartSpan("abc", startOption)
span.SetTag(string(ext.SpanKind), tc.setSpanKind)
mockSpan := span.(*bridgeSpan).otelSpan.(*internal.MockSpan)

assert.Equal(t, tc.expectedAttributes, mockSpan.Attributes)
})
}
}
8 changes: 6 additions & 2 deletions bridge/opentracing/internal/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func (t *MockTracer) Start(ctx context.Context, name string, opts ...trace.SpanS
EndTime: time.Time{},
ParentSpanID: t.getParentSpanID(ctx, &config),
Events: nil,
SpanKind: trace.ValidateSpanKind(config.SpanKind()),
spanKind: trace.ValidateSpanKind(config.SpanKind()),
}
if !migration.SkipContextSetup(ctx) {
ctx = trace.ContextWithSpan(ctx, span)
Expand Down Expand Up @@ -185,7 +185,7 @@ type MockSpan struct {
mockTracer *MockTracer
officialTracer trace.Tracer
spanContext trace.SpanContext
SpanKind trace.SpanKind
spanKind trace.SpanKind
recording bool

Attributes []attribute.KeyValue
Expand Down Expand Up @@ -292,3 +292,7 @@ func (s *MockSpan) OverrideTracer(tracer trace.Tracer) {
}

func (s *MockSpan) TracerProvider() trace.TracerProvider { return trace.NewNoopTracerProvider() }

func (s *MockSpan) SpanKind() trace.SpanKind {
return s.spanKind
}
4 changes: 2 additions & 2 deletions bridge/opentracing/mix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -583,8 +583,8 @@ func checkTraceAndSpans(t *testing.T, tracer *internal.MockTracer, expectedTrace
if span.ParentSpanID != expectedParentSpanID {
t.Errorf("Expected finished span %d (span ID: %d) to have parent span ID %d, but got %d", idx, sctx.SpanID(), expectedParentSpanID, span.ParentSpanID)
}
if span.SpanKind != sks[span.SpanContext().SpanID()] {
t.Errorf("Expected finished span %d (span ID: %d) to have span.kind to be '%v' but was '%v'", idx, sctx.SpanID(), sks[span.SpanContext().SpanID()], span.SpanKind)
if span.SpanKind() != sks[span.SpanContext().SpanID()] {
t.Errorf("Expected finished span %d (span ID: %d) to have span.kind to be '%v' but was '%v'", idx, sctx.SpanID(), sks[span.SpanContext().SpanID()], span.SpanKind())
}
}
}
Expand Down