forked from tracer/tracer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpropagation.go
173 lines (155 loc) · 4.72 KB
/
propagation.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package tracer
import (
"encoding/binary"
"io"
"strconv"
"strings"
"github.com/opentracing/opentracing-go"
)
// An Extracter extracts a SpanContext from carrier.
type Extracter func(carrier interface{}) (SpanContext, error)
// An Injecter injects a SpanContext into carrier.
type Injecter func(sm SpanContext, carrier interface{}) error
var extracters = map[interface{}]Extracter{
opentracing.HTTPHeaders: textExtracter,
opentracing.TextMap: textExtracter,
opentracing.Binary: binaryExtracter,
}
var injecters = map[interface{}]Injecter{
opentracing.HTTPHeaders: textInjecter,
opentracing.TextMap: textInjecter,
opentracing.Binary: binaryInjecter,
}
// RegisterExtracter registers an Extracter.
func RegisterExtracter(format interface{}, extracter Extracter) {
extracters[format] = extracter
}
// RegisterInjecter registers an Injecter.
func RegisterInjecter(format interface{}, injecter Injecter) {
injecters[format] = injecter
}
// SpanContext contains the parts of a span that will be sent to
// downstream services.
type SpanContext struct {
TraceID uint64 `json:"trace_id"`
ParentID uint64 `json:"parent_id"`
SpanID uint64 `json:"span_id"`
Flags uint64 `json:"flags"`
Baggage map[string]string `json:"baggage"`
}
// ForeachBaggageItem implements the opentracing.Tracer interface.
func (c SpanContext) ForeachBaggageItem(handler func(k, v string) bool) {
for k, v := range c.Baggage {
if !handler(k, v) {
return
}
}
}
func textInjecter(sm SpanContext, carrier interface{}) error {
w, ok := carrier.(opentracing.TextMapWriter)
if !ok {
return opentracing.ErrInvalidCarrier
}
w.Set("tracer-traceid", idToHex(sm.TraceID))
w.Set("tracer-spanid", idToHex(sm.SpanID))
w.Set("tracer-parentspanid", idToHex(sm.ParentID))
w.Set("tracer-flags", strconv.FormatUint(sm.Flags, 10))
for k, v := range sm.Baggage {
w.Set("tracer-baggage-"+k, v)
}
return nil
}
func textExtracter(carrier interface{}) (SpanContext, error) {
r, ok := carrier.(opentracing.TextMapReader)
if !ok {
return SpanContext{}, opentracing.ErrInvalidCarrier
}
ctx := SpanContext{Baggage: map[string]string{}}
err := r.ForeachKey(func(key string, val string) error {
lower := strings.ToLower(key)
switch lower {
case "tracer-traceid":
ctx.TraceID = idFromHex(val)
case "tracer-spanid":
ctx.SpanID = idFromHex(val)
case "tracer-parentspanid":
ctx.ParentID = idFromHex(val)
case "tracer-flags":
ctx.Flags, _ = strconv.ParseUint(val, 10, 64)
default:
if strings.HasPrefix(lower, "tracer-baggage-") {
key = key[len("Tracer-Baggage-"):]
ctx.Baggage[key] = val
}
}
return nil
})
if ctx.TraceID == 0 {
return SpanContext{}, opentracing.ErrSpanContextNotFound
}
return ctx, err
}
func binaryInjecter(sm SpanContext, carrier interface{}) error {
w, ok := carrier.(io.Writer)
if !ok {
return opentracing.ErrInvalidCarrier
}
b := make([]byte, 8*5)
binary.BigEndian.PutUint64(b, sm.TraceID)
binary.BigEndian.PutUint64(b[8:], sm.SpanID)
binary.BigEndian.PutUint64(b[16:], sm.ParentID)
binary.BigEndian.PutUint64(b[24:], sm.Flags)
binary.BigEndian.PutUint64(b[32:], uint64(len(sm.Baggage)))
for k, v := range sm.Baggage {
b2 := make([]byte, 16+len(k)+len(v))
binary.BigEndian.PutUint64(b2, uint64(len(k)))
binary.BigEndian.PutUint64(b2[8:], uint64(len(v)))
copy(b2[16:], k)
copy(b2[16+len(k):], v)
b = append(b, b2...)
}
_, err := w.Write(b)
return err
}
func binaryExtracter(carrier interface{}) (SpanContext, error) {
r, ok := carrier.(io.Reader)
if !ok {
return SpanContext{}, opentracing.ErrInvalidCarrier
}
ctx := SpanContext{Baggage: map[string]string{}}
b := make([]byte, 8*5)
if _, err := io.ReadFull(r, b); err != nil {
if err == io.ErrUnexpectedEOF {
return SpanContext{}, opentracing.ErrSpanContextNotFound
}
return SpanContext{}, err
}
ctx.TraceID = binary.BigEndian.Uint64(b)
ctx.SpanID = binary.BigEndian.Uint64(b[8:])
ctx.ParentID = binary.BigEndian.Uint64(b[16:])
ctx.Flags = binary.BigEndian.Uint64(b[24:])
n := binary.BigEndian.Uint64(b[32:])
b = make([]byte, 8*2)
for i := uint64(0); i < n; i++ {
if _, err := io.ReadFull(r, b); err != nil {
if err == io.ErrUnexpectedEOF {
return SpanContext{}, opentracing.ErrSpanContextNotFound
}
return SpanContext{}, err
}
kl := int(binary.BigEndian.Uint64(b))
vl := int(binary.BigEndian.Uint64(b[8:]))
if kl <= 0 || vl < 0 {
return SpanContext{}, opentracing.ErrSpanContextNotFound
}
b2 := make([]byte, kl+vl)
if _, err := io.ReadFull(r, b2); err != nil {
if err == io.ErrUnexpectedEOF {
return SpanContext{}, opentracing.ErrSpanContextNotFound
}
return SpanContext{}, err
}
ctx.Baggage[string(b2[:kl])] = string(b2[kl:])
}
return ctx, nil
}