traefik/vendor/github.com/uber/jaeger-client-go/zipkin/propagation.go
2019-04-05 11:58:06 +02:00

121 lines
3.6 KiB
Go

// Copyright (c) 2017 Uber Technologies, Inc.
//
// 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 zipkin
import (
"strconv"
"strings"
opentracing "github.com/opentracing/opentracing-go"
"github.com/uber/jaeger-client-go"
)
// Option is a function that sets an option on Propagator
type Option func(propagator *Propagator)
// BaggagePrefix is a function that sets baggage prefix on Propagator
func BaggagePrefix(prefix string) Option {
return func(propagator *Propagator) {
propagator.baggagePrefix = prefix
}
}
// Propagator is an Injector and Extractor
type Propagator struct {
baggagePrefix string
}
// NewZipkinB3HTTPHeaderPropagator creates a Propagator for extracting and injecting
// Zipkin HTTP B3 headers into SpanContexts. Baggage is by default enabled and uses prefix
// 'baggage-'.
func NewZipkinB3HTTPHeaderPropagator(opts ...Option) Propagator {
p := Propagator{baggagePrefix: "baggage-"}
for _, opt := range opts {
opt(&p)
}
return p
}
// Inject conforms to the Injector interface for decoding Zipkin HTTP B3 headers
func (p Propagator) Inject(
sc jaeger.SpanContext,
abstractCarrier interface{},
) error {
textMapWriter, ok := abstractCarrier.(opentracing.TextMapWriter)
if !ok {
return opentracing.ErrInvalidCarrier
}
textMapWriter.Set("x-b3-traceid", sc.TraceID().String())
if sc.ParentID() != 0 {
textMapWriter.Set("x-b3-parentspanid", strconv.FormatUint(uint64(sc.ParentID()), 16))
}
textMapWriter.Set("x-b3-spanid", strconv.FormatUint(uint64(sc.SpanID()), 16))
if sc.IsSampled() {
textMapWriter.Set("x-b3-sampled", "1")
} else {
textMapWriter.Set("x-b3-sampled", "0")
}
sc.ForeachBaggageItem(func(k, v string) bool {
textMapWriter.Set(p.baggagePrefix+k, v)
return true
})
return nil
}
// Extract conforms to the Extractor interface for encoding Zipkin HTTP B3 headers
func (p Propagator) Extract(abstractCarrier interface{}) (jaeger.SpanContext, error) {
textMapReader, ok := abstractCarrier.(opentracing.TextMapReader)
if !ok {
return jaeger.SpanContext{}, opentracing.ErrInvalidCarrier
}
var traceID jaeger.TraceID
var spanID uint64
var parentID uint64
sampled := false
var baggage map[string]string
err := textMapReader.ForeachKey(func(rawKey, value string) error {
key := strings.ToLower(rawKey) // TODO not necessary for plain TextMap
var err error
if key == "x-b3-traceid" {
traceID, err = jaeger.TraceIDFromString(value)
} else if key == "x-b3-parentspanid" {
parentID, err = strconv.ParseUint(value, 16, 64)
} else if key == "x-b3-spanid" {
spanID, err = strconv.ParseUint(value, 16, 64)
} else if key == "x-b3-sampled" && (value == "1" || value == "true") {
sampled = true
} else if strings.HasPrefix(key, p.baggagePrefix) {
if baggage == nil {
baggage = make(map[string]string)
}
baggage[key[len(p.baggagePrefix):]] = value
}
return err
})
if err != nil {
return jaeger.SpanContext{}, err
}
if !traceID.IsValid() {
return jaeger.SpanContext{}, opentracing.ErrSpanContextNotFound
}
return jaeger.NewSpanContext(
traceID,
jaeger.SpanID(spanID),
jaeger.SpanID(parentID),
sampled, baggage), nil
}