You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-07-15 01:04:25 +02:00
Update propagation to conform with OpenTelemetry specification (#1212)
* Move propagation package contents to the otel package * Implement package relocation * Update propagation to OTel spec * Add changes to changelog * Add propagation tests
This commit is contained in:
@ -15,6 +15,14 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Set default propagator to no-op propagator. (#1184)
|
- Set default propagator to no-op propagator. (#1184)
|
||||||
|
- The `HTTPSupplier`, `HTTPExtractor`, `HTTPInjector`, and `HTTPPropagator` from the `go.opentelemetry.io/otel/api/propagation` package were replaced with unified `TextMapCarrier` and `TextMapPropagator` in the `go.opentelemetry.io/otel` package. (#1212)
|
||||||
|
- The `New` function from the `go.opentelemetry.io/otel/api/propagation` package was replaced with `NewCompositeTextMapPropagator` in the `go.opentelemetry.io/otel` package. (#1212)
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- The `ExtractHTTP` and `InjectHTTP` fuctions from the `go.opentelemetry.io/otel/api/propagation` package were removed. (#1212)
|
||||||
|
- The `Propagators` interface from the `go.opentelemetry.io/otel/api/propagation` package was removed to conform to the OpenTelemetry specification.
|
||||||
|
The explicit `TextMapPropagator` type can be used in its place as this is the `Propagator` type the specification defines. (#1212)
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"go.opentelemetry.io/otel/api/propagation"
|
"go.opentelemetry.io/otel"
|
||||||
"go.opentelemetry.io/otel/label"
|
"go.opentelemetry.io/otel/label"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,21 +27,14 @@ import (
|
|||||||
// https://github.com/open-telemetry/opentelemetry-specification/blob/18b2752ebe6c7f0cdd8c7b2bcbdceb0ae3f5ad95/specification/correlationcontext/api.md#header-name
|
// https://github.com/open-telemetry/opentelemetry-specification/blob/18b2752ebe6c7f0cdd8c7b2bcbdceb0ae3f5ad95/specification/correlationcontext/api.md#header-name
|
||||||
const baggageHeader = "otcorrelations"
|
const baggageHeader = "otcorrelations"
|
||||||
|
|
||||||
// Baggage propagates Key:Values in W3C CorrelationContext
|
// Baggage propagates Key:Values in W3C CorrelationContext format.
|
||||||
// format.
|
|
||||||
// nolint:golint
|
// nolint:golint
|
||||||
type Baggage struct{}
|
type Baggage struct{}
|
||||||
|
|
||||||
var _ propagation.HTTPPropagator = Baggage{}
|
var _ otel.TextMapPropagator = Baggage{}
|
||||||
|
|
||||||
// DefaultHTTPPropagator returns the default context correlation HTTP
|
// Inject set baggage key-values from the Context into the carrier.
|
||||||
// propagator.
|
func (b Baggage) Inject(ctx context.Context, carrier otel.TextMapCarrier) {
|
||||||
func DefaultHTTPPropagator() propagation.HTTPPropagator {
|
|
||||||
return Baggage{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inject implements HTTPInjector.
|
|
||||||
func (b Baggage) Inject(ctx context.Context, supplier propagation.HTTPSupplier) {
|
|
||||||
baggageMap := MapFromContext(ctx)
|
baggageMap := MapFromContext(ctx)
|
||||||
firstIter := true
|
firstIter := true
|
||||||
var headerValueBuilder strings.Builder
|
var headerValueBuilder strings.Builder
|
||||||
@ -57,13 +50,13 @@ func (b Baggage) Inject(ctx context.Context, supplier propagation.HTTPSupplier)
|
|||||||
})
|
})
|
||||||
if headerValueBuilder.Len() > 0 {
|
if headerValueBuilder.Len() > 0 {
|
||||||
headerString := headerValueBuilder.String()
|
headerString := headerValueBuilder.String()
|
||||||
supplier.Set(baggageHeader, headerString)
|
carrier.Set(baggageHeader, headerString)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract implements HTTPExtractor.
|
// Extract reads baggage key-values from the carrier into a returned Context.
|
||||||
func (b Baggage) Extract(ctx context.Context, supplier propagation.HTTPSupplier) context.Context {
|
func (b Baggage) Extract(ctx context.Context, carrier otel.TextMapCarrier) context.Context {
|
||||||
baggage := supplier.Get(baggageHeader)
|
baggage := carrier.Get(baggageHeader)
|
||||||
if baggage == "" {
|
if baggage == "" {
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
@ -112,7 +105,7 @@ func (b Baggage) Extract(ctx context.Context, supplier propagation.HTTPSupplier)
|
|||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllKeys implements HTTPPropagator.
|
// Fields returns the keys who's values are set with Inject.
|
||||||
func (b Baggage) GetAllKeys() []string {
|
func (b Baggage) Fields() []string {
|
||||||
return []string{baggageHeader}
|
return []string{baggageHeader}
|
||||||
}
|
}
|
||||||
|
@ -22,13 +22,13 @@ import (
|
|||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
"go.opentelemetry.io/otel/api/baggage"
|
"go.opentelemetry.io/otel/api/baggage"
|
||||||
"go.opentelemetry.io/otel/api/propagation"
|
|
||||||
"go.opentelemetry.io/otel/label"
|
"go.opentelemetry.io/otel/label"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestExtractValidBaggageFromHTTPReq(t *testing.T) {
|
func TestExtractValidBaggageFromHTTPReq(t *testing.T) {
|
||||||
props := propagation.New(propagation.WithExtractors(baggage.Baggage{}))
|
prop := otel.TextMapPropagator(baggage.Baggage{})
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
header string
|
header string
|
||||||
@ -90,7 +90,7 @@ func TestExtractValidBaggageFromHTTPReq(t *testing.T) {
|
|||||||
req.Header.Set("otcorrelations", tt.header)
|
req.Header.Set("otcorrelations", tt.header)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
ctx = propagation.ExtractHTTP(ctx, props, req.Header)
|
ctx = prop.Extract(ctx, req.Header)
|
||||||
gotBaggage := baggage.MapFromContext(ctx)
|
gotBaggage := baggage.MapFromContext(ctx)
|
||||||
wantBaggage := baggage.NewMap(baggage.MapUpdate{MultiKV: tt.wantKVs})
|
wantBaggage := baggage.NewMap(baggage.MapUpdate{MultiKV: tt.wantKVs})
|
||||||
if gotBaggage.Len() != wantBaggage.Len() {
|
if gotBaggage.Len() != wantBaggage.Len() {
|
||||||
@ -117,7 +117,7 @@ func TestExtractValidBaggageFromHTTPReq(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractInvalidDistributedContextFromHTTPReq(t *testing.T) {
|
func TestExtractInvalidDistributedContextFromHTTPReq(t *testing.T) {
|
||||||
props := propagation.New(propagation.WithExtractors(baggage.Baggage{}))
|
prop := otel.TextMapPropagator(baggage.Baggage{})
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
header string
|
header string
|
||||||
@ -152,7 +152,7 @@ func TestExtractInvalidDistributedContextFromHTTPReq(t *testing.T) {
|
|||||||
|
|
||||||
ctx := baggage.NewContext(context.Background(), tt.hasKVs...)
|
ctx := baggage.NewContext(context.Background(), tt.hasKVs...)
|
||||||
wantBaggage := baggage.MapFromContext(ctx)
|
wantBaggage := baggage.MapFromContext(ctx)
|
||||||
ctx = propagation.ExtractHTTP(ctx, props, req.Header)
|
ctx = prop.Extract(ctx, req.Header)
|
||||||
gotBaggage := baggage.MapFromContext(ctx)
|
gotBaggage := baggage.MapFromContext(ctx)
|
||||||
if gotBaggage.Len() != wantBaggage.Len() {
|
if gotBaggage.Len() != wantBaggage.Len() {
|
||||||
t.Errorf(
|
t.Errorf(
|
||||||
@ -176,7 +176,6 @@ func TestExtractInvalidDistributedContextFromHTTPReq(t *testing.T) {
|
|||||||
|
|
||||||
func TestInjectBaggageToHTTPReq(t *testing.T) {
|
func TestInjectBaggageToHTTPReq(t *testing.T) {
|
||||||
propagator := baggage.Baggage{}
|
propagator := baggage.Baggage{}
|
||||||
props := propagation.New(propagation.WithInjectors(propagator))
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
kvs []label.KeyValue
|
kvs []label.KeyValue
|
||||||
@ -229,7 +228,7 @@ func TestInjectBaggageToHTTPReq(t *testing.T) {
|
|||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
req, _ := http.NewRequest("GET", "http://example.com", nil)
|
req, _ := http.NewRequest("GET", "http://example.com", nil)
|
||||||
ctx := baggage.ContextWithMap(context.Background(), baggage.NewMap(baggage.MapUpdate{MultiKV: tt.kvs}))
|
ctx := baggage.ContextWithMap(context.Background(), baggage.NewMap(baggage.MapUpdate{MultiKV: tt.kvs}))
|
||||||
propagation.InjectHTTP(ctx, props, req.Header)
|
propagator.Inject(ctx, req.Header)
|
||||||
|
|
||||||
gotHeader := req.Header.Get("otcorrelations")
|
gotHeader := req.Header.Get("otcorrelations")
|
||||||
wantedLen := len(strings.Join(tt.wantInHeader, ","))
|
wantedLen := len(strings.Join(tt.wantInHeader, ","))
|
||||||
@ -252,7 +251,7 @@ func TestInjectBaggageToHTTPReq(t *testing.T) {
|
|||||||
func TestTraceContextPropagator_GetAllKeys(t *testing.T) {
|
func TestTraceContextPropagator_GetAllKeys(t *testing.T) {
|
||||||
var propagator baggage.Baggage
|
var propagator baggage.Baggage
|
||||||
want := []string{"otcorrelations"}
|
want := []string{"otcorrelations"}
|
||||||
got := propagator.GetAllKeys()
|
got := propagator.Fields()
|
||||||
if diff := cmp.Diff(got, want); diff != "" {
|
if diff := cmp.Diff(got, want); diff != "" {
|
||||||
t.Errorf("GetAllKeys: -got +want %s", diff)
|
t.Errorf("GetAllKeys: -got +want %s", diff)
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
"go.opentelemetry.io/otel/api/metric"
|
"go.opentelemetry.io/otel/api/metric"
|
||||||
"go.opentelemetry.io/otel/api/propagation"
|
|
||||||
"go.opentelemetry.io/otel/api/trace"
|
"go.opentelemetry.io/otel/api/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ type (
|
|||||||
}
|
}
|
||||||
|
|
||||||
propagatorsHolder struct {
|
propagatorsHolder struct {
|
||||||
pr propagation.Propagators
|
tm otel.TextMapPropagator
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -90,14 +90,14 @@ func SetMeterProvider(mp metric.MeterProvider) {
|
|||||||
globalMeter.Store(meterProviderHolder{mp: mp})
|
globalMeter.Store(meterProviderHolder{mp: mp})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Propagators is the internal implementation for global.Propagators.
|
// TextMapPropagator is the internal implementation for global.TextMapPropagator.
|
||||||
func Propagators() propagation.Propagators {
|
func TextMapPropagator() otel.TextMapPropagator {
|
||||||
return globalPropagators.Load().(propagatorsHolder).pr
|
return globalPropagators.Load().(propagatorsHolder).tm
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPropagators is the internal implementation for global.SetPropagators.
|
// SetTextMapPropagator is the internal implementation for global.SetTextMapPropagator.
|
||||||
func SetPropagators(pr propagation.Propagators) {
|
func SetTextMapPropagator(p otel.TextMapPropagator) {
|
||||||
globalPropagators.Store(propagatorsHolder{pr: pr})
|
globalPropagators.Store(propagatorsHolder{tm: p})
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultTracerValue() *atomic.Value {
|
func defaultTracerValue() *atomic.Value {
|
||||||
@ -114,13 +114,14 @@ func defaultMeterValue() *atomic.Value {
|
|||||||
|
|
||||||
func defaultPropagatorsValue() *atomic.Value {
|
func defaultPropagatorsValue() *atomic.Value {
|
||||||
v := &atomic.Value{}
|
v := &atomic.Value{}
|
||||||
v.Store(propagatorsHolder{pr: getDefaultPropagators()})
|
v.Store(propagatorsHolder{tm: getDefaultTextMapPropagator()})
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// getDefaultPropagators returns a default noop Propagators
|
// getDefaultTextMapPropagator returns the default TextMapPropagator,
|
||||||
func getDefaultPropagators() propagation.Propagators {
|
// configured with W3C trace and baggage propagation.
|
||||||
return propagation.New()
|
func getDefaultTextMapPropagator() otel.TextMapPropagator {
|
||||||
|
return otel.NewCompositeTextMapPropagator()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetForTest restores the initial global state, for testing purposes.
|
// ResetForTest restores the initial global state, for testing purposes.
|
||||||
|
@ -15,18 +15,17 @@
|
|||||||
package global
|
package global
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
"go.opentelemetry.io/otel/api/global/internal"
|
"go.opentelemetry.io/otel/api/global/internal"
|
||||||
"go.opentelemetry.io/otel/api/propagation"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Propagators returns the registered global propagators instance. If
|
// TextMapPropagator returns the global TextMapPropagator. If none has been
|
||||||
// none is registered then an instance of propagators.NoopPropagators
|
// set, a No-Op TextMapPropagator is returned.
|
||||||
// is returned.
|
func TextMapPropagator() otel.TextMapPropagator {
|
||||||
func Propagators() propagation.Propagators {
|
return internal.TextMapPropagator()
|
||||||
return internal.Propagators()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPropagators registers `p` as the global propagators instance.
|
// SetTextMapPropagator sets propagator as the global TSetTextMapPropagator.
|
||||||
func SetPropagators(p propagation.Propagators) {
|
func SetTextMapPropagator(propagator otel.TextMapPropagator) {
|
||||||
internal.SetPropagators(p)
|
internal.SetTextMapPropagator(propagator)
|
||||||
}
|
}
|
||||||
|
@ -1,16 +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 propagation provides support for propagating context over HTTP.
|
|
||||||
package propagation // import "go.opentelemetry.io/otel/api/propagation"
|
|
@ -1,143 +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 propagation
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HTTPSupplier is an interface that specifies methods to retrieve and
|
|
||||||
// store a single value for a key to an associated carrier. It is
|
|
||||||
// implemented by http.Headers.
|
|
||||||
type HTTPSupplier interface {
|
|
||||||
// Get method retrieves a single value for a given key.
|
|
||||||
Get(key string) string
|
|
||||||
// Set method stores a single value for a given key. Note that
|
|
||||||
// this should not be appending a value to some array, but
|
|
||||||
// rather overwrite the old value.
|
|
||||||
Set(key string, value string)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPExtractor extracts information from a HTTPSupplier into a
|
|
||||||
// context.
|
|
||||||
type HTTPExtractor interface {
|
|
||||||
// Extract method retrieves encoded information using supplier
|
|
||||||
// from the associated carrier, decodes it and creates a new
|
|
||||||
// context containing the decoded information.
|
|
||||||
//
|
|
||||||
// Information can be a correlation context or a remote span
|
|
||||||
// context. In case of span context, the propagator should
|
|
||||||
// store it in the context using
|
|
||||||
// trace.ContextWithRemoteSpanContext. In case of correlation
|
|
||||||
// context, the propagator should use correlation.WithMap to
|
|
||||||
// store it in the context.
|
|
||||||
Extract(ctx context.Context, supplier HTTPSupplier) context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPInjector injects information into a HTTPSupplier.
|
|
||||||
type HTTPInjector interface {
|
|
||||||
// Inject method retrieves information from the context,
|
|
||||||
// encodes it into propagator specific format and then injects
|
|
||||||
// the encoded information using supplier into an associated
|
|
||||||
// carrier.
|
|
||||||
Inject(ctx context.Context, supplier HTTPSupplier)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config contains the current set of extractors and injectors.
|
|
||||||
type Config struct {
|
|
||||||
httpEx []HTTPExtractor
|
|
||||||
httpIn []HTTPInjector
|
|
||||||
}
|
|
||||||
|
|
||||||
// Propagators is the interface to a set of injectors and extractors
|
|
||||||
// for all supported carrier formats. It can be used to chain multiple
|
|
||||||
// propagators into a single entity.
|
|
||||||
type Propagators interface {
|
|
||||||
// HTTPExtractors returns the configured extractors.
|
|
||||||
HTTPExtractors() []HTTPExtractor
|
|
||||||
|
|
||||||
// HTTPInjectors returns the configured injectors.
|
|
||||||
HTTPInjectors() []HTTPInjector
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPPropagator is the interface to inject to and extract from
|
|
||||||
// HTTPSupplier.
|
|
||||||
type HTTPPropagator interface {
|
|
||||||
HTTPInjector
|
|
||||||
HTTPExtractor
|
|
||||||
|
|
||||||
// GetAllKeys returns the HTTP header names used.
|
|
||||||
GetAllKeys() []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Option support passing configuration parameters to New().
|
|
||||||
type Option func(*Config)
|
|
||||||
|
|
||||||
// propagators is the default Propagators implementation.
|
|
||||||
type propagators struct {
|
|
||||||
config Config
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns a standard Propagators implementation.
|
|
||||||
func New(options ...Option) Propagators {
|
|
||||||
config := Config{}
|
|
||||||
for _, opt := range options {
|
|
||||||
opt(&config)
|
|
||||||
}
|
|
||||||
return &propagators{
|
|
||||||
config: config,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithInjectors appends to the optional injector set.
|
|
||||||
func WithInjectors(inj ...HTTPInjector) Option {
|
|
||||||
return func(config *Config) {
|
|
||||||
config.httpIn = append(config.httpIn, inj...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithExtractors appends to the optional extractor set.
|
|
||||||
func WithExtractors(ext ...HTTPExtractor) Option {
|
|
||||||
return func(config *Config) {
|
|
||||||
config.httpEx = append(config.httpEx, ext...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPExtractors implements Propagators.
|
|
||||||
func (p *propagators) HTTPExtractors() []HTTPExtractor {
|
|
||||||
return p.config.httpEx
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPInjectors implements Propagators.
|
|
||||||
func (p *propagators) HTTPInjectors() []HTTPInjector {
|
|
||||||
return p.config.httpIn
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExtractHTTP applies props.HTTPExtractors() to the passed context
|
|
||||||
// and the supplier and returns the combined result context.
|
|
||||||
func ExtractHTTP(ctx context.Context, props Propagators, supplier HTTPSupplier) context.Context {
|
|
||||||
for _, ex := range props.HTTPExtractors() {
|
|
||||||
ctx = ex.Extract(ctx, supplier)
|
|
||||||
}
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
// InjectHTTP applies props.HTTPInjectors() to the passed context and
|
|
||||||
// the supplier.
|
|
||||||
func InjectHTTP(ctx context.Context, props Propagators, supplier HTTPSupplier) {
|
|
||||||
for _, in := range props.HTTPInjectors() {
|
|
||||||
in.Inject(ctx, supplier)
|
|
||||||
}
|
|
||||||
}
|
|
@ -25,9 +25,9 @@ import (
|
|||||||
otext "github.com/opentracing/opentracing-go/ext"
|
otext "github.com/opentracing/opentracing-go/ext"
|
||||||
otlog "github.com/opentracing/opentracing-go/log"
|
otlog "github.com/opentracing/opentracing-go/log"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
otelbaggage "go.opentelemetry.io/otel/api/baggage"
|
otelbaggage "go.opentelemetry.io/otel/api/baggage"
|
||||||
otelglobal "go.opentelemetry.io/otel/api/global"
|
otelglobal "go.opentelemetry.io/otel/api/global"
|
||||||
otelpropagation "go.opentelemetry.io/otel/api/propagation"
|
|
||||||
oteltrace "go.opentelemetry.io/otel/api/trace"
|
oteltrace "go.opentelemetry.io/otel/api/trace"
|
||||||
"go.opentelemetry.io/otel/codes"
|
"go.opentelemetry.io/otel/codes"
|
||||||
"go.opentelemetry.io/otel/internal/trace/noop"
|
"go.opentelemetry.io/otel/internal/trace/noop"
|
||||||
@ -287,7 +287,7 @@ type BridgeTracer struct {
|
|||||||
warningHandler BridgeWarningHandler
|
warningHandler BridgeWarningHandler
|
||||||
warnOnce sync.Once
|
warnOnce sync.Once
|
||||||
|
|
||||||
propagators otelpropagation.Propagators
|
propagator otel.TextMapPropagator
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ ot.Tracer = &BridgeTracer{}
|
var _ ot.Tracer = &BridgeTracer{}
|
||||||
@ -304,7 +304,7 @@ func NewBridgeTracer() *BridgeTracer {
|
|||||||
otelTracer: noop.Tracer,
|
otelTracer: noop.Tracer,
|
||||||
},
|
},
|
||||||
warningHandler: func(msg string) {},
|
warningHandler: func(msg string) {},
|
||||||
propagators: nil,
|
propagator: nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,8 +322,8 @@ func (t *BridgeTracer) SetOpenTelemetryTracer(tracer oteltrace.Tracer) {
|
|||||||
t.setTracer.isSet = true
|
t.setTracer.isSet = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *BridgeTracer) SetPropagators(propagators otelpropagation.Propagators) {
|
func (t *BridgeTracer) SetTextMapPropagator(propagator otel.TextMapPropagator) {
|
||||||
t.propagators = propagators
|
t.propagator = propagator
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *BridgeTracer) NewHookedContext(ctx context.Context) context.Context {
|
func (t *BridgeTracer) NewHookedContext(ctx context.Context) context.Context {
|
||||||
@ -614,7 +614,7 @@ func (t *BridgeTracer) Inject(sm ot.SpanContext, format interface{}, carrier int
|
|||||||
}
|
}
|
||||||
ctx := oteltrace.ContextWithSpan(context.Background(), fs)
|
ctx := oteltrace.ContextWithSpan(context.Background(), fs)
|
||||||
ctx = otelbaggage.ContextWithMap(ctx, bridgeSC.baggageItems)
|
ctx = otelbaggage.ContextWithMap(ctx, bridgeSC.baggageItems)
|
||||||
otelpropagation.InjectHTTP(ctx, t.getPropagators(), header)
|
t.getPropagator().Inject(ctx, header)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,7 +631,7 @@ func (t *BridgeTracer) Extract(format interface{}, carrier interface{}) (ot.Span
|
|||||||
return nil, ot.ErrInvalidCarrier
|
return nil, ot.ErrInvalidCarrier
|
||||||
}
|
}
|
||||||
header := http.Header(hhcarrier)
|
header := http.Header(hhcarrier)
|
||||||
ctx := otelpropagation.ExtractHTTP(context.Background(), t.getPropagators(), header)
|
ctx := t.getPropagator().Extract(context.Background(), header)
|
||||||
baggage := otelbaggage.MapFromContext(ctx)
|
baggage := otelbaggage.MapFromContext(ctx)
|
||||||
otelSC, _, _ := otelparent.GetSpanContextAndLinks(ctx, false)
|
otelSC, _, _ := otelparent.GetSpanContextAndLinks(ctx, false)
|
||||||
bridgeSC := &bridgeSpanContext{
|
bridgeSC := &bridgeSpanContext{
|
||||||
@ -644,9 +644,9 @@ func (t *BridgeTracer) Extract(format interface{}, carrier interface{}) (ot.Span
|
|||||||
return bridgeSC, nil
|
return bridgeSC, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *BridgeTracer) getPropagators() otelpropagation.Propagators {
|
func (t *BridgeTracer) getPropagator() otel.TextMapPropagator {
|
||||||
if t.propagators != nil {
|
if t.propagator != nil {
|
||||||
return t.propagators
|
return t.propagator
|
||||||
}
|
}
|
||||||
return otelglobal.Propagators()
|
return otelglobal.TextMapPropagator()
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
"go.opentelemetry.io/otel/api/baggage"
|
"go.opentelemetry.io/otel/api/baggage"
|
||||||
"go.opentelemetry.io/otel/api/global"
|
"go.opentelemetry.io/otel/api/global"
|
||||||
"go.opentelemetry.io/otel/api/metric"
|
"go.opentelemetry.io/otel/api/metric"
|
||||||
"go.opentelemetry.io/otel/api/propagation"
|
|
||||||
"go.opentelemetry.io/otel/api/trace"
|
"go.opentelemetry.io/otel/api/trace"
|
||||||
"go.opentelemetry.io/otel/exporters/stdout"
|
"go.opentelemetry.io/otel/exporters/stdout"
|
||||||
"go.opentelemetry.io/otel/label"
|
"go.opentelemetry.io/otel/label"
|
||||||
@ -62,12 +61,8 @@ func main() {
|
|||||||
global.SetTracerProvider(tp)
|
global.SetTracerProvider(tp)
|
||||||
global.SetMeterProvider(pusher.MeterProvider())
|
global.SetMeterProvider(pusher.MeterProvider())
|
||||||
|
|
||||||
// set propagator to baggage since the default is no-op
|
// set global propagator to baggage (the default is no-op).
|
||||||
bagPropagator := baggage.DefaultHTTPPropagator()
|
global.SetTextMapPropagator(baggage.Baggage{})
|
||||||
props := propagation.New(propagation.WithExtractors(bagPropagator),
|
|
||||||
propagation.WithInjectors(bagPropagator))
|
|
||||||
|
|
||||||
global.SetPropagators(props)
|
|
||||||
tracer := global.Tracer("ex.com/basic")
|
tracer := global.Tracer("ex.com/basic")
|
||||||
meter := global.Meter("ex.com/basic")
|
meter := global.Meter("ex.com/basic")
|
||||||
|
|
||||||
|
@ -27,7 +27,6 @@ import (
|
|||||||
|
|
||||||
"go.opentelemetry.io/otel/api/global"
|
"go.opentelemetry.io/otel/api/global"
|
||||||
"go.opentelemetry.io/otel/api/metric"
|
"go.opentelemetry.io/otel/api/metric"
|
||||||
"go.opentelemetry.io/otel/api/propagation"
|
|
||||||
apitrace "go.opentelemetry.io/otel/api/trace"
|
apitrace "go.opentelemetry.io/otel/api/trace"
|
||||||
"go.opentelemetry.io/otel/exporters/otlp"
|
"go.opentelemetry.io/otel/exporters/otlp"
|
||||||
"go.opentelemetry.io/otel/label"
|
"go.opentelemetry.io/otel/label"
|
||||||
@ -75,10 +74,8 @@ func initProvider() func() {
|
|||||||
push.WithPeriod(2*time.Second),
|
push.WithPeriod(2*time.Second),
|
||||||
)
|
)
|
||||||
|
|
||||||
tcPropagator := propagators.TraceContext{}
|
// set global propagator to tracecontext (the default is no-op).
|
||||||
props := propagation.New(propagation.WithExtractors(tcPropagator),
|
global.SetTextMapPropagator(propagators.TraceContext{})
|
||||||
propagation.WithInjectors(tcPropagator))
|
|
||||||
global.SetPropagators(props)
|
|
||||||
global.SetTracerProvider(tracerProvider)
|
global.SetTracerProvider(tracerProvider)
|
||||||
global.SetMeterProvider(pusher.MeterProvider())
|
global.SetMeterProvider(pusher.MeterProvider())
|
||||||
pusher.Start()
|
pusher.Start()
|
||||||
|
3
otel.go
3
otel.go
@ -16,7 +16,6 @@ package otel
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"go.opentelemetry.io/otel/api/metric"
|
"go.opentelemetry.io/otel/api/metric"
|
||||||
"go.opentelemetry.io/otel/api/propagation"
|
|
||||||
"go.opentelemetry.io/otel/api/trace"
|
"go.opentelemetry.io/otel/api/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,8 +23,6 @@ type Tracer = trace.Tracer
|
|||||||
|
|
||||||
type Meter = metric.Meter
|
type Meter = metric.Meter
|
||||||
|
|
||||||
type Propagators = propagation.Propagators
|
|
||||||
|
|
||||||
// ErrorHandler handles irremediable events.
|
// ErrorHandler handles irremediable events.
|
||||||
type ErrorHandler interface {
|
type ErrorHandler interface {
|
||||||
// Handle handles any error deemed irremediable by an OpenTelemetry
|
// Handle handles any error deemed irremediable by an OpenTelemetry
|
||||||
|
78
propagation.go
Normal file
78
propagation.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// 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 otel
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TextMapPropagator propagates cross-cutting concerns as key-value text
|
||||||
|
// pairs within a carrier that travels in-band across process boundaries.
|
||||||
|
type TextMapPropagator interface {
|
||||||
|
// Inject set cross-cutting concerns from the Context into the carrier.
|
||||||
|
Inject(ctx context.Context, carrier TextMapCarrier)
|
||||||
|
// Extract reads cross-cutting concerns from the carrier into a Context.
|
||||||
|
Extract(ctx context.Context, carrier TextMapCarrier) context.Context
|
||||||
|
// Fields returns the keys who's values are set with Inject.
|
||||||
|
Fields() []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type compositeTextMapPropagator []TextMapPropagator
|
||||||
|
|
||||||
|
func (p compositeTextMapPropagator) Inject(ctx context.Context, carrier TextMapCarrier) {
|
||||||
|
for _, i := range p {
|
||||||
|
i.Inject(ctx, carrier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p compositeTextMapPropagator) Extract(ctx context.Context, carrier TextMapCarrier) context.Context {
|
||||||
|
for _, i := range p {
|
||||||
|
ctx = i.Extract(ctx, carrier)
|
||||||
|
}
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p compositeTextMapPropagator) Fields() []string {
|
||||||
|
unique := make(map[string]struct{})
|
||||||
|
for _, i := range p {
|
||||||
|
for _, k := range i.Fields() {
|
||||||
|
unique[k] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := make([]string, 0, len(unique))
|
||||||
|
for k := range unique {
|
||||||
|
fields = append(fields, k)
|
||||||
|
}
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCompositeTextMapPropagator returns a unified TextMapPropagator from the
|
||||||
|
// group of passed TextMapPropagator. This allows different cross-cutting
|
||||||
|
// concerns to be propagates in a unified manner.
|
||||||
|
//
|
||||||
|
// The returned TextMapPropagator will inject and extract cross-cutting
|
||||||
|
// concerns in the order the TextMapPropagators were provided. Additionally,
|
||||||
|
// the Fields method will return a de-duplicated slice of the keys that are
|
||||||
|
// set with the Inject method.
|
||||||
|
func NewCompositeTextMapPropagator(p ...TextMapPropagator) TextMapPropagator {
|
||||||
|
return compositeTextMapPropagator(p)
|
||||||
|
}
|
100
propagation_test.go
Normal file
100
propagation_test.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// 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 otel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ctxKeyType uint
|
||||||
|
|
||||||
|
var (
|
||||||
|
ctxKey ctxKeyType = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
type carrier []string
|
||||||
|
|
||||||
|
func (c *carrier) Get(string) string { return "" }
|
||||||
|
|
||||||
|
func (c *carrier) Set(setter, _ string) {
|
||||||
|
*c = append(*c, setter)
|
||||||
|
}
|
||||||
|
|
||||||
|
type propagator struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p propagator) Inject(ctx context.Context, carrier TextMapCarrier) {
|
||||||
|
carrier.Set(p.Name, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p propagator) Extract(ctx context.Context, carrier TextMapCarrier) context.Context {
|
||||||
|
v := ctx.Value(ctxKey)
|
||||||
|
if v == nil {
|
||||||
|
ctx = context.WithValue(ctx, ctxKey, []string{p.Name})
|
||||||
|
} else {
|
||||||
|
orig := v.([]string)
|
||||||
|
ctx = context.WithValue(ctx, ctxKey, append(orig, p.Name))
|
||||||
|
}
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p propagator) Fields() []string { return []string{p.Name} }
|
||||||
|
|
||||||
|
func TestCompositeTextMapPropagatorFields(t *testing.T) {
|
||||||
|
a, b1, b2 := propagator{"a"}, propagator{"b"}, propagator{"b"}
|
||||||
|
|
||||||
|
want := map[string]struct{}{
|
||||||
|
"a": {},
|
||||||
|
"b": {},
|
||||||
|
}
|
||||||
|
got := NewCompositeTextMapPropagator(a, b1, b2).Fields()
|
||||||
|
if len(got) != len(want) {
|
||||||
|
t.Fatalf("invalid fields from composite: %v (want %v)", got, want)
|
||||||
|
}
|
||||||
|
for _, v := range got {
|
||||||
|
if _, ok := want[v]; !ok {
|
||||||
|
t.Errorf("invalid field returned from composite: %q", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompositeTextMapPropagatorInject(t *testing.T) {
|
||||||
|
a, b := propagator{"a"}, propagator{"b"}
|
||||||
|
|
||||||
|
c := make(carrier, 0, 2)
|
||||||
|
NewCompositeTextMapPropagator(a, b).Inject(context.Background(), &c)
|
||||||
|
|
||||||
|
if got := strings.Join([]string(c), ","); got != "a,b" {
|
||||||
|
t.Errorf("invalid inject order: %s", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompositeTextMapPropagatorExtract(t *testing.T) {
|
||||||
|
a, b := propagator{"a"}, propagator{"b"}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
ctx = NewCompositeTextMapPropagator(a, b).Extract(ctx, nil)
|
||||||
|
|
||||||
|
v := ctx.Value(ctxKey)
|
||||||
|
if v == nil {
|
||||||
|
t.Fatal("no composite extraction")
|
||||||
|
}
|
||||||
|
if got := strings.Join(v.([]string), ","); got != "a,b" {
|
||||||
|
t.Errorf("invalid extract order: %s", got)
|
||||||
|
}
|
||||||
|
}
|
@ -1,25 +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 "go.opentelemetry.io/otel/api/propagation"
|
|
||||||
|
|
||||||
// DefaultHTTPPropagator returns the default OpenTelemetry HTTP propagator,
|
|
||||||
// the W3C Trace Context propagator.
|
|
||||||
func DefaultHTTPPropagator() propagation.HTTPPropagator {
|
|
||||||
// As specified here:
|
|
||||||
// https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/context/api-propagators.md#global-propagators
|
|
||||||
return TraceContext{}
|
|
||||||
}
|
|
@ -21,7 +21,7 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"go.opentelemetry.io/otel/api/propagation"
|
"go.opentelemetry.io/otel"
|
||||||
"go.opentelemetry.io/otel/api/trace"
|
"go.opentelemetry.io/otel/api/trace"
|
||||||
"go.opentelemetry.io/otel/propagators"
|
"go.opentelemetry.io/otel/propagators"
|
||||||
)
|
)
|
||||||
@ -58,9 +58,9 @@ type outOfThinAirPropagator struct {
|
|||||||
t *testing.T
|
t *testing.T
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ propagation.HTTPPropagator = outOfThinAirPropagator{}
|
var _ otel.TextMapPropagator = outOfThinAirPropagator{}
|
||||||
|
|
||||||
func (p outOfThinAirPropagator) Extract(ctx context.Context, supplier propagation.HTTPSupplier) context.Context {
|
func (p outOfThinAirPropagator) Extract(ctx context.Context, carrier otel.TextMapCarrier) context.Context {
|
||||||
sc := trace.SpanContext{
|
sc := trace.SpanContext{
|
||||||
TraceID: traceID,
|
TraceID: traceID,
|
||||||
SpanID: spanID,
|
SpanID: spanID,
|
||||||
@ -70,34 +70,33 @@ func (p outOfThinAirPropagator) Extract(ctx context.Context, supplier propagatio
|
|||||||
return trace.ContextWithRemoteSpanContext(ctx, sc)
|
return trace.ContextWithRemoteSpanContext(ctx, sc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (outOfThinAirPropagator) Inject(context.Context, propagation.HTTPSupplier) {}
|
func (outOfThinAirPropagator) Inject(context.Context, otel.TextMapCarrier) {}
|
||||||
|
|
||||||
func (outOfThinAirPropagator) GetAllKeys() []string {
|
func (outOfThinAirPropagator) Fields() []string {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type nilSupplier struct{}
|
type nilCarrier struct{}
|
||||||
|
|
||||||
var _ propagation.HTTPSupplier = nilSupplier{}
|
var _ otel.TextMapCarrier = nilCarrier{}
|
||||||
|
|
||||||
func (nilSupplier) Get(key string) string {
|
func (nilCarrier) Get(key string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nilSupplier) Set(key string, value string) {}
|
func (nilCarrier) Set(key string, value string) {}
|
||||||
|
|
||||||
func TestMultiplePropagators(t *testing.T) {
|
func TestMultiplePropagators(t *testing.T) {
|
||||||
ootaProp := outOfThinAirPropagator{t: t}
|
ootaProp := outOfThinAirPropagator{t: t}
|
||||||
ns := nilSupplier{}
|
ns := nilCarrier{}
|
||||||
testProps := []propagation.HTTPPropagator{
|
testProps := []otel.TextMapPropagator{
|
||||||
propagators.TraceContext{},
|
propagators.TraceContext{},
|
||||||
}
|
}
|
||||||
bg := context.Background()
|
bg := context.Background()
|
||||||
// sanity check of oota propagator, ensuring that it really
|
// sanity check of oota propagator, ensuring that it really
|
||||||
// generates the valid span context out of thin air
|
// generates the valid span context out of thin air
|
||||||
{
|
{
|
||||||
props := propagation.New(propagation.WithExtractors(ootaProp))
|
ctx := ootaProp.Extract(bg, ns)
|
||||||
ctx := propagation.ExtractHTTP(bg, props, ns)
|
|
||||||
sc := trace.RemoteSpanContextFromContext(ctx)
|
sc := trace.RemoteSpanContextFromContext(ctx)
|
||||||
require.True(t, sc.IsValid(), "oota prop failed sanity check")
|
require.True(t, sc.IsValid(), "oota prop failed sanity check")
|
||||||
}
|
}
|
||||||
@ -105,19 +104,14 @@ func TestMultiplePropagators(t *testing.T) {
|
|||||||
// really are not putting any valid span context into an empty
|
// really are not putting any valid span context into an empty
|
||||||
// go context in absence of the HTTP headers.
|
// go context in absence of the HTTP headers.
|
||||||
for _, prop := range testProps {
|
for _, prop := range testProps {
|
||||||
props := propagation.New(propagation.WithExtractors(prop))
|
ctx := prop.Extract(bg, ns)
|
||||||
ctx := propagation.ExtractHTTP(bg, props, ns)
|
|
||||||
sc := trace.RemoteSpanContextFromContext(ctx)
|
sc := trace.RemoteSpanContextFromContext(ctx)
|
||||||
require.Falsef(t, sc.IsValid(), "%#v failed sanity check", prop)
|
require.Falsef(t, sc.IsValid(), "%#v failed sanity check", prop)
|
||||||
}
|
}
|
||||||
for _, prop := range testProps {
|
for _, prop := range testProps {
|
||||||
props := propagation.New(propagation.WithExtractors(ootaProp, prop))
|
props := otel.NewCompositeTextMapPropagator(ootaProp, prop)
|
||||||
ctx := propagation.ExtractHTTP(bg, props, ns)
|
ctx := props.Extract(bg, ns)
|
||||||
sc := trace.RemoteSpanContextFromContext(ctx)
|
sc := trace.RemoteSpanContextFromContext(ctx)
|
||||||
assert.Truef(t, sc.IsValid(), "%#v clobbers span context", prop)
|
assert.Truef(t, sc.IsValid(), "%#v clobbers span context", prop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDefaultHTTPPropagator(t *testing.T) {
|
|
||||||
assert.IsType(t, propagators.TraceContext{}, propagators.DefaultHTTPPropagator())
|
|
||||||
}
|
|
||||||
|
@ -20,7 +20,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"go.opentelemetry.io/otel/api/propagation"
|
"go.opentelemetry.io/otel"
|
||||||
"go.opentelemetry.io/otel/api/trace"
|
"go.opentelemetry.io/otel/api/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -47,15 +47,14 @@ const (
|
|||||||
// their proprietary information.
|
// their proprietary information.
|
||||||
type TraceContext struct{}
|
type TraceContext struct{}
|
||||||
|
|
||||||
var _ propagation.HTTPPropagator = TraceContext{}
|
var _ otel.TextMapPropagator = TraceContext{}
|
||||||
var traceCtxRegExp = regexp.MustCompile("^(?P<version>[0-9a-f]{2})-(?P<traceID>[a-f0-9]{32})-(?P<spanID>[a-f0-9]{16})-(?P<traceFlags>[a-f0-9]{2})(?:-.*)?$")
|
var traceCtxRegExp = regexp.MustCompile("^(?P<version>[0-9a-f]{2})-(?P<traceID>[a-f0-9]{32})-(?P<spanID>[a-f0-9]{16})-(?P<traceFlags>[a-f0-9]{2})(?:-.*)?$")
|
||||||
|
|
||||||
// Inject injects a context into the supplier as W3C Trace Context HTTP
|
// Inject set tracecontext from the Context into the carrier.
|
||||||
// headers.
|
func (tc TraceContext) Inject(ctx context.Context, carrier otel.TextMapCarrier) {
|
||||||
func (tc TraceContext) Inject(ctx context.Context, supplier propagation.HTTPSupplier) {
|
|
||||||
tracestate := ctx.Value(tracestateKey)
|
tracestate := ctx.Value(tracestateKey)
|
||||||
if state, ok := tracestate.(string); tracestate != nil && ok {
|
if state, ok := tracestate.(string); tracestate != nil && ok {
|
||||||
supplier.Set(tracestateHeader, state)
|
carrier.Set(tracestateHeader, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
sc := trace.SpanFromContext(ctx).SpanContext()
|
sc := trace.SpanFromContext(ctx).SpanContext()
|
||||||
@ -67,26 +66,25 @@ func (tc TraceContext) Inject(ctx context.Context, supplier propagation.HTTPSupp
|
|||||||
sc.TraceID,
|
sc.TraceID,
|
||||||
sc.SpanID,
|
sc.SpanID,
|
||||||
sc.TraceFlags&trace.FlagsSampled)
|
sc.TraceFlags&trace.FlagsSampled)
|
||||||
supplier.Set(traceparentHeader, h)
|
carrier.Set(traceparentHeader, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract extracts a context from the supplier if it contains W3C Trace
|
// Extract reads tracecontext from the carrier into a returned Context.
|
||||||
// Context headers.
|
func (tc TraceContext) Extract(ctx context.Context, carrier otel.TextMapCarrier) context.Context {
|
||||||
func (tc TraceContext) Extract(ctx context.Context, supplier propagation.HTTPSupplier) context.Context {
|
state := carrier.Get(tracestateHeader)
|
||||||
state := supplier.Get(tracestateHeader)
|
|
||||||
if state != "" {
|
if state != "" {
|
||||||
ctx = context.WithValue(ctx, tracestateKey, state)
|
ctx = context.WithValue(ctx, tracestateKey, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
sc := tc.extract(supplier)
|
sc := tc.extract(carrier)
|
||||||
if !sc.IsValid() {
|
if !sc.IsValid() {
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
return trace.ContextWithRemoteSpanContext(ctx, sc)
|
return trace.ContextWithRemoteSpanContext(ctx, sc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tc TraceContext) extract(supplier propagation.HTTPSupplier) trace.SpanContext {
|
func (tc TraceContext) extract(carrier otel.TextMapCarrier) trace.SpanContext {
|
||||||
h := supplier.Get(traceparentHeader)
|
h := carrier.Get(traceparentHeader)
|
||||||
if h == "" {
|
if h == "" {
|
||||||
return trace.EmptySpanContext()
|
return trace.EmptySpanContext()
|
||||||
}
|
}
|
||||||
@ -153,8 +151,7 @@ func (tc TraceContext) extract(supplier propagation.HTTPSupplier) trace.SpanCont
|
|||||||
return sc
|
return sc
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllKeys returns the HTTP header names this propagator will use when
|
// Fields returns the keys who's values are set with Inject.
|
||||||
// injecting.
|
func (tc TraceContext) Fields() []string {
|
||||||
func (tc TraceContext) GetAllKeys() []string {
|
|
||||||
return []string{traceparentHeader, tracestateHeader}
|
return []string{traceparentHeader, tracestateHeader}
|
||||||
}
|
}
|
||||||
|
@ -16,15 +16,11 @@ package propagators_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"go.opentelemetry.io/otel/api/global"
|
"go.opentelemetry.io/otel/api/global"
|
||||||
"go.opentelemetry.io/otel/api/propagation"
|
|
||||||
"go.opentelemetry.io/otel/propagators"
|
"go.opentelemetry.io/otel/propagators"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExampleTraceContext() {
|
func ExampleTraceContext() {
|
||||||
tc := propagators.TraceContext{}
|
tc := propagators.TraceContext{}
|
||||||
// Register the TraceContext propagator globally.
|
// Register the TraceContext propagator globally.
|
||||||
global.SetPropagators(propagation.New(
|
global.SetTextMapPropagator(tc)
|
||||||
propagation.WithExtractors(tc),
|
|
||||||
propagation.WithInjectors(tc),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
@ -21,14 +21,13 @@ import (
|
|||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
|
||||||
"go.opentelemetry.io/otel/api/propagation"
|
|
||||||
"go.opentelemetry.io/otel/api/trace"
|
"go.opentelemetry.io/otel/api/trace"
|
||||||
"go.opentelemetry.io/otel/api/trace/tracetest"
|
"go.opentelemetry.io/otel/api/trace/tracetest"
|
||||||
"go.opentelemetry.io/otel/propagators"
|
"go.opentelemetry.io/otel/propagators"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestExtractValidTraceContextFromHTTPReq(t *testing.T) {
|
func TestExtractValidTraceContextFromHTTPReq(t *testing.T) {
|
||||||
props := propagation.New(propagation.WithExtractors(propagators.TraceContext{}))
|
prop := propagators.TraceContext{}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
header string
|
header string
|
||||||
@ -112,7 +111,7 @@ func TestExtractValidTraceContextFromHTTPReq(t *testing.T) {
|
|||||||
req.Header.Set("traceparent", tt.header)
|
req.Header.Set("traceparent", tt.header)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
ctx = propagation.ExtractHTTP(ctx, props, req.Header)
|
ctx = prop.Extract(ctx, req.Header)
|
||||||
gotSc := trace.RemoteSpanContextFromContext(ctx)
|
gotSc := trace.RemoteSpanContextFromContext(ctx)
|
||||||
if diff := cmp.Diff(gotSc, tt.wantSc); diff != "" {
|
if diff := cmp.Diff(gotSc, tt.wantSc); diff != "" {
|
||||||
t.Errorf("Extract Tracecontext: %s: -got +want %s", tt.name, diff)
|
t.Errorf("Extract Tracecontext: %s: -got +want %s", tt.name, diff)
|
||||||
@ -123,7 +122,7 @@ func TestExtractValidTraceContextFromHTTPReq(t *testing.T) {
|
|||||||
|
|
||||||
func TestExtractInvalidTraceContextFromHTTPReq(t *testing.T) {
|
func TestExtractInvalidTraceContextFromHTTPReq(t *testing.T) {
|
||||||
wantSc := trace.EmptySpanContext()
|
wantSc := trace.EmptySpanContext()
|
||||||
props := propagation.New(propagation.WithExtractors(propagators.TraceContext{}))
|
prop := propagators.TraceContext{}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
header string
|
header string
|
||||||
@ -200,7 +199,7 @@ func TestExtractInvalidTraceContextFromHTTPReq(t *testing.T) {
|
|||||||
req.Header.Set("traceparent", tt.header)
|
req.Header.Set("traceparent", tt.header)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
ctx = propagation.ExtractHTTP(ctx, props, req.Header)
|
ctx = prop.Extract(ctx, req.Header)
|
||||||
gotSc := trace.RemoteSpanContextFromContext(ctx)
|
gotSc := trace.RemoteSpanContextFromContext(ctx)
|
||||||
if diff := cmp.Diff(gotSc, wantSc); diff != "" {
|
if diff := cmp.Diff(gotSc, wantSc); diff != "" {
|
||||||
t.Errorf("Extract Tracecontext: %s: -got +want %s", tt.name, diff)
|
t.Errorf("Extract Tracecontext: %s: -got +want %s", tt.name, diff)
|
||||||
@ -215,7 +214,7 @@ func TestInjectTraceContextToHTTPReq(t *testing.T) {
|
|||||||
Sampled: false,
|
Sampled: false,
|
||||||
StartSpanID: &id,
|
StartSpanID: &id,
|
||||||
}
|
}
|
||||||
props := propagation.New(propagation.WithInjectors(propagators.TraceContext{}))
|
prop := propagators.TraceContext{}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
sc trace.SpanContext
|
sc trace.SpanContext
|
||||||
@ -261,7 +260,7 @@ func TestInjectTraceContextToHTTPReq(t *testing.T) {
|
|||||||
ctx = trace.ContextWithRemoteSpanContext(ctx, tt.sc)
|
ctx = trace.ContextWithRemoteSpanContext(ctx, tt.sc)
|
||||||
ctx, _ = mockTracer.Start(ctx, "inject")
|
ctx, _ = mockTracer.Start(ctx, "inject")
|
||||||
}
|
}
|
||||||
propagation.InjectHTTP(ctx, props, req.Header)
|
prop.Inject(ctx, req.Header)
|
||||||
|
|
||||||
gotHeader := req.Header.Get("traceparent")
|
gotHeader := req.Header.Get("traceparent")
|
||||||
if diff := cmp.Diff(gotHeader, tt.wantHeader); diff != "" {
|
if diff := cmp.Diff(gotHeader, tt.wantHeader); diff != "" {
|
||||||
@ -274,23 +273,23 @@ func TestInjectTraceContextToHTTPReq(t *testing.T) {
|
|||||||
func TestTraceContextPropagator_GetAllKeys(t *testing.T) {
|
func TestTraceContextPropagator_GetAllKeys(t *testing.T) {
|
||||||
var propagator propagators.TraceContext
|
var propagator propagators.TraceContext
|
||||||
want := []string{"traceparent", "tracestate"}
|
want := []string{"traceparent", "tracestate"}
|
||||||
got := propagator.GetAllKeys()
|
got := propagator.Fields()
|
||||||
if diff := cmp.Diff(got, want); diff != "" {
|
if diff := cmp.Diff(got, want); diff != "" {
|
||||||
t.Errorf("GetAllKeys: -got +want %s", diff)
|
t.Errorf("GetAllKeys: -got +want %s", diff)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTraceStatePropagation(t *testing.T) {
|
func TestTraceStatePropagation(t *testing.T) {
|
||||||
props := propagation.New(propagation.WithInjectors(propagators.TraceContext{}), propagation.WithExtractors(propagators.TraceContext{}))
|
prop := propagators.TraceContext{}
|
||||||
want := "opaquevalue"
|
want := "opaquevalue"
|
||||||
headerName := "tracestate"
|
headerName := "tracestate"
|
||||||
|
|
||||||
inReq, _ := http.NewRequest(http.MethodGet, "http://example.com", nil)
|
inReq, _ := http.NewRequest(http.MethodGet, "http://example.com", nil)
|
||||||
inReq.Header.Add(headerName, want)
|
inReq.Header.Add(headerName, want)
|
||||||
ctx := propagation.ExtractHTTP(context.Background(), props, inReq.Header)
|
ctx := prop.Extract(context.Background(), inReq.Header)
|
||||||
|
|
||||||
outReq, _ := http.NewRequest(http.MethodGet, "http://www.example.com", nil)
|
outReq, _ := http.NewRequest(http.MethodGet, "http://www.example.com", nil)
|
||||||
propagation.InjectHTTP(ctx, props, outReq.Header)
|
prop.Inject(ctx, outReq.Header)
|
||||||
|
|
||||||
if diff := cmp.Diff(outReq.Header.Get(headerName), want); diff != "" {
|
if diff := cmp.Diff(outReq.Header.Get(headerName), want); diff != "" {
|
||||||
t.Errorf("Propagate tracestate: -got +want %s", diff)
|
t.Errorf("Propagate tracestate: -got +want %s", diff)
|
||||||
|
Reference in New Issue
Block a user