mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-02-05 13:15:41 +02:00
Remove B3 propagator from otel repo (#1191)
* Remove B3 propagator * Add to Changelog Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
This commit is contained in:
parent
e7e1dce982
commit
038f505d12
@ -48,6 +48,11 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
||||
- Move the `go.opentelemetry.io/otel/api/unit` package to `go.opentelemetry.io/otel/unit`. (#1185)
|
||||
- Renamed `SamplingDecision` values to comply with OpenTelemetry specification change. (#1192)
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove the B3 propagator from `go.opentelemetry.io/otel/propagators`. It is now located in the
|
||||
`go.opentelemetry.io/contrib/propagators/` module. (#1191)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Zipkin example no longer mentions `ParentSampler`, corrected to `ParentBased`. (#1171)
|
||||
|
@ -1,343 +0,0 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package propagators
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"go.opentelemetry.io/otel/api/propagation"
|
||||
"go.opentelemetry.io/otel/api/trace"
|
||||
)
|
||||
|
||||
const (
|
||||
// Default B3 Header names.
|
||||
b3ContextHeader = "b3"
|
||||
b3DebugFlagHeader = "x-b3-flags"
|
||||
b3TraceIDHeader = "x-b3-traceid"
|
||||
b3SpanIDHeader = "x-b3-spanid"
|
||||
b3SampledHeader = "x-b3-sampled"
|
||||
b3ParentSpanIDHeader = "x-b3-parentspanid"
|
||||
|
||||
b3TraceIDPadding = "0000000000000000"
|
||||
|
||||
// B3 Single Header encoding widths.
|
||||
separatorWidth = 1 // Single "-" character.
|
||||
samplingWidth = 1 // Single hex character.
|
||||
traceID64BitsWidth = 64 / 4 // 16 hex character Trace ID.
|
||||
traceID128BitsWidth = 128 / 4 // 32 hex character Trace ID.
|
||||
spanIDWidth = 16 // 16 hex character ID.
|
||||
parentSpanIDWidth = 16 // 16 hex character ID.
|
||||
)
|
||||
|
||||
var (
|
||||
empty = trace.EmptySpanContext()
|
||||
|
||||
errInvalidSampledByte = errors.New("invalid B3 Sampled found")
|
||||
errInvalidSampledHeader = errors.New("invalid B3 Sampled header found")
|
||||
errInvalidTraceIDHeader = errors.New("invalid B3 TraceID header found")
|
||||
errInvalidSpanIDHeader = errors.New("invalid B3 SpanID header found")
|
||||
errInvalidParentSpanIDHeader = errors.New("invalid B3 ParentSpanID header found")
|
||||
errInvalidScope = errors.New("require either both TraceID and SpanID or none")
|
||||
errInvalidScopeParent = errors.New("ParentSpanID requires both TraceID and SpanID to be available")
|
||||
errInvalidScopeParentSingle = errors.New("ParentSpanID requires TraceID, SpanID and Sampled to be available")
|
||||
errEmptyContext = errors.New("empty request context")
|
||||
errInvalidTraceIDValue = errors.New("invalid B3 TraceID value found")
|
||||
errInvalidSpanIDValue = errors.New("invalid B3 SpanID value found")
|
||||
errInvalidParentSpanIDValue = errors.New("invalid B3 ParentSpanID value found")
|
||||
)
|
||||
|
||||
// B3Encoding is a bitmask representation of the B3 encoding type.
|
||||
type B3Encoding uint8
|
||||
|
||||
// supports returns if e has o bit(s) set.
|
||||
func (e B3Encoding) supports(o B3Encoding) bool {
|
||||
return e&o == o
|
||||
}
|
||||
|
||||
const (
|
||||
// B3MultipleHeader is a B3 encoding that uses multiple headers to
|
||||
// transmit tracing information all prefixed with `x-b3-`.
|
||||
B3MultipleHeader B3Encoding = 1 << iota
|
||||
// B3SingleHeader is a B3 encoding that uses a single header named `b3`
|
||||
// to transmit tracing information.
|
||||
B3SingleHeader
|
||||
// B3Unspecified is an unspecified B3 encoding.
|
||||
B3Unspecified B3Encoding = 0
|
||||
)
|
||||
|
||||
// B3 is a propagator that supports the B3 HTTP encoding.
|
||||
//
|
||||
// Both single (https://github.com/openzipkin/b3-propagation#single-header)
|
||||
// and multiple (https://github.com/openzipkin/b3-propagation#single-header)
|
||||
// header encoding are supported.
|
||||
type B3 struct {
|
||||
// InjectEncoding are the B3 encodings used when injecting trace
|
||||
// information. If no encoding is specified (i.e. `B3Unspecified`)
|
||||
// `B3MultipleHeader` will be used as the default as it is the most
|
||||
// backwards compatible.
|
||||
InjectEncoding B3Encoding
|
||||
}
|
||||
|
||||
var _ propagation.HTTPPropagator = B3{}
|
||||
|
||||
// Inject injects a context into the supplier as B3 HTTP headers.
|
||||
// The parent span ID is omitted because it is not tracked in the
|
||||
// SpanContext.
|
||||
func (b3 B3) Inject(ctx context.Context, supplier propagation.HTTPSupplier) {
|
||||
sc := trace.SpanFromContext(ctx).SpanContext()
|
||||
|
||||
if b3.InjectEncoding.supports(B3SingleHeader) {
|
||||
header := []string{}
|
||||
if sc.TraceID.IsValid() && sc.SpanID.IsValid() {
|
||||
header = append(header, sc.TraceID.String(), sc.SpanID.String())
|
||||
}
|
||||
|
||||
if sc.IsDebug() {
|
||||
header = append(header, "d")
|
||||
} else if !sc.IsDeferred() {
|
||||
if sc.IsSampled() {
|
||||
header = append(header, "1")
|
||||
} else {
|
||||
header = append(header, "0")
|
||||
}
|
||||
}
|
||||
|
||||
supplier.Set(b3ContextHeader, strings.Join(header, "-"))
|
||||
}
|
||||
|
||||
if b3.InjectEncoding.supports(B3MultipleHeader) || b3.InjectEncoding == B3Unspecified {
|
||||
if sc.TraceID.IsValid() && sc.SpanID.IsValid() {
|
||||
supplier.Set(b3TraceIDHeader, sc.TraceID.String())
|
||||
supplier.Set(b3SpanIDHeader, sc.SpanID.String())
|
||||
}
|
||||
|
||||
if sc.IsDebug() {
|
||||
// Since Debug implies deferred, don't also send "X-B3-Sampled".
|
||||
supplier.Set(b3DebugFlagHeader, "1")
|
||||
} else if !sc.IsDeferred() {
|
||||
if sc.IsSampled() {
|
||||
supplier.Set(b3SampledHeader, "1")
|
||||
} else {
|
||||
supplier.Set(b3SampledHeader, "0")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract extracts a context from the supplier if it contains B3 HTTP
|
||||
// headers.
|
||||
func (b3 B3) Extract(ctx context.Context, supplier propagation.HTTPSupplier) context.Context {
|
||||
var (
|
||||
sc trace.SpanContext
|
||||
err error
|
||||
)
|
||||
|
||||
// Default to Single Header if a valid value exists.
|
||||
if h := supplier.Get(b3ContextHeader); h != "" {
|
||||
sc, err = extractSingle(h)
|
||||
if err == nil && sc.IsValid() {
|
||||
return trace.ContextWithRemoteSpanContext(ctx, sc)
|
||||
}
|
||||
// The Single Header value was invalid, fallback to Multiple Header.
|
||||
}
|
||||
|
||||
var (
|
||||
traceID = supplier.Get(b3TraceIDHeader)
|
||||
spanID = supplier.Get(b3SpanIDHeader)
|
||||
parentSpanID = supplier.Get(b3ParentSpanIDHeader)
|
||||
sampled = supplier.Get(b3SampledHeader)
|
||||
debugFlag = supplier.Get(b3DebugFlagHeader)
|
||||
)
|
||||
sc, err = extractMultiple(traceID, spanID, parentSpanID, sampled, debugFlag)
|
||||
if err != nil || !sc.IsValid() {
|
||||
return ctx
|
||||
}
|
||||
return trace.ContextWithRemoteSpanContext(ctx, sc)
|
||||
}
|
||||
|
||||
// GetAllKeys returns the HTTP header names this propagator will use when
|
||||
// injecting.
|
||||
func (b3 B3) GetAllKeys() []string {
|
||||
header := []string{}
|
||||
if b3.InjectEncoding.supports(B3SingleHeader) {
|
||||
header = append(header, b3ContextHeader)
|
||||
}
|
||||
if b3.InjectEncoding.supports(B3MultipleHeader) || b3.InjectEncoding == B3Unspecified {
|
||||
header = append(header, b3TraceIDHeader, b3SpanIDHeader, b3SampledHeader, b3DebugFlagHeader)
|
||||
}
|
||||
return header
|
||||
}
|
||||
|
||||
// extractMultiple reconstructs a SpanContext from header values based on B3
|
||||
// Multiple header. It is based on the implementation found here:
|
||||
// https://github.com/openzipkin/zipkin-go/blob/v0.2.2/propagation/b3/spancontext.go
|
||||
// and adapted to support a SpanContext.
|
||||
func extractMultiple(traceID, spanID, parentSpanID, sampled, flags string) (trace.SpanContext, error) {
|
||||
var (
|
||||
err error
|
||||
requiredCount int
|
||||
sc = trace.SpanContext{}
|
||||
)
|
||||
|
||||
// correct values for an existing sampled header are "0" and "1".
|
||||
// For legacy support and being lenient to other tracing implementations we
|
||||
// allow "true" and "false" as inputs for interop purposes.
|
||||
switch strings.ToLower(sampled) {
|
||||
case "0", "false":
|
||||
// Zero value for TraceFlags sample bit is unset.
|
||||
case "1", "true":
|
||||
sc.TraceFlags = trace.FlagsSampled
|
||||
case "":
|
||||
sc.TraceFlags = trace.FlagsDeferred
|
||||
default:
|
||||
return empty, errInvalidSampledHeader
|
||||
}
|
||||
|
||||
// The only accepted value for Flags is "1". This will set Debug to
|
||||
// true. All other values and omission of header will be ignored.
|
||||
if flags == "1" {
|
||||
sc.TraceFlags |= trace.FlagsDebug
|
||||
}
|
||||
|
||||
if traceID != "" {
|
||||
requiredCount++
|
||||
id := traceID
|
||||
if len(traceID) == 16 {
|
||||
// Pad 64-bit trace IDs.
|
||||
id = b3TraceIDPadding + traceID
|
||||
}
|
||||
if sc.TraceID, err = trace.IDFromHex(id); err != nil {
|
||||
return empty, errInvalidTraceIDHeader
|
||||
}
|
||||
}
|
||||
|
||||
if spanID != "" {
|
||||
requiredCount++
|
||||
if sc.SpanID, err = trace.SpanIDFromHex(spanID); err != nil {
|
||||
return empty, errInvalidSpanIDHeader
|
||||
}
|
||||
}
|
||||
|
||||
if requiredCount != 0 && requiredCount != 2 {
|
||||
return empty, errInvalidScope
|
||||
}
|
||||
|
||||
if parentSpanID != "" {
|
||||
if requiredCount == 0 {
|
||||
return empty, errInvalidScopeParent
|
||||
}
|
||||
// Validate parent span ID but we do not use it so do not save it.
|
||||
if _, err = trace.SpanIDFromHex(parentSpanID); err != nil {
|
||||
return empty, errInvalidParentSpanIDHeader
|
||||
}
|
||||
}
|
||||
|
||||
return sc, nil
|
||||
}
|
||||
|
||||
// extractSingle reconstructs a SpanContext from contextHeader based on a B3
|
||||
// Single header. It is based on the implementation found here:
|
||||
// https://github.com/openzipkin/zipkin-go/blob/v0.2.2/propagation/b3/spancontext.go
|
||||
// and adapted to support a SpanContext.
|
||||
func extractSingle(contextHeader string) (trace.SpanContext, error) {
|
||||
if contextHeader == "" {
|
||||
return empty, errEmptyContext
|
||||
}
|
||||
|
||||
var (
|
||||
sc = trace.SpanContext{}
|
||||
sampling string
|
||||
)
|
||||
|
||||
headerLen := len(contextHeader)
|
||||
|
||||
if headerLen == samplingWidth {
|
||||
sampling = contextHeader
|
||||
} else if headerLen == traceID64BitsWidth || headerLen == traceID128BitsWidth {
|
||||
// Trace ID by itself is invalid.
|
||||
return empty, errInvalidScope
|
||||
} else if headerLen >= traceID64BitsWidth+spanIDWidth+separatorWidth {
|
||||
pos := 0
|
||||
var traceID string
|
||||
if string(contextHeader[traceID64BitsWidth]) == "-" {
|
||||
// traceID must be 64 bits
|
||||
pos += traceID64BitsWidth // {traceID}
|
||||
traceID = b3TraceIDPadding + string(contextHeader[0:pos])
|
||||
} else if string(contextHeader[32]) == "-" {
|
||||
// traceID must be 128 bits
|
||||
pos += traceID128BitsWidth // {traceID}
|
||||
traceID = string(contextHeader[0:pos])
|
||||
} else {
|
||||
return empty, errInvalidTraceIDValue
|
||||
}
|
||||
var err error
|
||||
sc.TraceID, err = trace.IDFromHex(traceID)
|
||||
if err != nil {
|
||||
return empty, errInvalidTraceIDValue
|
||||
}
|
||||
pos += separatorWidth // {traceID}-
|
||||
|
||||
sc.SpanID, err = trace.SpanIDFromHex(contextHeader[pos : pos+spanIDWidth])
|
||||
if err != nil {
|
||||
return empty, errInvalidSpanIDValue
|
||||
}
|
||||
pos += spanIDWidth // {traceID}-{spanID}
|
||||
|
||||
if headerLen > pos {
|
||||
if headerLen == pos+separatorWidth {
|
||||
// {traceID}-{spanID}- is invalid.
|
||||
return empty, errInvalidSampledByte
|
||||
}
|
||||
pos += separatorWidth // {traceID}-{spanID}-
|
||||
|
||||
if headerLen == pos+samplingWidth {
|
||||
sampling = string(contextHeader[pos])
|
||||
} else if headerLen == pos+parentSpanIDWidth {
|
||||
// {traceID}-{spanID}-{parentSpanID} is invalid.
|
||||
return empty, errInvalidScopeParentSingle
|
||||
} else if headerLen == pos+samplingWidth+separatorWidth+parentSpanIDWidth {
|
||||
sampling = string(contextHeader[pos])
|
||||
pos += samplingWidth + separatorWidth // {traceID}-{spanID}-{sampling}-
|
||||
|
||||
// Validate parent span ID but we do not use it so do not
|
||||
// save it.
|
||||
_, err = trace.SpanIDFromHex(contextHeader[pos:])
|
||||
if err != nil {
|
||||
return empty, errInvalidParentSpanIDValue
|
||||
}
|
||||
} else {
|
||||
return empty, errInvalidParentSpanIDValue
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return empty, errInvalidTraceIDValue
|
||||
}
|
||||
switch sampling {
|
||||
case "":
|
||||
sc.TraceFlags = trace.FlagsDeferred
|
||||
case "d":
|
||||
sc.TraceFlags = trace.FlagsDebug
|
||||
case "1":
|
||||
sc.TraceFlags = trace.FlagsSampled
|
||||
case "0":
|
||||
// Zero value for TraceFlags sample bit is unset.
|
||||
default:
|
||||
return empty, errInvalidSampledByte
|
||||
}
|
||||
|
||||
return sc, nil
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package propagators_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"go.opentelemetry.io/otel/api/trace"
|
||||
"go.opentelemetry.io/otel/propagators"
|
||||
)
|
||||
|
||||
func BenchmarkExtractB3(b *testing.B) {
|
||||
testGroup := []struct {
|
||||
name string
|
||||
tests []extractTest
|
||||
}{
|
||||
{
|
||||
name: "valid headers",
|
||||
tests: extractHeaders,
|
||||
},
|
||||
{
|
||||
name: "invalid headers",
|
||||
tests: extractInvalidHeaders,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tg := range testGroup {
|
||||
propagator := propagators.B3{}
|
||||
for _, tt := range tg.tests {
|
||||
traceBenchmark(tg.name+"/"+tt.name, b, func(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
req, _ := http.NewRequest("GET", "http://example.com", nil)
|
||||
for h, v := range tt.headers {
|
||||
req.Header.Set(h, v)
|
||||
}
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = propagator.Extract(ctx, req.Header)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkInjectB3(b *testing.B) {
|
||||
testGroup := []struct {
|
||||
name string
|
||||
tests []injectTest
|
||||
}{
|
||||
{
|
||||
name: "valid headers",
|
||||
tests: injectHeader,
|
||||
},
|
||||
{
|
||||
name: "invalid headers",
|
||||
tests: injectInvalidHeader,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tg := range testGroup {
|
||||
for _, tt := range tg.tests {
|
||||
propagator := propagators.B3{InjectEncoding: tt.encoding}
|
||||
traceBenchmark(tg.name+"/"+tt.name, b, func(b *testing.B) {
|
||||
req, _ := http.NewRequest("GET", "http://example.com", nil)
|
||||
ctx := trace.ContextWithSpan(
|
||||
context.Background(),
|
||||
testSpan{sc: tt.sc},
|
||||
)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
propagator.Inject(ctx, req.Header)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traceBenchmark(name string, b *testing.B, fn func(*testing.B)) {
|
||||
b.Run(name, func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
fn(b)
|
||||
})
|
||||
b.Run(name, func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
fn(b)
|
||||
})
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,42 +0,0 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package propagators_test
|
||||
|
||||
import (
|
||||
"go.opentelemetry.io/otel/api/global"
|
||||
"go.opentelemetry.io/otel/api/propagation"
|
||||
"go.opentelemetry.io/otel/propagators"
|
||||
)
|
||||
|
||||
func ExampleB3() {
|
||||
b3 := propagators.B3{}
|
||||
// Register the B3 propagator globally.
|
||||
global.SetPropagators(propagation.New(
|
||||
propagation.WithExtractors(b3),
|
||||
propagation.WithInjectors(b3),
|
||||
))
|
||||
}
|
||||
|
||||
func ExampleB3_injectEncoding() {
|
||||
// Create a B3 propagator configured to inject context with both multiple
|
||||
// and single header B3 HTTP encoding.
|
||||
b3 := propagators.B3{
|
||||
InjectEncoding: propagators.B3MultipleHeader | propagators.B3SingleHeader,
|
||||
}
|
||||
global.SetPropagators(propagation.New(
|
||||
propagation.WithExtractors(b3),
|
||||
propagation.WithInjectors(b3),
|
||||
))
|
||||
}
|
@ -1,173 +0,0 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package propagators_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"go.opentelemetry.io/otel/api/propagation"
|
||||
"go.opentelemetry.io/otel/api/trace"
|
||||
"go.opentelemetry.io/otel/internal/trace/noop"
|
||||
"go.opentelemetry.io/otel/propagators"
|
||||
)
|
||||
|
||||
func TestExtractB3(t *testing.T) {
|
||||
testGroup := []struct {
|
||||
name string
|
||||
tests []extractTest
|
||||
}{
|
||||
{
|
||||
name: "valid extract headers",
|
||||
tests: extractHeaders,
|
||||
},
|
||||
{
|
||||
name: "invalid extract headers",
|
||||
tests: extractInvalidHeaders,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tg := range testGroup {
|
||||
propagator := propagators.B3{}
|
||||
props := propagation.New(propagation.WithExtractors(propagator))
|
||||
|
||||
for _, tt := range tg.tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", "http://example.com", nil)
|
||||
for h, v := range tt.headers {
|
||||
req.Header.Set(h, v)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = propagation.ExtractHTTP(ctx, props, req.Header)
|
||||
gotSc := trace.RemoteSpanContextFromContext(ctx)
|
||||
if diff := cmp.Diff(gotSc, tt.wantSc); diff != "" {
|
||||
t.Errorf("%s: %s: -got +want %s", tg.name, tt.name, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type testSpan struct {
|
||||
trace.Span
|
||||
sc trace.SpanContext
|
||||
}
|
||||
|
||||
func (s testSpan) SpanContext() trace.SpanContext {
|
||||
return s.sc
|
||||
}
|
||||
|
||||
func TestInjectB3(t *testing.T) {
|
||||
testGroup := []struct {
|
||||
name string
|
||||
tests []injectTest
|
||||
}{
|
||||
{
|
||||
name: "valid inject headers",
|
||||
tests: injectHeader,
|
||||
},
|
||||
{
|
||||
name: "invalid inject headers",
|
||||
tests: injectInvalidHeader,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tg := range testGroup {
|
||||
for _, tt := range tg.tests {
|
||||
propagator := propagators.B3{InjectEncoding: tt.encoding}
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", "http://example.com", nil)
|
||||
ctx := trace.ContextWithSpan(
|
||||
context.Background(),
|
||||
testSpan{
|
||||
Span: noop.Span,
|
||||
sc: tt.sc,
|
||||
},
|
||||
)
|
||||
propagator.Inject(ctx, req.Header)
|
||||
|
||||
for h, v := range tt.wantHeaders {
|
||||
got, want := req.Header.Get(h), v
|
||||
if diff := cmp.Diff(got, want); diff != "" {
|
||||
t.Errorf("%s: %s, header=%s: -got +want %s", tg.name, tt.name, h, diff)
|
||||
}
|
||||
}
|
||||
for _, h := range tt.doNotWantHeaders {
|
||||
v, gotOk := req.Header[h]
|
||||
if diff := cmp.Diff(gotOk, false); diff != "" {
|
||||
t.Errorf("%s: %s, header=%s: -got +want %s, value=%s", tg.name, tt.name, h, diff, v)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestB3Propagator_GetAllKeys(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
propagator propagators.B3
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
name: "no encoding specified",
|
||||
propagator: propagators.B3{},
|
||||
want: []string{
|
||||
b3TraceID,
|
||||
b3SpanID,
|
||||
b3Sampled,
|
||||
b3Flags,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "B3MultipleHeader encoding specified",
|
||||
propagator: propagators.B3{InjectEncoding: propagators.B3MultipleHeader},
|
||||
want: []string{
|
||||
b3TraceID,
|
||||
b3SpanID,
|
||||
b3Sampled,
|
||||
b3Flags,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "B3SingleHeader encoding specified",
|
||||
propagator: propagators.B3{InjectEncoding: propagators.B3SingleHeader},
|
||||
want: []string{
|
||||
b3Context,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "B3SingleHeader and B3MultipleHeader encoding specified",
|
||||
propagator: propagators.B3{InjectEncoding: propagators.B3SingleHeader | propagators.B3MultipleHeader},
|
||||
want: []string{
|
||||
b3Context,
|
||||
b3TraceID,
|
||||
b3SpanID,
|
||||
b3Sampled,
|
||||
b3Flags,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
if diff := cmp.Diff(test.propagator.GetAllKeys(), test.want); diff != "" {
|
||||
t.Errorf("%s: GetAllKeys: -got +want %s", test.name, diff)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,326 +0,0 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package propagators
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"go.opentelemetry.io/otel/api/trace"
|
||||
)
|
||||
|
||||
var (
|
||||
traceID = trace.ID{0, 0, 0, 0, 0, 0, 0, 0x7b, 0, 0, 0, 0, 0, 0, 0x1, 0xc8}
|
||||
traceIDStr = "000000000000007b00000000000001c8"
|
||||
spanID = trace.SpanID{0, 0, 0, 0, 0, 0, 0, 0x7b}
|
||||
spanIDStr = "000000000000007b"
|
||||
)
|
||||
|
||||
func TestExtractMultiple(t *testing.T) {
|
||||
tests := []struct {
|
||||
traceID string
|
||||
spanID string
|
||||
parentSpanID string
|
||||
sampled string
|
||||
flags string
|
||||
expected trace.SpanContext
|
||||
err error
|
||||
}{
|
||||
{
|
||||
"", "", "", "0", "",
|
||||
trace.SpanContext{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"", "", "", "", "",
|
||||
trace.SpanContext{TraceFlags: trace.FlagsDeferred},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"", "", "", "1", "",
|
||||
trace.SpanContext{TraceFlags: trace.FlagsSampled},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"", "", "", "", "1",
|
||||
trace.SpanContext{TraceFlags: trace.FlagsDeferred | trace.FlagsDebug},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"", "", "", "0", "1",
|
||||
trace.SpanContext{TraceFlags: trace.FlagsDebug},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"", "", "", "1", "1",
|
||||
trace.SpanContext{TraceFlags: trace.FlagsSampled | trace.FlagsDebug},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
traceIDStr, spanIDStr, "", "", "",
|
||||
trace.SpanContext{TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsDeferred},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
traceIDStr, spanIDStr, "", "0", "",
|
||||
trace.SpanContext{TraceID: traceID, SpanID: spanID},
|
||||
nil,
|
||||
},
|
||||
// Ensure backwards compatibility.
|
||||
{
|
||||
traceIDStr, spanIDStr, "", "false", "",
|
||||
trace.SpanContext{TraceID: traceID, SpanID: spanID},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
traceIDStr, spanIDStr, "", "1", "",
|
||||
trace.SpanContext{TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled},
|
||||
nil,
|
||||
},
|
||||
// Ensure backwards compatibility.
|
||||
{
|
||||
traceIDStr, spanIDStr, "", "true", "",
|
||||
trace.SpanContext{TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
traceIDStr, spanIDStr, "", "a", "",
|
||||
empty,
|
||||
errInvalidSampledHeader,
|
||||
},
|
||||
{
|
||||
traceIDStr, spanIDStr, "", "1", "1",
|
||||
trace.SpanContext{TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled | trace.FlagsDebug},
|
||||
nil,
|
||||
},
|
||||
// Invalid flags are discarded.
|
||||
{
|
||||
traceIDStr, spanIDStr, "", "1", "invalid",
|
||||
trace.SpanContext{TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled},
|
||||
nil,
|
||||
},
|
||||
// Support short trace IDs.
|
||||
{
|
||||
"00000000000001c8", spanIDStr, "", "0", "",
|
||||
trace.SpanContext{
|
||||
TraceID: trace.ID{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1, 0xc8},
|
||||
SpanID: spanID,
|
||||
},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"00000000000001c", spanIDStr, "", "0", "",
|
||||
empty,
|
||||
errInvalidTraceIDHeader,
|
||||
},
|
||||
{
|
||||
"00000000000001c80", spanIDStr, "", "0", "",
|
||||
empty,
|
||||
errInvalidTraceIDHeader,
|
||||
},
|
||||
{
|
||||
traceIDStr[:len(traceIDStr)-2], spanIDStr, "", "0", "",
|
||||
empty,
|
||||
errInvalidTraceIDHeader,
|
||||
},
|
||||
{
|
||||
traceIDStr + "0", spanIDStr, "", "0", "",
|
||||
empty,
|
||||
errInvalidTraceIDHeader,
|
||||
},
|
||||
{
|
||||
traceIDStr, "00000000000001c", "", "0", "",
|
||||
empty,
|
||||
errInvalidSpanIDHeader,
|
||||
},
|
||||
{
|
||||
traceIDStr, "00000000000001c80", "", "0", "",
|
||||
empty,
|
||||
errInvalidSpanIDHeader,
|
||||
},
|
||||
{
|
||||
traceIDStr, "", "", "0", "",
|
||||
empty,
|
||||
errInvalidScope,
|
||||
},
|
||||
{
|
||||
"", spanIDStr, "", "0", "",
|
||||
empty,
|
||||
errInvalidScope,
|
||||
},
|
||||
{
|
||||
"", "", spanIDStr, "0", "",
|
||||
empty,
|
||||
errInvalidScopeParent,
|
||||
},
|
||||
{
|
||||
traceIDStr, spanIDStr, "00000000000001c8", "0", "",
|
||||
trace.SpanContext{TraceID: traceID, SpanID: spanID},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
traceIDStr, spanIDStr, "00000000000001c", "0", "",
|
||||
empty,
|
||||
errInvalidParentSpanIDHeader,
|
||||
},
|
||||
{
|
||||
traceIDStr, spanIDStr, "00000000000001c80", "0", "",
|
||||
empty,
|
||||
errInvalidParentSpanIDHeader,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
actual, err := extractMultiple(
|
||||
test.traceID,
|
||||
test.spanID,
|
||||
test.parentSpanID,
|
||||
test.sampled,
|
||||
test.flags,
|
||||
)
|
||||
info := []interface{}{
|
||||
"trace ID: %q, span ID: %q, parent span ID: %q, sampled: %q, flags: %q",
|
||||
test.traceID,
|
||||
test.spanID,
|
||||
test.parentSpanID,
|
||||
test.sampled,
|
||||
test.flags,
|
||||
}
|
||||
if !assert.Equal(t, test.err, err, info...) {
|
||||
continue
|
||||
}
|
||||
assert.Equal(t, test.expected, actual, info...)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractSingle(t *testing.T) {
|
||||
tests := []struct {
|
||||
header string
|
||||
expected trace.SpanContext
|
||||
err error
|
||||
}{
|
||||
{"0", trace.SpanContext{}, nil},
|
||||
{"1", trace.SpanContext{TraceFlags: trace.FlagsSampled}, nil},
|
||||
{"d", trace.SpanContext{TraceFlags: trace.FlagsDebug}, nil},
|
||||
{"a", empty, errInvalidSampledByte},
|
||||
{"3", empty, errInvalidSampledByte},
|
||||
{"000000000000007b", empty, errInvalidScope},
|
||||
{"000000000000007b00000000000001c8", empty, errInvalidScope},
|
||||
// Support short trace IDs.
|
||||
{
|
||||
"00000000000001c8-000000000000007b",
|
||||
trace.SpanContext{
|
||||
TraceID: trace.ID{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1, 0xc8},
|
||||
SpanID: spanID,
|
||||
TraceFlags: trace.FlagsDeferred,
|
||||
},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"000000000000007b00000000000001c8-000000000000007b",
|
||||
trace.SpanContext{
|
||||
TraceID: traceID,
|
||||
SpanID: spanID,
|
||||
TraceFlags: trace.FlagsDeferred,
|
||||
},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"000000000000007b00000000000001c8-000000000000007b-",
|
||||
empty,
|
||||
errInvalidSampledByte,
|
||||
},
|
||||
{
|
||||
"000000000000007b00000000000001c8-000000000000007b-3",
|
||||
empty,
|
||||
errInvalidSampledByte,
|
||||
},
|
||||
{
|
||||
"000000000000007b00000000000001c8-000000000000007b-00000000000001c8",
|
||||
empty,
|
||||
errInvalidScopeParentSingle,
|
||||
},
|
||||
{
|
||||
"000000000000007b00000000000001c8-000000000000007b-1",
|
||||
trace.SpanContext{TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled},
|
||||
nil,
|
||||
},
|
||||
// ParentSpanID is discarded, but should still restult in a parsable
|
||||
// header.
|
||||
{
|
||||
"000000000000007b00000000000001c8-000000000000007b-1-00000000000001c8",
|
||||
trace.SpanContext{TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"000000000000007b00000000000001c8-000000000000007b-1-00000000000001c",
|
||||
empty,
|
||||
errInvalidParentSpanIDValue,
|
||||
},
|
||||
{"", empty, errEmptyContext},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
actual, err := extractSingle(test.header)
|
||||
if !assert.Equal(t, test.err, err, "header: %s", test.header) {
|
||||
continue
|
||||
}
|
||||
assert.Equal(t, test.expected, actual, "header: %s", test.header)
|
||||
}
|
||||
}
|
||||
|
||||
func TestB3EncodingOperations(t *testing.T) {
|
||||
encodings := []B3Encoding{
|
||||
B3MultipleHeader,
|
||||
B3SingleHeader,
|
||||
B3Unspecified,
|
||||
}
|
||||
|
||||
// Test for overflow (or something really unexpected).
|
||||
for i, e := range encodings {
|
||||
for j := i + 1; j < i+len(encodings); j++ {
|
||||
o := encodings[j%len(encodings)]
|
||||
assert.False(t, e == o, "%v == %v", e, o)
|
||||
}
|
||||
}
|
||||
|
||||
// B3Unspecified is a special case, it supports only itself, but is
|
||||
// supported by everything.
|
||||
assert.True(t, B3Unspecified.supports(B3Unspecified))
|
||||
for _, e := range encodings[:len(encodings)-1] {
|
||||
assert.False(t, B3Unspecified.supports(e), e)
|
||||
assert.True(t, e.supports(B3Unspecified), e)
|
||||
}
|
||||
|
||||
// Skip the special case for B3Unspecified.
|
||||
for i, e := range encodings[:len(encodings)-1] {
|
||||
// Everything should support itself.
|
||||
assert.True(t, e.supports(e))
|
||||
for j := i + 1; j < i+len(encodings); j++ {
|
||||
o := encodings[j%len(encodings)]
|
||||
// Any "or" combination should be supportive of an operand.
|
||||
assert.True(t, (e | o).supports(e), "(%[0]v|%[1]v).supports(%[0]v)", e, o)
|
||||
// Bitmasks should be unique.
|
||||
assert.False(t, o.supports(e), "%v.supports(%v)", o, e)
|
||||
}
|
||||
}
|
||||
|
||||
// B3Encoding.supports should be more inclusive than equality.
|
||||
all := ^B3Unspecified
|
||||
for _, e := range encodings {
|
||||
assert.True(t, all.supports(e))
|
||||
}
|
||||
}
|
@ -16,9 +16,7 @@
|
||||
Package propagators contains OpenTelemetry context propagators.
|
||||
|
||||
OpenTelemetry propagators are used to extract and inject context data from and
|
||||
into messages exchanged by applications. The propagators supported by this
|
||||
package includes are the B3 single and multiple header HTTP encoding
|
||||
(https://github.com/openzipkin/b3-propagation) and the W3C Trace Context
|
||||
encoding (https://www.w3.org/TR/trace-context/).
|
||||
into messages exchanged by applications. The propagator supported by this
|
||||
package is the W3C Trace Context encoding (https://www.w3.org/TR/trace-context/).
|
||||
*/
|
||||
package propagators // import "go.opentelemetry.io/otel/propagators"
|
||||
|
@ -91,9 +91,6 @@ func TestMultiplePropagators(t *testing.T) {
|
||||
ns := nilSupplier{}
|
||||
testProps := []propagation.HTTPPropagator{
|
||||
propagators.TraceContext{},
|
||||
propagators.B3{},
|
||||
propagators.B3{InjectEncoding: propagators.B3SingleHeader},
|
||||
propagators.B3{InjectEncoding: propagators.B3SingleHeader | propagators.B3MultipleHeader},
|
||||
}
|
||||
bg := context.Background()
|
||||
// sanity check of oota propagator, ensuring that it really
|
||||
|
Loading…
x
Reference in New Issue
Block a user