-
Notifications
You must be signed in to change notification settings - Fork 926
/
Copy pathidentity.go
110 lines (100 loc) · 2.91 KB
/
identity.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
package tracing
import (
"bytes"
"encoding/binary"
"fmt"
"strconv"
"strings"
)
const (
// 16 bytes for tracing ID, 8 bytes for span ID and 1 byte for flags
IdentityLength = 16 + 8 + 1
)
type Identity struct {
// Based on https://www.jaegertracing.io/docs/1.36/client-libraries/#value
// parent span ID is always 0 for our case
traceIDUpper uint64
traceIDLower uint64
spanID uint64
flags uint8
}
// TODO: TUN-6604 Remove this. To reconstruct into Jaeger propagation format, convert tracingContext to tracing.Identity
func (tc *Identity) String() string {
return fmt.Sprintf("%016x%016x:%x:0:%x", tc.traceIDUpper, tc.traceIDLower, tc.spanID, tc.flags)
}
func (tc *Identity) MarshalBinary() ([]byte, error) {
buf := bytes.NewBuffer(make([]byte, 0, IdentityLength))
for _, field := range []interface{}{
tc.traceIDUpper,
tc.traceIDLower,
tc.spanID,
tc.flags,
} {
if err := binary.Write(buf, binary.BigEndian, field); err != nil {
return nil, err
}
}
return buf.Bytes(), nil
}
func (tc *Identity) UnmarshalBinary(data []byte) error {
if len(data) < IdentityLength {
return fmt.Errorf("expect tracingContext to have at least %d bytes, got %d", IdentityLength, len(data))
}
buf := bytes.NewBuffer(data)
for _, field := range []interface{}{
&tc.traceIDUpper,
&tc.traceIDLower,
&tc.spanID,
&tc.flags,
} {
if err := binary.Read(buf, binary.BigEndian, field); err != nil {
return err
}
}
return nil
}
func NewIdentity(trace string) (*Identity, error) {
parts := strings.Split(trace, separator)
if len(parts) != 4 {
return nil, fmt.Errorf("trace '%s' doesn't have exactly 4 parts separated by %s", trace, separator)
}
const base = 16
tracingID, err := padTracingID(parts[0])
if err != nil {
return nil, err
}
traceIDUpper, err := strconv.ParseUint(tracingID[:16], base, 64)
if err != nil {
return nil, fmt.Errorf("failed to parse first 16 bytes of tracing ID as uint64, err: %w", err)
}
traceIDLower, err := strconv.ParseUint(tracingID[16:], base, 64)
if err != nil {
return nil, fmt.Errorf("failed to parse last 16 bytes of tracing ID as uint64, err: %w", err)
}
spanID, err := strconv.ParseUint(parts[1], base, 64)
if err != nil {
return nil, fmt.Errorf("failed to parse span ID as uint64, err: %w", err)
}
flags, err := strconv.ParseUint(parts[3], base, 8)
if err != nil {
return nil, fmt.Errorf("failed to parse flag as uint8, err: %w", err)
}
return &Identity{
traceIDUpper: traceIDUpper,
traceIDLower: traceIDLower,
spanID: spanID,
flags: uint8(flags),
}, nil
}
func padTracingID(tracingID string) (string, error) {
if len(tracingID) == 0 {
return "", fmt.Errorf("missing tracing ID")
}
if len(tracingID) == traceID128bitsWidth {
return tracingID, nil
}
// Correctly left pad the trace to a length of 32
left := traceID128bitsWidth - len(tracingID)
paddedTracingID := strings.Repeat("0", left) + tracingID
return paddedTracingID, nil
}