Skip to content

Commit

Permalink
Add Keys() method to propagation.TextMapCarrier (open-telemetry#1544)
Browse files Browse the repository at this point in the history
...and propagation.HeaderCarrier to adapt http.Header to this interface.

Co-authored-by: Tyler Yahn <[email protected]>
  • Loading branch information
punya and MrAlias authored Feb 17, 2021
1 parent 0b1a1c7 commit 3bce9c9
Show file tree
Hide file tree
Showing 10 changed files with 68 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Added

- Added `resource.Default()` for use with meter and tracer providers. (#1507)
- Added `Keys()` method to `propagation.TextMapCarrier` and `propagation.HeaderCarrier` to adapt `http.Header` to this interface. (#1544)

## [0.17.0] - 2020-02-12

Expand Down
4 changes: 2 additions & 2 deletions bridge/opentracing/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ func (t *BridgeTracer) Inject(sm ot.SpanContext, format interface{}, carrier int
}
ctx := trace.ContextWithSpan(context.Background(), fs)
ctx = baggage.ContextWithMap(ctx, bridgeSC.baggageItems)
t.getPropagator().Inject(ctx, header)
t.getPropagator().Inject(ctx, propagation.HeaderCarrier(header))
return nil
}

Expand All @@ -654,7 +654,7 @@ func (t *BridgeTracer) Extract(format interface{}, carrier interface{}) (ot.Span
return nil, ot.ErrInvalidCarrier
}
header := http.Header(hhcarrier)
ctx := t.getPropagator().Extract(context.Background(), header)
ctx := t.getPropagator().Extract(context.Background(), propagation.HeaderCarrier(header))
baggage := baggage.MapFromContext(ctx)
otelSC, _, _ := otelparent.GetSpanContextAndLinks(ctx, false)
bridgeSC := &bridgeSpanContext{
Expand Down
12 changes: 12 additions & 0 deletions oteltest/text_map_propagator.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ func NewTextMapCarrier(data map[string]string) *TextMapCarrier {
return &TextMapCarrier{data: copied}
}

// Keys returns the keys for which this carrier has a value.
func (c *TextMapCarrier) Keys() []string {
c.mtx.Lock()
defer c.mtx.Unlock()

result := make([]string, 0, len(c.data))
for k := range c.data {
result = append(result, k)
}
return result
}

// Get returns the value associated with the passed key.
func (c *TextMapCarrier) Get(key string) string {
c.mtx.Lock()
Expand Down
9 changes: 9 additions & 0 deletions oteltest/text_map_propagator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,22 @@ package oteltest

import (
"context"
"reflect"
"testing"
)

var (
key, value = "test", "true"
)

func TestTextMapCarrierKeys(t *testing.T) {
tmc := NewTextMapCarrier(map[string]string{key: value})
expected, actual := []string{key}, tmc.Keys()
if !reflect.DeepEqual(actual, expected) {
t.Errorf("expected tmc.Keys() to be %v but it was %v", expected, actual)
}
}

func TestTextMapCarrierGet(t *testing.T) {
tmc := NewTextMapCarrier(map[string]string{key: value})
tmc.GotN(t, 0)
Expand Down
6 changes: 3 additions & 3 deletions propagation/baggage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func TestExtractValidBaggageFromHTTPReq(t *testing.T) {
req.Header.Set("baggage", tt.header)

ctx := context.Background()
ctx = prop.Extract(ctx, req.Header)
ctx = prop.Extract(ctx, propagation.HeaderCarrier(req.Header))
gotBaggage := baggage.MapFromContext(ctx)
wantBaggage := baggage.NewMap(baggage.MapUpdate{MultiKV: tt.wantKVs})
if gotBaggage.Len() != wantBaggage.Len() {
Expand Down Expand Up @@ -152,7 +152,7 @@ func TestExtractInvalidDistributedContextFromHTTPReq(t *testing.T) {

ctx := baggage.NewContext(context.Background(), tt.hasKVs...)
wantBaggage := baggage.MapFromContext(ctx)
ctx = prop.Extract(ctx, req.Header)
ctx = prop.Extract(ctx, propagation.HeaderCarrier(req.Header))
gotBaggage := baggage.MapFromContext(ctx)
if gotBaggage.Len() != wantBaggage.Len() {
t.Errorf(
Expand Down Expand Up @@ -218,7 +218,7 @@ func TestInjectBaggageToHTTPReq(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
req, _ := http.NewRequest("GET", "http://example.com", nil)
ctx := baggage.ContextWithMap(context.Background(), baggage.NewMap(baggage.MapUpdate{MultiKV: tt.kvs}))
propagator.Inject(ctx, req.Header)
propagator.Inject(ctx, propagation.HeaderCarrier(req.Header))

gotHeader := req.Header.Get("baggage")
wantedLen := len(strings.Join(tt.wantInHeader, ","))
Expand Down
29 changes: 28 additions & 1 deletion propagation/propagation.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,41 @@

package propagation // import "go.opentelemetry.io/otel/propagation"

import "context"
import (
"context"
"net/http"
)

// TextMapCarrier is the storage medium used by a TextMapPropagator.
type TextMapCarrier interface {
// Get returns the value associated with the passed key.
Get(key string) string
// Set stores the key-value pair.
Set(key string, value string)
// Keys lists the keys stored in this carrier.
Keys() []string
}

// HeaderCarrier adapts http.Header to satisfy the TextMapCarrier interface.
type HeaderCarrier http.Header

// Get returns the value associated with the passed key.
func (hc HeaderCarrier) Get(key string) string {
return http.Header(hc).Get(key)
}

// Set stores the key-value pair.
func (hc HeaderCarrier) Set(key string, value string) {
http.Header(hc).Set(key, value)
}

// Keys lists the keys stored in this carrier.
func (hc HeaderCarrier) Keys() []string {
keys := make([]string, 0, len(hc))
for k := range hc {
keys = append(keys, k)
}
return keys
}

// TextMapPropagator propagates cross-cutting concerns as key-value text
Expand Down
2 changes: 2 additions & 0 deletions propagation/propagation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ var (

type carrier []string

func (c *carrier) Keys() []string { return nil }

func (c *carrier) Get(string) string { return "" }

func (c *carrier) Set(setter, _ string) {
Expand Down
4 changes: 4 additions & 0 deletions propagation/propagators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ type nilCarrier struct{}

var _ propagation.TextMapCarrier = nilCarrier{}

func (nilCarrier) Keys() []string {
return nil
}

func (nilCarrier) Get(key string) string {
return ""
}
Expand Down
4 changes: 2 additions & 2 deletions propagation/trace_context_benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func BenchmarkInject(b *testing.B) {
req, _ := http.NewRequest("GET", "http://example.com", nil)
b.ResetTimer()
for i := 0; i < b.N; i++ {
t.Inject(ctx, req.Header)
t.Inject(ctx, propagation.HeaderCarrier(req.Header))
}
})
}
Expand Down Expand Up @@ -66,7 +66,7 @@ func BenchmarkExtract(b *testing.B) {
ctx := context.Background()
b.ResetTimer()
for i := 0; i < b.N; i++ {
propagator.Extract(ctx, req.Header)
propagator.Extract(ctx, propagation.HeaderCarrier(req.Header))
}
})
}
Expand Down
10 changes: 5 additions & 5 deletions propagation/trace_context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func TestExtractValidTraceContextFromHTTPReq(t *testing.T) {
req.Header.Set("traceparent", tt.header)

ctx := context.Background()
ctx = prop.Extract(ctx, req.Header)
ctx = prop.Extract(ctx, propagation.HeaderCarrier(req.Header))
gotSc := trace.RemoteSpanContextFromContext(ctx)
if diff := cmp.Diff(gotSc, tt.wantSc, cmp.AllowUnexported(trace.TraceState{})); diff != "" {
t.Errorf("Extract Tracecontext: %s: -got +want %s", tt.name, diff)
Expand Down Expand Up @@ -200,7 +200,7 @@ func TestExtractInvalidTraceContextFromHTTPReq(t *testing.T) {
req.Header.Set("traceparent", tt.header)

ctx := context.Background()
ctx = prop.Extract(ctx, req.Header)
ctx = prop.Extract(ctx, propagation.HeaderCarrier(req.Header))
gotSc := trace.RemoteSpanContextFromContext(ctx)
if diff := cmp.Diff(gotSc, wantSc, cmp.AllowUnexported(trace.TraceState{})); diff != "" {
t.Errorf("Extract Tracecontext: %s: -got +want %s", tt.name, diff)
Expand Down Expand Up @@ -257,7 +257,7 @@ func TestInjectTraceContextToHTTPReq(t *testing.T) {
ctx = trace.ContextWithRemoteSpanContext(ctx, tt.sc)
ctx, _ = mockTracer.Start(ctx, "inject")
}
prop.Inject(ctx, req.Header)
prop.Inject(ctx, propagation.HeaderCarrier(req.Header))

gotHeader := req.Header.Get("traceparent")
if diff := cmp.Diff(gotHeader, tt.wantHeader); diff != "" {
Expand Down Expand Up @@ -337,7 +337,7 @@ func TestTraceStatePropagation(t *testing.T) {
inReq.Header.Add(hk, hv)
}

ctx := prop.Extract(context.Background(), inReq.Header)
ctx := prop.Extract(context.Background(), propagation.HeaderCarrier(inReq.Header))
if diff := cmp.Diff(
trace.RemoteSpanContextFromContext(ctx),
tt.wantSc,
Expand All @@ -351,7 +351,7 @@ func TestTraceStatePropagation(t *testing.T) {
mockTracer := oteltest.DefaultTracer()
ctx, _ = mockTracer.Start(ctx, "inject")
outReq, _ := http.NewRequest(http.MethodGet, "http://www.example.com", nil)
prop.Inject(ctx, outReq.Header)
prop.Inject(ctx, propagation.HeaderCarrier(outReq.Header))

if diff := cmp.Diff(outReq.Header.Get(stateHeader), tt.headers[stateHeader]); diff != "" {
t.Errorf("Propagated tracestate: -got +want %s", diff)
Expand Down

0 comments on commit 3bce9c9

Please sign in to comment.