forked from st3v/go-plugins
-
Notifications
You must be signed in to change notification settings - Fork 0
/
util.go
173 lines (146 loc) · 3.77 KB
/
util.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 awsxray
import (
"crypto/rand"
"fmt"
"strings"
"time"
"context"
"github.com/asim/go-awsxray"
"github.com/micro/go-micro/errors"
"github.com/micro/go-micro/metadata"
)
// getHTTP returns a http struct
func getHTTP(url, method string, err error) *awsxray.HTTP {
return &awsxray.HTTP{
Request: &awsxray.Request{
Method: method,
URL: url,
},
Response: &awsxray.Response{
Status: getStatus(err),
},
}
}
// getRandom generates a random byte slice
func getRandom(i int) []byte {
b := make([]byte, i)
for {
// keep trying till we get it
if _, err := rand.Read(b); err != nil {
continue
}
return b
}
}
// getSegment creates a new segment based on whether we're part of an existing flow
func getSegment(name string, ctx context.Context) *awsxray.Segment {
md, _ := metadata.FromContext(ctx)
parentId := getParentId(md)
traceId := getTraceId(md)
// try get existing segment for parent Id
if s, ok := awsxray.FromContext(ctx); ok {
// only set existing segment as parent if its not a subsegment itself
if len(parentId) == 0 && len(s.Type) == 0 {
parentId = s.Id
}
if len(traceId) == 0 {
traceId = s.TraceId
}
}
// create segment
s := &awsxray.Segment{
Id: fmt.Sprintf("%x", getRandom(8)),
Name: name,
TraceId: traceId,
StartTime: float64(time.Now().Truncate(time.Millisecond).UnixNano()) / 1e9,
}
// we have a parent so subsegment
if len(parentId) > 0 {
s.ParentId = parentId
s.Type = "subsegment"
}
return s
}
// getStatus returns a status code from the error
func getStatus(err error) int {
// no error
if err == nil {
return 200
}
// try get errors.Error
if e, ok := err.(*errors.Error); ok {
return int(e.Code)
}
// try parse marshalled error
if e := errors.Parse(err.Error()); e.Code > 0 {
return int(e.Code)
}
// could not parse, 500
return 500
}
// getTraceId returns trace header or generates a new one
func getTraceId(md metadata.Metadata) string {
// try as is
if h, ok := md[awsxray.TraceHeader]; ok {
return awsxray.GetTraceId(h)
}
// try lower case
if h, ok := md[strings.ToLower(awsxray.TraceHeader)]; ok {
return awsxray.GetTraceId(h)
}
// generate new one, probably a bad idea...
return fmt.Sprintf("%d-%x-%x", 1, time.Now().Unix(), getRandom(12))
}
// getParentId returns parent header or blank
func getParentId(md metadata.Metadata) string {
// try as is
if h, ok := md[awsxray.TraceHeader]; ok {
return awsxray.GetParentId(h)
}
// try lower case
if h, ok := md[strings.ToLower(awsxray.TraceHeader)]; ok {
return awsxray.GetParentId(h)
}
return ""
}
func newXRay(opts Options) *awsxray.AWSXRay {
return awsxray.New(
awsxray.WithClient(opts.Client),
awsxray.WithDaemon(opts.Daemon),
)
}
func record(x *awsxray.AWSXRay, s *awsxray.Segment) error {
// set end time
s.EndTime = float64(time.Now().Truncate(time.Millisecond).UnixNano()) / 1e9
return x.Record(s)
}
// setCallStatus sets the http section and related status
func setCallStatus(s *awsxray.Segment, url, method string, err error) {
s.HTTP = getHTTP(url, method, err)
status := getStatus(err)
switch {
case status >= 500:
s.Fault = true
case status >= 400:
s.Error = true
case err != nil:
s.Fault = true
}
}
func newContext(ctx context.Context, s *awsxray.Segment) context.Context {
md, _ := metadata.FromContext(ctx)
// make copy to avoid races
newMd := metadata.Metadata{}
for k, v := range md {
newMd[k] = v
}
// set trace id in header
newMd[awsxray.TraceHeader] = awsxray.SetTraceId(newMd[awsxray.TraceHeader], s.TraceId)
// set parent id in header
newMd[awsxray.TraceHeader] = awsxray.SetParentId(newMd[awsxray.TraceHeader], s.ParentId)
// store segment in context
ctx = awsxray.NewContext(ctx, s)
// store metadata in context
ctx = metadata.NewContext(ctx, newMd)
return ctx
}