165 lines
3.3 KiB
Go
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
|
|
}
|