traefik/vendor/github.com/instana/go-sensor/propagation.go
2019-02-18 16:52:03 +01:00

165 lines
3.3 KiB
Go

package instana
import (
"net/http"
"strconv"
"strings"
ot "github.com/opentracing/opentracing-go"
)
type textMapPropagator struct {
tracer *tracerS
}
// Instana header constants
const (
// FieldT Trace ID header
FieldT = "x-instana-t"
// FieldS Span ID header
FieldS = "x-instana-s"
// FieldL Level header
FieldL = "x-instana-l"
// FieldB OT Baggage header
FieldB = "x-instana-b-"
fieldCount = 2
)
func (r *textMapPropagator) inject(spanContext ot.SpanContext, opaqueCarrier interface{}) error {
sc, ok := spanContext.(SpanContext)
if !ok {
return ot.ErrInvalidSpanContext
}
roCarrier, ok := opaqueCarrier.(ot.TextMapReader)
if !ok {
return ot.ErrInvalidCarrier
}
// Handle pre-existing case-sensitive keys
var (
exstfieldT = FieldT
exstfieldS = FieldS
exstfieldL = FieldL
exstfieldB = FieldB
)
roCarrier.ForeachKey(func(k, v string) error {
switch strings.ToLower(k) {
case FieldT:
exstfieldT = k
case FieldS:
exstfieldS = k
case FieldL:
exstfieldL = k
default:
if strings.HasPrefix(strings.ToLower(k), FieldB) {
exstfieldB = string([]rune(k)[0:len(FieldB)])
}
}
return nil
})
carrier, ok := opaqueCarrier.(ot.TextMapWriter)
if !ok {
return ot.ErrInvalidCarrier
}
hhcarrier, ok := opaqueCarrier.(ot.HTTPHeadersCarrier)
if ok {
// If http.Headers has pre-existing keys, calling Set() like we do
// below will just append to those existing values and break context
// propagation. So defend against that case, we delete any pre-existing
// keys entirely first.
y := http.Header(hhcarrier)
y.Del(exstfieldT)
y.Del(exstfieldS)
y.Del(exstfieldL)
for key := range y {
if strings.HasPrefix(strings.ToLower(key), FieldB) {
y.Del(key)
}
}
}
if instanaTID, err := ID2Header(sc.TraceID); err == nil {
carrier.Set(exstfieldT, instanaTID)
} else {
log.debug(err)
}
if instanaSID, err := ID2Header(sc.SpanID); err == nil {
carrier.Set(exstfieldS, instanaSID)
} else {
log.debug(err)
}
carrier.Set(exstfieldL, strconv.Itoa(1))
for k, v := range sc.Baggage {
carrier.Set(exstfieldB+k, v)
}
return nil
}
func (r *textMapPropagator) extract(opaqueCarrier interface{}) (ot.SpanContext, error) {
carrier, ok := opaqueCarrier.(ot.TextMapReader)
if !ok {
return nil, ot.ErrInvalidCarrier
}
fieldCount := 0
var traceID, spanID int64
var err error
baggage := make(map[string]string)
err = carrier.ForeachKey(func(k, v string) error {
switch strings.ToLower(k) {
case FieldT:
fieldCount++
traceID, err = Header2ID(v)
if err != nil {
return ot.ErrSpanContextCorrupted
}
case FieldS:
fieldCount++
spanID, err = Header2ID(v)
if err != nil {
return ot.ErrSpanContextCorrupted
}
default:
lk := strings.ToLower(k)
if strings.HasPrefix(lk, FieldB) {
baggage[strings.TrimPrefix(lk, FieldB)] = v
}
}
return nil
})
return r.finishExtract(err, fieldCount, traceID, spanID, baggage)
}
func (r *textMapPropagator) finishExtract(err error,
fieldCount int,
traceID int64,
spanID int64,
baggage map[string]string) (ot.SpanContext, error) {
if err != nil {
return nil, err
}
if fieldCount < 2 {
if fieldCount == 0 {
return nil, ot.ErrSpanContextNotFound
}
return nil, ot.ErrSpanContextCorrupted
}
return SpanContext{
TraceID: traceID,
SpanID: spanID,
Sampled: false,
Baggage: baggage,
}, nil
}