forked from xmidt-org/golang-money
-
Notifications
You must be signed in to change notification settings - Fork 1
/
trace.go
92 lines (75 loc) · 2.13 KB
/
trace.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
package money
import (
"errors"
"fmt"
"math/rand"
"strconv"
"strings"
"time"
)
//Trace Context decoding errors
var (
errPairsCount = errors.New("expecting three pairs in trace context")
errBadPair = errors.New("expected trace context header to have pairs")
errBadTrace = errors.New("malformatted trace context header")
)
//TraceContext encapsutes all the core information of any given span
//In a single trace, the TID is the same across all spans and
//the SID and the PID is what links all spans together
type TraceContext struct {
TID string //Trace ID
SID int64 //Span ID
PID int64 //Parent ID
}
//decodeTraceContext returns a TraceContext from the given value "raw"
//raw is typically taken directly from http.Request headers
//for now, it is overly strict with the expected format
//TODO: could we use regex here instead for simplicity?
func decodeTraceContext(raw string) (tc *TraceContext, err error) {
tc = new(TraceContext)
pairs := strings.Split(raw, ";")
if len(pairs) != 3 {
return nil, errPairsCount
}
seen := make(map[string]bool)
for _, pair := range pairs {
kv := strings.Split(pair, "=")
if len(kv) != 2 {
return nil, errBadPair
}
var k, v = kv[0], kv[1]
switch {
case k == tIDKey && !seen[k]:
tc.TID, seen[k] = v, true
case k == sIDKey && !seen[k]:
var pv int64
if pv, err = strconv.ParseInt(v, 10, 64); err != nil {
return nil, err
}
tc.SID, seen[k] = pv, true
case k == pIDKey && !seen[k]:
var pv int64
if pv, err = strconv.ParseInt(v, 10, 64); err != nil {
return nil, err
}
tc.PID, seen[k] = pv, true
default:
return nil, errBadTrace
}
}
return
}
//EncodeTraceContext encodes the TraceContext into a string.
//This is useful if you want to pass your trace context over an outgoing request
func EncodeTraceContext(tc *TraceContext) string {
return fmt.Sprintf("%s=%v;%s=%v;%s=%v", pIDKey, tc.PID, sIDKey, tc.SID, tIDKey, tc.TID)
}
//SubTrace creates a child trace context for current
func SubTrace(current *TraceContext) *TraceContext {
rand.Seed(time.Now().Unix())
return &TraceContext{
PID: current.SID,
SID: rand.Int63(),
TID: current.TID,
}
}