mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-02-09 13:37:12 +02:00
Refactor propagators (#467)
* Remove binary propagators They are in process of being dropped from the specification and we haven't be using them anywhere in the project. Can reintroduce them later. * Rename Supplier to HTTPSupplier The supplier is used only in HTTP propagators currently. It's not clear if it will be useful for binary propagators if they get to be specified at some point. * Rework propagation interfaces The biggest change here is that HTTP extractors return a new context with whatever information the propagator is able to retrieve from the supplier. Such interface does not hardcode any extractor's functionality (like it was before by explicitly returning a span context and correlation context) and makes it easy to chain multiple propagators. Injection part hasn't changed. * Add Propagators interface This interface (and its default implementation) is likely going to be the propagation API used the most. Single injectors, extractors or propagators are likely going to be used just as parameters to the Option functions that configure the Propagators implementation. * Drop noop propagator It's rather pointless - just create an empty Propagators instance. * Fix wrong name in docs Co-authored-by: Joshua MacDonald <jmacd@users.noreply.github.com>
This commit is contained in:
parent
c3974513aa
commit
cf7a4d909c
@ -1,80 +0,0 @@
|
||||
// Copyright 2019, 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 (
|
||||
"go.opentelemetry.io/otel/api/core"
|
||||
)
|
||||
|
||||
// BinaryFormat is an interface that specifies methods to convert SpanContext
|
||||
// to/from byte array.
|
||||
type BinaryFormat interface {
|
||||
// ToBytes serializes span context into a byte array and returns the array.
|
||||
ToBytes(sc core.SpanContext) []byte
|
||||
|
||||
// FromBytes de-serializes byte array into span context and returns the span context.
|
||||
FromBytes([]byte) core.SpanContext
|
||||
}
|
||||
|
||||
var _ BinaryFormat = binary{}
|
||||
|
||||
type binary struct{}
|
||||
|
||||
// Binary creates a new propagator. The propagator implements
|
||||
// ToBytes and FromBytes method to transform SpanContext to/from byte array.
|
||||
func Binary() BinaryFormat {
|
||||
return binary{}
|
||||
}
|
||||
|
||||
// ToBytes implements ToBytes method of propagators.BinaryFormat.
|
||||
// It serializes core.SpanContext into a byte array.
|
||||
func (bp binary) ToBytes(sc core.SpanContext) []byte {
|
||||
if sc == core.EmptySpanContext() {
|
||||
return nil
|
||||
}
|
||||
var b [29]byte
|
||||
copy(b[2:18], sc.TraceID[:])
|
||||
b[18] = 1
|
||||
copy(b[19:27], sc.SpanID[:])
|
||||
b[27] = 2
|
||||
b[28] = sc.TraceFlags
|
||||
return b[:]
|
||||
}
|
||||
|
||||
// FromBytes implements FromBytes method of propagators.BinaryFormat.
|
||||
// It de-serializes bytes into core.SpanContext.
|
||||
func (bp binary) FromBytes(b []byte) (sc core.SpanContext) {
|
||||
if len(b) == 0 {
|
||||
return core.EmptySpanContext()
|
||||
}
|
||||
b = b[1:]
|
||||
if len(b) >= 17 && b[0] == 0 {
|
||||
copy(sc.TraceID[:], b[1:17])
|
||||
b = b[17:]
|
||||
} else {
|
||||
return core.EmptySpanContext()
|
||||
}
|
||||
if len(b) >= 9 && b[0] == 1 {
|
||||
copy(sc.SpanID[:], b[1:9])
|
||||
b = b[9:]
|
||||
}
|
||||
if len(b) >= 2 && b[0] == 2 {
|
||||
sc.TraceFlags = b[1]
|
||||
}
|
||||
if sc.IsValid() {
|
||||
return sc
|
||||
}
|
||||
return core.EmptySpanContext()
|
||||
}
|
@ -1,170 +0,0 @@
|
||||
// Copyright 2019, 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_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"go.opentelemetry.io/otel/api/core"
|
||||
"go.opentelemetry.io/otel/api/propagation"
|
||||
)
|
||||
|
||||
func TestExtractSpanContextFromBytes(t *testing.T) {
|
||||
traceID, _ := core.TraceIDFromHex("4bf92f3577b34da6a3ce929d0e0e4736")
|
||||
spanID, _ := core.SpanIDFromHex("00f067aa0ba902b7")
|
||||
|
||||
propagator := propagation.Binary()
|
||||
tests := []struct {
|
||||
name string
|
||||
bytes []byte
|
||||
wantSc core.SpanContext
|
||||
}{
|
||||
{
|
||||
name: "future version of the proto",
|
||||
bytes: []byte{
|
||||
0x02, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36,
|
||||
0x01, 0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7,
|
||||
0x02, 0x01,
|
||||
},
|
||||
wantSc: core.SpanContext{
|
||||
TraceID: traceID,
|
||||
SpanID: spanID,
|
||||
TraceFlags: core.TraceFlagsSampled,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "current version with valid SpanContext and with Sampled bit set",
|
||||
bytes: []byte{
|
||||
0x00, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36,
|
||||
0x01, 0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7,
|
||||
0x02, 0x01,
|
||||
},
|
||||
wantSc: core.SpanContext{
|
||||
TraceID: traceID,
|
||||
SpanID: spanID,
|
||||
TraceFlags: core.TraceFlagsSampled,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid SpanContext without option",
|
||||
bytes: []byte{
|
||||
0x00, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36,
|
||||
0x01, 0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7,
|
||||
},
|
||||
wantSc: core.SpanContext{
|
||||
TraceID: traceID,
|
||||
SpanID: spanID,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "zero trace ID",
|
||||
bytes: []byte{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x01,
|
||||
},
|
||||
wantSc: core.EmptySpanContext(),
|
||||
},
|
||||
{
|
||||
name: "zero span ID",
|
||||
bytes: []byte{
|
||||
0x00, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x01,
|
||||
},
|
||||
wantSc: core.EmptySpanContext(),
|
||||
},
|
||||
{
|
||||
name: "wrong trace ID field number",
|
||||
bytes: []byte{
|
||||
0x00, 0x01, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36,
|
||||
0x01, 0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7,
|
||||
},
|
||||
wantSc: core.EmptySpanContext(),
|
||||
},
|
||||
{
|
||||
name: "short byte array",
|
||||
bytes: []byte{
|
||||
0x00, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d,
|
||||
},
|
||||
wantSc: core.EmptySpanContext(),
|
||||
},
|
||||
{
|
||||
name: "nil byte array",
|
||||
wantSc: core.EmptySpanContext(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotSc := propagator.FromBytes(tt.bytes)
|
||||
if diff := cmp.Diff(gotSc, tt.wantSc); diff != "" {
|
||||
t.Errorf("Deserialize SpanContext from byte array: %s: -got +want %s", tt.name, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertSpanContextToBytes(t *testing.T) {
|
||||
traceID, _ := core.TraceIDFromHex("4bf92f3577b34da6a3ce929d0e0e4736")
|
||||
spanID, _ := core.SpanIDFromHex("00f067aa0ba902b7")
|
||||
|
||||
propagator := propagation.Binary()
|
||||
tests := []struct {
|
||||
name string
|
||||
sc core.SpanContext
|
||||
bytes []byte
|
||||
}{
|
||||
{
|
||||
name: "valid SpanContext, with sampling bit set",
|
||||
sc: core.SpanContext{
|
||||
TraceID: traceID,
|
||||
SpanID: spanID,
|
||||
TraceFlags: core.TraceFlagsSampled,
|
||||
},
|
||||
bytes: []byte{
|
||||
0x00, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36,
|
||||
0x01, 0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7,
|
||||
0x02, 0x01,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid SpanContext, with sampling bit cleared",
|
||||
sc: core.SpanContext{
|
||||
TraceID: traceID,
|
||||
SpanID: spanID,
|
||||
},
|
||||
bytes: []byte{
|
||||
0x00, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36,
|
||||
0x01, 0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7,
|
||||
0x02, 0x00,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid spancontext",
|
||||
sc: core.EmptySpanContext(),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotBytes := propagator.ToBytes(tt.sc)
|
||||
if diff := cmp.Diff(gotBytes, tt.bytes); diff != "" {
|
||||
t.Errorf("Serialize SpanContext to byte array: %s: -got +want %s", tt.name, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -12,6 +12,5 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package propagation contains interface definition for BinaryFormat and
|
||||
// TextFormat propagators.
|
||||
// Package propagation contains interface definition for HTTP propagators.
|
||||
package propagation // import "go.opentelemetry.io/otel/api/propagation"
|
||||
|
143
api/propagation/propagation.go
Normal file
143
api/propagation/propagation.go
Normal file
@ -0,0 +1,143 @@
|
||||
// Copyright 2019, 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(context.Context, 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(context.Context, 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)
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
// Copyright 2019, 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"
|
||||
|
||||
"go.opentelemetry.io/otel/api/core"
|
||||
"go.opentelemetry.io/otel/api/correlation"
|
||||
)
|
||||
|
||||
// NoopTextFormat implements TextFormat that does nothing.
|
||||
type NoopTextFormat struct{}
|
||||
|
||||
var _ TextFormat = NoopTextFormat{}
|
||||
|
||||
// Inject does nothing.
|
||||
func (np NoopTextFormat) Inject(ctx context.Context, supplier Supplier) {
|
||||
}
|
||||
|
||||
// Extract does nothing and returns an empty SpanContext
|
||||
func (np NoopTextFormat) Extract(ctx context.Context, supplier Supplier) (core.SpanContext, correlation.Map) {
|
||||
return core.EmptySpanContext(), correlation.NewEmptyMap()
|
||||
}
|
||||
|
||||
// GetAllKeys returns empty list of strings.
|
||||
func (np NoopTextFormat) GetAllKeys() []string {
|
||||
return []string{}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
// Copyright 2019, 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"
|
||||
|
||||
"go.opentelemetry.io/otel/api/core"
|
||||
"go.opentelemetry.io/otel/api/correlation"
|
||||
)
|
||||
|
||||
// TextFormat is an interface that specifies methods to inject and extract SpanContext
|
||||
// and distributed context into/from a carrier using Supplier interface.
|
||||
// For example, HTTP Trace Context propagator would encode SpanContext into W3C Trace
|
||||
// Context Header and set the header into HttpRequest.
|
||||
type TextFormat interface {
|
||||
// Inject method retrieves current SpanContext from the ctx, encodes it into propagator
|
||||
// specific format and then injects the encoded SpanContext using supplier into a carrier
|
||||
// associated with the supplier. It also takes a correlationCtx whose values will be
|
||||
// injected into a carrier using the supplier.
|
||||
Inject(ctx context.Context, supplier Supplier)
|
||||
|
||||
// Extract method retrieves encoded SpanContext using supplier from the associated carrier.
|
||||
// It decodes the SpanContext and returns it and a baggage of correlated context.
|
||||
// If no SpanContext was retrieved OR if the retrieved SpanContext is invalid then
|
||||
// an empty SpanContext is returned.
|
||||
Extract(ctx context.Context, supplier Supplier) (core.SpanContext, correlation.Map)
|
||||
|
||||
// GetAllKeys returns all the keys that this propagator injects/extracts into/from a
|
||||
// carrier. The use cases for this are
|
||||
// * allow pre-allocation of fields, especially in systems like gRPC Metadata
|
||||
// * allow a single-pass over an iterator (ex OpenTracing has no getter in TextMap)
|
||||
GetAllKeys() []string
|
||||
}
|
||||
|
||||
// Supplier is an interface that specifies methods to retrieve and store
|
||||
// value for a key to an associated carrier.
|
||||
// Get method retrieves the value for a given key.
|
||||
// Set method stores the value for a given key.
|
||||
type Supplier interface {
|
||||
Get(key string) string
|
||||
Set(key string, value string)
|
||||
}
|
@ -20,7 +20,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"go.opentelemetry.io/otel/api/core"
|
||||
"go.opentelemetry.io/otel/api/correlation"
|
||||
"go.opentelemetry.io/otel/api/propagation"
|
||||
)
|
||||
|
||||
@ -50,9 +49,9 @@ type B3 struct {
|
||||
SingleHeader bool
|
||||
}
|
||||
|
||||
var _ propagation.TextFormat = B3{}
|
||||
var _ propagation.HTTPPropagator = B3{}
|
||||
|
||||
func (b3 B3) Inject(ctx context.Context, supplier propagation.Supplier) {
|
||||
func (b3 B3) Inject(ctx context.Context, supplier propagation.HTTPSupplier) {
|
||||
sc := SpanFromContext(ctx).SpanContext()
|
||||
if sc.IsValid() {
|
||||
if b3.SingleHeader {
|
||||
@ -76,21 +75,17 @@ func (b3 B3) Inject(ctx context.Context, supplier propagation.Supplier) {
|
||||
}
|
||||
|
||||
// Extract retrieves B3 Headers from the supplier
|
||||
func (b3 B3) Extract(ctx context.Context, supplier propagation.Supplier) (core.SpanContext, correlation.Map) {
|
||||
func (b3 B3) Extract(ctx context.Context, supplier propagation.HTTPSupplier) context.Context {
|
||||
var sc core.SpanContext
|
||||
if b3.SingleHeader {
|
||||
return b3.extractSingleHeader(supplier), correlation.NewEmptyMap()
|
||||
sc = b3.extractSingleHeader(supplier)
|
||||
} else {
|
||||
sc = b3.extract(supplier)
|
||||
}
|
||||
return b3.extract(supplier), correlation.NewEmptyMap()
|
||||
return ContextWithRemoteSpanContext(ctx, sc)
|
||||
}
|
||||
|
||||
func (b3 B3) GetAllKeys() []string {
|
||||
if b3.SingleHeader {
|
||||
return []string{B3SingleHeader}
|
||||
}
|
||||
return []string{B3TraceIDHeader, B3SpanIDHeader, B3SampledHeader}
|
||||
}
|
||||
|
||||
func (b3 B3) extract(supplier propagation.Supplier) core.SpanContext {
|
||||
func (b3 B3) extract(supplier propagation.HTTPSupplier) core.SpanContext {
|
||||
tid, err := core.TraceIDFromHex(supplier.Get(B3TraceIDHeader))
|
||||
if err != nil {
|
||||
return core.EmptySpanContext()
|
||||
@ -125,10 +120,10 @@ func (b3 B3) extract(supplier propagation.Supplier) core.SpanContext {
|
||||
return sc
|
||||
}
|
||||
|
||||
func (b3 B3) extractSingleHeader(supplier propagation.Supplier) core.SpanContext {
|
||||
func (b3 B3) extractSingleHeader(supplier propagation.HTTPSupplier) core.SpanContext {
|
||||
h := supplier.Get(B3SingleHeader)
|
||||
if h == "" || h == "0" {
|
||||
core.EmptySpanContext()
|
||||
return core.EmptySpanContext()
|
||||
}
|
||||
sc := core.SpanContext{}
|
||||
parts := strings.Split(h, "-")
|
||||
@ -202,3 +197,10 @@ func (b3 B3) extracDebugFlag(debug string) (flag byte, ok bool) {
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func (b3 B3) GetAllKeys() []string {
|
||||
if b3.SingleHeader {
|
||||
return []string{B3SingleHeader}
|
||||
}
|
||||
return []string{B3TraceIDHeader, B3SpanIDHeader, B3SampledHeader}
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ func BenchmarkExtractB3(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = propagator.Extract(ctx, req.Header)
|
||||
_ = propagator.Extract(ctx, req.Header)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"go.opentelemetry.io/otel/api/propagation"
|
||||
"go.opentelemetry.io/otel/api/trace"
|
||||
mocktrace "go.opentelemetry.io/otel/internal/trace"
|
||||
)
|
||||
@ -55,6 +56,8 @@ func TestExtractB3(t *testing.T) {
|
||||
|
||||
for _, tg := range testGroup {
|
||||
propagator := trace.B3{SingleHeader: tg.singleHeader}
|
||||
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)
|
||||
@ -63,7 +66,8 @@ func TestExtractB3(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
gotSc, _ := propagator.Extract(ctx, req.Header)
|
||||
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)
|
||||
}
|
||||
@ -99,6 +103,7 @@ func TestInjectB3(t *testing.T) {
|
||||
for _, tg := range testGroup {
|
||||
id = 0
|
||||
propagator := trace.B3{SingleHeader: tg.singleHeader}
|
||||
props := propagation.New(propagation.WithInjectors(propagator))
|
||||
for _, tt := range tg.tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", "http://example.com", nil)
|
||||
@ -107,7 +112,7 @@ func TestInjectB3(t *testing.T) {
|
||||
ctx = trace.ContextWithRemoteSpanContext(ctx, tt.parentSc)
|
||||
}
|
||||
ctx, _ = mockTracer.Start(ctx, "inject")
|
||||
propagator.Inject(ctx, req.Header)
|
||||
propagation.InjectHTTP(ctx, props, req.Header)
|
||||
|
||||
for h, v := range tt.wantHeaders {
|
||||
got, want := req.Header.Get(h), v
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"go.opentelemetry.io/otel/api/core"
|
||||
"go.opentelemetry.io/otel/api/correlation"
|
||||
"go.opentelemetry.io/otel/api/key"
|
||||
"go.opentelemetry.io/otel/api/propagation"
|
||||
"go.opentelemetry.io/otel/api/trace"
|
||||
mocktrace "go.opentelemetry.io/otel/internal/trace"
|
||||
)
|
||||
@ -45,7 +46,7 @@ func mustSpanIDFromHex(s string) (t core.SpanID) {
|
||||
}
|
||||
|
||||
func TestExtractValidTraceContextFromHTTPReq(t *testing.T) {
|
||||
var propagator trace.TraceContext
|
||||
props := propagation.New(propagation.WithExtractors(trace.TraceContext{}))
|
||||
tests := []struct {
|
||||
name string
|
||||
header string
|
||||
@ -129,7 +130,8 @@ func TestExtractValidTraceContextFromHTTPReq(t *testing.T) {
|
||||
req.Header.Set("traceparent", tt.header)
|
||||
|
||||
ctx := context.Background()
|
||||
gotSc, _ := propagator.Extract(ctx, req.Header)
|
||||
ctx = propagation.ExtractHTTP(ctx, props, req.Header)
|
||||
gotSc := trace.RemoteSpanContextFromContext(ctx)
|
||||
if diff := cmp.Diff(gotSc, tt.wantSc); diff != "" {
|
||||
t.Errorf("Extract Tracecontext: %s: -got +want %s", tt.name, diff)
|
||||
}
|
||||
@ -138,8 +140,8 @@ func TestExtractValidTraceContextFromHTTPReq(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestExtractInvalidTraceContextFromHTTPReq(t *testing.T) {
|
||||
var propagator trace.TraceContext
|
||||
wantSc := core.EmptySpanContext()
|
||||
props := propagation.New(propagation.WithExtractors(trace.TraceContext{}))
|
||||
tests := []struct {
|
||||
name string
|
||||
header string
|
||||
@ -216,7 +218,8 @@ func TestExtractInvalidTraceContextFromHTTPReq(t *testing.T) {
|
||||
req.Header.Set("traceparent", tt.header)
|
||||
|
||||
ctx := context.Background()
|
||||
gotSc, _ := propagator.Extract(ctx, req.Header)
|
||||
ctx = propagation.ExtractHTTP(ctx, props, req.Header)
|
||||
gotSc := trace.RemoteSpanContextFromContext(ctx)
|
||||
if diff := cmp.Diff(gotSc, wantSc); diff != "" {
|
||||
t.Errorf("Extract Tracecontext: %s: -got +want %s", tt.name, diff)
|
||||
}
|
||||
@ -230,7 +233,7 @@ func TestInjectTraceContextToHTTPReq(t *testing.T) {
|
||||
Sampled: false,
|
||||
StartSpanID: &id,
|
||||
}
|
||||
var propagator trace.TraceContext
|
||||
props := propagation.New(propagation.WithInjectors(trace.TraceContext{}))
|
||||
tests := []struct {
|
||||
name string
|
||||
sc core.SpanContext
|
||||
@ -276,7 +279,7 @@ func TestInjectTraceContextToHTTPReq(t *testing.T) {
|
||||
ctx = trace.ContextWithRemoteSpanContext(ctx, tt.sc)
|
||||
ctx, _ = mockTracer.Start(ctx, "inject")
|
||||
}
|
||||
propagator.Inject(ctx, req.Header)
|
||||
propagation.InjectHTTP(ctx, props, req.Header)
|
||||
|
||||
gotHeader := req.Header.Get("traceparent")
|
||||
if diff := cmp.Diff(gotHeader, tt.wantHeader); diff != "" {
|
||||
@ -288,6 +291,7 @@ func TestInjectTraceContextToHTTPReq(t *testing.T) {
|
||||
|
||||
func TestExtractValidDistributedContextFromHTTPReq(t *testing.T) {
|
||||
propagator := trace.TraceContext{}
|
||||
props := propagation.New(propagation.WithExtractors(propagator))
|
||||
tests := []struct {
|
||||
name string
|
||||
header string
|
||||
@ -349,7 +353,8 @@ func TestExtractValidDistributedContextFromHTTPReq(t *testing.T) {
|
||||
req.Header.Set("Correlation-Context", tt.header)
|
||||
|
||||
ctx := context.Background()
|
||||
_, gotCorCtx := propagator.Extract(ctx, req.Header)
|
||||
ctx = propagation.ExtractHTTP(ctx, props, req.Header)
|
||||
gotCorCtx := correlation.FromContext(ctx)
|
||||
wantCorCtx := correlation.NewMap(correlation.MapUpdate{MultiKV: tt.wantKVs})
|
||||
if gotCorCtx.Len() != wantCorCtx.Len() {
|
||||
t.Errorf(
|
||||
@ -376,6 +381,7 @@ func TestExtractValidDistributedContextFromHTTPReq(t *testing.T) {
|
||||
|
||||
func TestExtractInvalidDistributedContextFromHTTPReq(t *testing.T) {
|
||||
propagator := trace.TraceContext{}
|
||||
props := propagation.New(propagation.WithExtractors(propagator))
|
||||
tests := []struct {
|
||||
name string
|
||||
header string
|
||||
@ -392,7 +398,8 @@ func TestExtractInvalidDistributedContextFromHTTPReq(t *testing.T) {
|
||||
req.Header.Set("Correlation-Context", tt.header)
|
||||
|
||||
ctx := context.Background()
|
||||
_, gotCorCtx := propagator.Extract(ctx, req.Header)
|
||||
ctx = propagation.ExtractHTTP(ctx, props, req.Header)
|
||||
gotCorCtx := correlation.FromContext(ctx)
|
||||
if gotCorCtx.Len() != 0 {
|
||||
t.Errorf("Got and Want CorCtx are not the same size %d != %d", gotCorCtx.Len(), 0)
|
||||
}
|
||||
@ -402,6 +409,7 @@ func TestExtractInvalidDistributedContextFromHTTPReq(t *testing.T) {
|
||||
|
||||
func TestInjectCorrelationContextToHTTPReq(t *testing.T) {
|
||||
propagator := trace.TraceContext{}
|
||||
props := propagation.New(propagation.WithInjectors(propagator))
|
||||
tests := []struct {
|
||||
name string
|
||||
kvs []core.KeyValue
|
||||
@ -454,7 +462,7 @@ func TestInjectCorrelationContextToHTTPReq(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", "http://example.com", nil)
|
||||
ctx := correlation.WithMap(context.Background(), correlation.NewMap(correlation.MapUpdate{MultiKV: tt.kvs}))
|
||||
propagator.Inject(ctx, req.Header)
|
||||
propagation.InjectHTTP(ctx, props, req.Header)
|
||||
|
||||
gotHeader := req.Header.Get("Correlation-Context")
|
||||
wantedLen := len(strings.Join(tt.wantInHeader, ","))
|
||||
|
@ -39,15 +39,15 @@ const (
|
||||
//nolint:golint
|
||||
type TraceContext struct{}
|
||||
|
||||
var _ propagation.TextFormat = TraceContext{}
|
||||
var _ propagation.HTTPPropagator = TraceContext{}
|
||||
var traceCtxRegExp = regexp.MustCompile("^[0-9a-f]{2}-[a-f0-9]{32}-[a-f0-9]{16}-[a-f0-9]{2}-?")
|
||||
|
||||
// DefaultPropagator returns the default trace propagator.
|
||||
func DefaultPropagator() propagation.TextFormat {
|
||||
// DefaultHTTPPropagator returns the default trace HTTP propagator.
|
||||
func DefaultHTTPPropagator() propagation.HTTPPropagator {
|
||||
return TraceContext{}
|
||||
}
|
||||
|
||||
func (hp TraceContext) Inject(ctx context.Context, supplier propagation.Supplier) {
|
||||
func (TraceContext) Inject(ctx context.Context, supplier propagation.HTTPSupplier) {
|
||||
sc := SpanFromContext(ctx).SpanContext()
|
||||
if sc.IsValid() {
|
||||
h := fmt.Sprintf("%.2x-%s-%.16x-%.2x",
|
||||
@ -77,15 +77,11 @@ func (hp TraceContext) Inject(ctx context.Context, supplier propagation.Supplier
|
||||
}
|
||||
}
|
||||
|
||||
func (hp TraceContext) Extract(
|
||||
ctx context.Context, supplier propagation.Supplier,
|
||||
) (core.SpanContext, correlation.Map) {
|
||||
return hp.extractSpanContext(ctx, supplier), hp.extractCorrelationCtx(ctx, supplier)
|
||||
func (tc TraceContext) Extract(ctx context.Context, supplier propagation.HTTPSupplier) context.Context {
|
||||
return correlation.WithMap(ContextWithRemoteSpanContext(ctx, tc.extractSpanContext(supplier)), tc.extractCorrelationCtx(supplier))
|
||||
}
|
||||
|
||||
func (hp TraceContext) extractSpanContext(
|
||||
ctx context.Context, supplier propagation.Supplier,
|
||||
) core.SpanContext {
|
||||
func (TraceContext) extractSpanContext(supplier propagation.HTTPSupplier) core.SpanContext {
|
||||
h := supplier.Get(TraceparentHeader)
|
||||
if h == "" {
|
||||
return core.EmptySpanContext()
|
||||
@ -152,7 +148,7 @@ func (hp TraceContext) extractSpanContext(
|
||||
return sc
|
||||
}
|
||||
|
||||
func (hp TraceContext) extractCorrelationCtx(ctx context.Context, supplier propagation.Supplier) correlation.Map {
|
||||
func (TraceContext) extractCorrelationCtx(supplier propagation.HTTPSupplier) correlation.Map {
|
||||
correlationContext := supplier.Get(CorrelationContextHeader)
|
||||
if correlationContext == "" {
|
||||
return correlation.NewEmptyMap()
|
||||
@ -196,6 +192,6 @@ func (hp TraceContext) extractCorrelationCtx(ctx context.Context, supplier propa
|
||||
})
|
||||
}
|
||||
|
||||
func (hp TraceContext) GetAllKeys() []string {
|
||||
func (TraceContext) GetAllKeys() []string {
|
||||
return []string{TraceparentHeader, CorrelationContextHeader}
|
||||
}
|
||||
|
@ -20,11 +20,14 @@ import (
|
||||
"google.golang.org/grpc/metadata"
|
||||
|
||||
"go.opentelemetry.io/otel/api/core"
|
||||
"go.opentelemetry.io/otel/api/correlation"
|
||||
"go.opentelemetry.io/otel/api/propagation"
|
||||
"go.opentelemetry.io/otel/api/trace"
|
||||
)
|
||||
|
||||
var (
|
||||
propagator = trace.DefaultPropagator()
|
||||
propagator = trace.DefaultHTTPPropagator()
|
||||
propagators = propagation.New(propagation.WithInjectors(propagator), propagation.WithExtractors(propagator))
|
||||
)
|
||||
|
||||
type metadataSupplier struct {
|
||||
@ -47,7 +50,7 @@ func (s *metadataSupplier) Set(key string, value string) {
|
||||
// metadata object. This function is meant to be used on outgoing
|
||||
// requests.
|
||||
func Inject(ctx context.Context, metadata *metadata.MD) {
|
||||
propagator.Inject(ctx, &metadataSupplier{
|
||||
propagation.InjectHTTP(ctx, propagators, &metadataSupplier{
|
||||
metadata: metadata,
|
||||
})
|
||||
}
|
||||
@ -56,12 +59,13 @@ func Inject(ctx context.Context, metadata *metadata.MD) {
|
||||
// another service encoded in the gRPC metadata object with Inject.
|
||||
// This function is meant to be used on incoming requests.
|
||||
func Extract(ctx context.Context, metadata *metadata.MD) ([]core.KeyValue, core.SpanContext) {
|
||||
spanContext, correlationCtx := propagator.Extract(ctx, &metadataSupplier{
|
||||
ctx = propagation.ExtractHTTP(ctx, propagators, &metadataSupplier{
|
||||
metadata: metadata,
|
||||
})
|
||||
|
||||
spanContext := trace.RemoteSpanContextFromContext(ctx)
|
||||
var correlationCtxKVs []core.KeyValue
|
||||
correlationCtx.Foreach(func(kv core.KeyValue) bool {
|
||||
correlation.FromContext(ctx).Foreach(func(kv core.KeyValue) bool {
|
||||
correlationCtxKVs = append(correlationCtxKVs, kv)
|
||||
return true
|
||||
})
|
||||
|
@ -19,7 +19,9 @@ import (
|
||||
"net/http"
|
||||
|
||||
"go.opentelemetry.io/otel/api/core"
|
||||
"go.opentelemetry.io/otel/api/correlation"
|
||||
"go.opentelemetry.io/otel/api/key"
|
||||
"go.opentelemetry.io/otel/api/propagation"
|
||||
"go.opentelemetry.io/otel/api/trace"
|
||||
)
|
||||
|
||||
@ -27,12 +29,13 @@ var (
|
||||
HostKey = key.New("http.host")
|
||||
URLKey = key.New("http.url")
|
||||
|
||||
propagator = trace.DefaultPropagator()
|
||||
propagator = trace.DefaultHTTPPropagator()
|
||||
propagators = propagation.New(propagation.WithInjectors(propagator), propagation.WithExtractors(propagator))
|
||||
)
|
||||
|
||||
// Returns the Attributes, Context Entries, and SpanContext that were encoded by Inject.
|
||||
func Extract(ctx context.Context, req *http.Request) ([]core.KeyValue, []core.KeyValue, core.SpanContext) {
|
||||
sc, correlationCtx := propagator.Extract(ctx, req.Header)
|
||||
ctx = propagation.ExtractHTTP(ctx, propagators, req.Header)
|
||||
|
||||
attrs := []core.KeyValue{
|
||||
URLKey.String(req.URL.String()),
|
||||
@ -40,14 +43,14 @@ func Extract(ctx context.Context, req *http.Request) ([]core.KeyValue, []core.Ke
|
||||
}
|
||||
|
||||
var correlationCtxKVs []core.KeyValue
|
||||
correlationCtx.Foreach(func(kv core.KeyValue) bool {
|
||||
correlation.FromContext(ctx).Foreach(func(kv core.KeyValue) bool {
|
||||
correlationCtxKVs = append(correlationCtxKVs, kv)
|
||||
return true
|
||||
})
|
||||
|
||||
return attrs, correlationCtxKVs, sc
|
||||
return attrs, correlationCtxKVs, trace.RemoteSpanContextFromContext(ctx)
|
||||
}
|
||||
|
||||
func Inject(ctx context.Context, req *http.Request) {
|
||||
propagator.Inject(ctx, req.Header)
|
||||
propagation.InjectHTTP(ctx, propagators, req.Header)
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ type Handler struct {
|
||||
handler http.Handler
|
||||
|
||||
tracer trace.Tracer
|
||||
prop propagation.TextFormat
|
||||
props propagation.Propagators
|
||||
spanStartOptions []trace.StartOption
|
||||
public bool
|
||||
readEvent bool
|
||||
@ -77,12 +77,12 @@ func WithPublicEndpoint() Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithPropagator configures the Handler with a specific propagator. If this
|
||||
// option isn't specificed then
|
||||
// go.opentelemetry.io/otel/api/trace.DefaultPropagator is used.
|
||||
func WithPropagator(p propagation.TextFormat) Option {
|
||||
// WithPropagators configures the Handler with specific propagators. If this
|
||||
// option isn't specified then Propagators with
|
||||
// go.opentelemetry.io/otel/api/trace.DefaultHTTPPropagator are used.
|
||||
func WithPropagators(ps propagation.Propagators) Option {
|
||||
return func(h *Handler) {
|
||||
h.prop = p
|
||||
h.props = ps
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,9 +128,10 @@ func WithMessageEvents(events ...event) Option {
|
||||
// named after the operation and with any provided HandlerOptions.
|
||||
func NewHandler(handler http.Handler, operation string, opts ...Option) http.Handler {
|
||||
h := Handler{handler: handler, operation: operation}
|
||||
propagator := trace.DefaultHTTPPropagator()
|
||||
defaultOpts := []Option{
|
||||
WithTracer(global.TraceProvider().Tracer("go.opentelemetry.io/plugin/othttp")),
|
||||
WithPropagator(trace.DefaultPropagator()),
|
||||
WithPropagators(propagation.New(propagation.WithInjectors(propagator), propagation.WithExtractors(propagator))),
|
||||
WithSpanOptions(trace.WithSpanKind(trace.SpanKindServer)),
|
||||
}
|
||||
|
||||
@ -145,9 +146,10 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
opts := append([]trace.StartOption{}, h.spanStartOptions...) // start with the configured options
|
||||
|
||||
// TODO: do something with the correlation context
|
||||
sc, _ := h.prop.Extract(r.Context(), r.Header)
|
||||
ctx := r.Context()
|
||||
if sc.IsValid() { // not a valid span context, so no link / parent relationship to establish
|
||||
ctx := propagation.ExtractHTTP(r.Context(), h.props, r.Header)
|
||||
|
||||
// not a valid span context, so no link / parent relationship to establish
|
||||
if sc := trace.RemoteSpanContextFromContext(ctx); sc.IsValid() {
|
||||
var opt trace.StartOption
|
||||
if h.public {
|
||||
// If the endpoint is a public endpoint, it should start a new trace
|
||||
@ -178,7 +180,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
rww := &respWriterWrapper{ResponseWriter: w, record: writeRecordFunc, ctx: ctx, injector: h.prop}
|
||||
rww := &respWriterWrapper{ResponseWriter: w, record: writeRecordFunc, ctx: ctx, props: h.props}
|
||||
|
||||
// Setup basic span attributes before calling handler.ServeHTTP so that they
|
||||
// are available to be mutated by the handler if needed.
|
||||
|
@ -49,10 +49,6 @@ func (w *bodyWrapper) Close() error {
|
||||
|
||||
var _ http.ResponseWriter = &respWriterWrapper{}
|
||||
|
||||
type injector interface {
|
||||
Inject(context.Context, propagation.Supplier)
|
||||
}
|
||||
|
||||
// respWriterWrapper wraps a http.ResponseWriter in order to track the number of
|
||||
// bytes written, the last error, and to catch the returned statusCode
|
||||
// TODO: The wrapped http.ResponseWriter doesn't implement any of the optional
|
||||
@ -64,7 +60,8 @@ type respWriterWrapper struct {
|
||||
|
||||
// used to inject the header
|
||||
ctx context.Context
|
||||
injector
|
||||
|
||||
props propagation.Propagators
|
||||
|
||||
written int64
|
||||
statusCode int
|
||||
@ -95,6 +92,6 @@ func (w *respWriterWrapper) WriteHeader(statusCode int) {
|
||||
}
|
||||
w.wroteHeader = true
|
||||
w.statusCode = statusCode
|
||||
w.injector.Inject(w.ctx, w.Header())
|
||||
propagation.InjectHTTP(w.ctx, w.props, w.Header())
|
||||
w.ResponseWriter.WriteHeader(statusCode)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user