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

Feat/bridge support text map #2911

Merged
merged 20 commits into from Jul 6, 2022
Merged
Show file tree
Hide file tree
Changes from 4 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
31 changes: 25 additions & 6 deletions bridge/opentracing/bridge.go
Expand Up @@ -25,6 +25,7 @@ import (
otext "github.com/opentracing/opentracing-go/ext"
otlog "github.com/opentracing/opentracing-go/log"

"github.com/opentracing/opentracing-go"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/baggage"
Expand Down Expand Up @@ -666,15 +667,33 @@ func (t *BridgeTracer) Inject(sm ot.SpanContext, format interface{}, carrier int
//
// Currently only the HTTPHeaders format is supported.
func (t *BridgeTracer) Extract(format interface{}, carrier interface{}) (ot.SpanContext, error) {
if builtinFormat, ok := format.(ot.BuiltinFormat); !ok || builtinFormat != ot.HTTPHeaders {
builtinFormat, ok := format.(ot.BuiltinFormat)
if !ok {
return nil, ot.ErrUnsupportedFormat
}
hhcarrier, ok := carrier.(ot.HTTPHeadersCarrier)
if !ok {
return nil, ot.ErrInvalidCarrier

var textCarrier propagation.TextMapCarrier

switch builtinFormat {
case ot.HTTPHeaders:
hhcarrier, ok := carrier.(ot.HTTPHeadersCarrier)
if !ok {
return nil, ot.ErrInvalidCarrier
}

textCarrier = propagation.HeaderCarrier(hhcarrier)
case ot.TextMap:
if textCarrier, ok = carrier.(propagation.TextMapCarrier); !ok {
var err error
if textCarrier, err = newTextMapWrapperForExtract(carrier); err != nil {
return nil, err
Aneurysm9 marked this conversation as resolved.
Show resolved Hide resolved
}
}
default:
return nil, ot.ErrUnsupportedFormat
}
header := http.Header(hhcarrier)
ctx := t.getPropagator().Extract(context.Background(), propagation.HeaderCarrier(header))

ctx := t.getPropagator().Extract(context.Background(), textCarrier)
bag := baggage.FromContext(ctx)
bridgeSC := &bridgeSpanContext{
bag: bag,
Expand Down
292 changes: 292 additions & 0 deletions bridge/opentracing/bridge_test.go
@@ -0,0 +1,292 @@
package opentracing

import (
"context"
"errors"
ot "github.com/opentracing/opentracing-go"
"github.com/stretchr/testify/assert"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace"
"strings"
"testing"
)

type testOnlyTextMapReader struct {
}

func newTestOnlyTextMapReader() *testOnlyTextMapReader {
return &testOnlyTextMapReader{}
}

func (t *testOnlyTextMapReader) ForeachKey(handler func(key string, val string) error) error {
_ = handler("key1", "val1")
_ = handler("key2", "val2")

return nil
}

type testOnlyTextMapWriter struct {
m map[string]string
}

func newTestOnlyTextMapWriter() *testOnlyTextMapWriter {
return &testOnlyTextMapWriter{m: map[string]string{}}
}

func (t *testOnlyTextMapWriter) Set(key, val string) {
t.m[key] = val

return
}

type testTextMapReaderAndWriter struct {
*testOnlyTextMapReader
*testOnlyTextMapWriter
}

func newTestTextMapReaderAndWriter() *testTextMapReaderAndWriter {
return &testTextMapReaderAndWriter{
testOnlyTextMapReader: newTestOnlyTextMapReader(),
testOnlyTextMapWriter: newTestOnlyTextMapWriter(),
}
}

func TestTextMapWrapper_New(t *testing.T) {
_, err := newTextMapWrapperForExtract(newTestOnlyTextMapReader())
assert.NoError(t, err)

_, err = newTextMapWrapperForExtract(newTestOnlyTextMapWriter())
assert.True(t, errors.Is(err, ot.ErrInvalidCarrier))

_, err = newTextMapWrapperForExtract(newTestTextMapReaderAndWriter())
assert.NoError(t, err)

_, err = newTextMapWrapperForInject(newTestOnlyTextMapWriter())
assert.NoError(t, err)

_, err = newTextMapWrapperForInject(newTestOnlyTextMapReader())
assert.True(t, errors.Is(err, ot.ErrInvalidCarrier))

_, err = newTextMapWrapperForInject(newTestTextMapReaderAndWriter())
assert.NoError(t, err)
}

func TestTextMapWrapper_action(t *testing.T) {
testExtractFunc := func(carrier propagation.TextMapCarrier) {
assert.Equal(t, carrier.Get("key1"), "val1")
assert.Equal(t, carrier.Get("key2"), "val2")

str := carrier.Keys()
assert.Len(t, str, 2)
assert.Contains(t, str, "key1", "key2")
}

testInjectFunc := func(carrier propagation.TextMapCarrier) {
carrier.Set("key1", "val1")
carrier.Set("key2", "val2")

wrap, ok := carrier.(*textMapWrapper)
assert.True(t, ok)

writer, ok := wrap.TextMapWriter.(*testOnlyTextMapWriter)
if ok {
assert.Contains(t, writer.m, "key1", "key2", "val1", "val2")
return
}

writer2, ok := wrap.TextMapWriter.(*testTextMapReaderAndWriter)
assert.True(t, ok)
assert.Contains(t, writer2.m, "key1", "key2", "val1", "val2")
}

onlyWriter, err := newTextMapWrapperForExtract(newTestOnlyTextMapReader())
assert.NoError(t, err)
testExtractFunc(onlyWriter)

onlyReader, err := newTextMapWrapperForInject(&testOnlyTextMapWriter{m: map[string]string{}})
assert.NoError(t, err)
testInjectFunc(onlyReader)

both, err := newTextMapWrapperForExtract(newTestTextMapReaderAndWriter())
assert.NoError(t, err)
testExtractFunc(both)

both, err = newTextMapWrapperForInject(newTestTextMapReaderAndWriter())
assert.NoError(t, err)
testInjectFunc(both)
}

var (
testHeader = "test-trace-id"
traceID trace.TraceID = [16]byte{byte(10)}
spanID trace.SpanID = [8]byte{byte(11)}
)

type testTextMapPropagator struct {
}

func (t testTextMapPropagator) Inject(ctx context.Context, carrier propagation.TextMapCarrier) {

carrier.Set(testHeader, strings.Join([]string{traceID.String(), spanID.String()}, ":"))
}

func (t testTextMapPropagator) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context {
traces := carrier.Get(testHeader)

str := strings.Split(traces, ":")
if len(str) != 2 {
return ctx
}

var (
traceID, _ = trace.TraceIDFromHex(str[0])
spanID, _ = trace.SpanIDFromHex(str[1])
sc = trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
})
)

return trace.ContextWithRemoteSpanContext(ctx, sc)
}

func (t testTextMapPropagator) Fields() []string {
return []string{"test"}
}

// textMapCarrier Implemented propagation.TextMapCarrier interface
type textMapCarrier struct {
m map[string]string
}

func newTextCarrier() *textMapCarrier {
return &textMapCarrier{m: map[string]string{}}
}

func (t *textMapCarrier) Get(key string) string {
return t.m[key]
}

func (t *textMapCarrier) Set(key string, value string) {
t.m[key] = value
}

func (t *textMapCarrier) Keys() []string {
str := make([]string, 0, len(t.m))

for key := range t.m {
str = append(str, key)
}

return str
}

// opentracingTextMap Implemented opentracing.TextMapReader and opentracing.TextMapWriter interface
type opentracingTextMapCarrier struct {
m map[string]string
}

func newOpentracingTextMapCarrier() *opentracingTextMapCarrier {
return &opentracingTextMapCarrier{m: map[string]string{}}
}

func (o *opentracingTextMapCarrier) Set(key, val string) {
o.m[key] = val
}

func (o *opentracingTextMapCarrier) ForeachKey(handler func(key string, val string) error) error {
for key, val := range o.m {
if err := handler(key, val); err != nil {
return err
}
}

return nil
}

// testTextMapReader only implemented opentracing.TextMapReader interface
type testTextMapReader struct {
m *map[string]string
}

func newTestTextMapReader(m *map[string]string) *testTextMapReader {
return &testTextMapReader{m: m}
}

func (t *testTextMapReader) ForeachKey(handler func(key string, val string) error) error {
for key, val := range *t.m {
if err := handler(key, val); err != nil {
return err
}
}

return nil
}

// testTextMapWriter only implemented opentracing.TextMapWriter interface
type testTextMapWriter struct {
m *map[string]string
}

func newTestTextMapWriter(m *map[string]string) *testTextMapWriter {
return &testTextMapWriter{m: m}
}

func (t *testTextMapWriter) Set(key, val string) {
(*t.m)[key] = val
}

func TestBridgeTracer_ExtractAndInject(t *testing.T) {
bridge := NewBridgeTracer()
bridge.SetTextMapPropagator(new(testTextMapPropagator))

tmc := newTextCarrier()
otmc := newOpentracingTextMapCarrier()
shareMap := map[string]string{}

testCases := []struct {
name string
carrierType ot.BuiltinFormat
extractCarrier interface{}
injectCarrier interface{}
}{
{
name: "support for propagation.TextMapCarrier",
carrierType: ot.TextMap,
extractCarrier: tmc,
injectCarrier: tmc,
},
{
name: "support for opentracing.TextMapReader and opentracing.TextMapWriter",
carrierType: ot.TextMap,
extractCarrier: otmc,
injectCarrier: otmc,
},
{
name: "support for opentracing.TextMapReader and opentracing.TextMapWriter,non-same instance",
carrierType: ot.TextMap,
extractCarrier: newTestTextMapReader(&shareMap),
injectCarrier: newTestTextMapWriter(&shareMap),
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := bridge.Inject(newBridgeSpanContext(trace.NewSpanContext(trace.SpanContextConfig{
TraceID: [16]byte{byte(1)},
SpanID: [8]byte{byte(2)},
}), nil), tc.carrierType, tc.injectCarrier)
assert.NoError(t, err)

spanContext, err := bridge.Extract(tc.carrierType, tc.extractCarrier)
assert.NoError(t, err)

bsc, ok := spanContext.(*bridgeSpanContext)
assert.True(t, ok)

assert.Equal(t, spanID.String(), bsc.otelSpanContext.SpanID().String())
assert.Equal(t, traceID.String(), bsc.otelSpanContext.TraceID().String())
})
}

}
1 change: 1 addition & 0 deletions bridge/opentracing/go.mod
Expand Up @@ -6,6 +6,7 @@ replace go.opentelemetry.io/otel => ../..

require (
github.com/opentracing/opentracing-go v1.2.0
github.com/stretchr/testify v1.7.1
tttoad marked this conversation as resolved.
Show resolved Hide resolved
go.opentelemetry.io/otel v1.7.0
go.opentelemetry.io/otel/trace v1.7.0
)
Expand Down
1 change: 1 addition & 0 deletions bridge/opentracing/go.sum
Expand Up @@ -15,6 +15,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=