forked from mikaukora/rcc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmetrics.go
160 lines (140 loc) · 3.96 KB
/
metrics.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
package cloud
import (
"bytes"
"encoding/json"
"fmt"
"net/url"
"os"
"runtime"
"sync"
"time"
"github.com/robocorp/rcc/common"
"github.com/robocorp/rcc/fail"
"github.com/robocorp/rcc/settings"
"github.com/robocorp/rcc/xviper"
)
var (
telemetryBarrier = sync.WaitGroup{}
)
const (
trackingUrl = `/metric-v1/%v/%v/%v/%v/%v`
batchUrl = `/metric-v1/batch`
contentType = `content-type`
applicationJson = `application/json`
)
type (
batchStatus struct {
File string `json:"file"`
Host string `json:"host"`
Code int `json:"code"`
Warning string `json:"warning"`
Content string `json:"content"`
}
)
func sendMetric(metricsHost, kind, name, value string) {
common.Timeline("%s:%s = %s", kind, name, value)
defer func() {
status := recover()
if status != nil {
common.Debug("Telemetry panic recovered: %v", status)
}
telemetryBarrier.Done()
}()
client, err := NewClient(metricsHost)
if err != nil {
common.Debug("WARNING: %v (not critical)", err)
return
}
timeout := 5 * time.Second
client = client.Uncritical().WithTimeout(timeout)
timestamp := time.Now().UnixNano()
url := fmt.Sprintf(trackingUrl, url.PathEscape(kind), timestamp, url.PathEscape(xviper.TrackingIdentity()), url.PathEscape(name), url.PathEscape(value))
common.Debug("Sending metric (timeout %v) as %v%v", timeout, metricsHost, url)
client.Put(client.NewRequest(url))
}
func BackgroundMetric(kind, name, value string) {
if common.WarrantyVoided() {
return
}
metricsHost := settings.Global.TelemetryURL()
if len(metricsHost) == 0 {
return
}
common.Debug("BackgroundMetric kind:%v name:%v value:%v send:%v", kind, name, value, xviper.CanTrack())
if xviper.CanTrack() {
telemetryBarrier.Add(1)
go sendMetric(metricsHost, kind, name, value)
runtime.Gosched()
}
}
func InternalBackgroundMetric(kind, name, value string) {
if common.Product.AllowInternalMetrics() {
BackgroundMetric(kind, name, value)
}
}
func stdoutDump(origin error, message any) (err error) {
defer fail.Around(&err)
body, failure := json.MarshalIndent(message, "", " ")
fail.Fast(failure)
os.Stdout.Write(append(body, '\n'))
return origin
}
func BatchMetric(filename string) error {
status := &batchStatus{
File: filename,
Code: 999,
}
metricsHost := settings.Global.TelemetryURL()
if len(metricsHost) < 8 {
status.Warning = "No metrics host."
return stdoutDump(nil, status)
}
blob, err := os.ReadFile(filename)
if err != nil {
status.Code = 998
status.Warning = err.Error()
return stdoutDump(err, status)
}
status.Host = metricsHost
client, err := NewClient(metricsHost)
if err != nil {
status.Code = 997
status.Warning = err.Error()
return stdoutDump(err, status)
}
timeout := 10 * time.Second
client = client.Uncritical().WithTimeout(timeout)
request := client.NewRequest(batchUrl)
request.Headers[contentType] = applicationJson
request.Body = bytes.NewBuffer([]byte(blob))
response := client.Put(request)
switch {
case response == nil:
status.Code = 996
status.Warning = "Response was <nil>"
case response != nil && response.Status == 202 && response.Err == nil:
status.Code = response.Status
status.Warning = "ok"
status.Content = string(response.Body)
case response != nil && response.Err != nil:
status.Code = response.Status
status.Warning = fmt.Sprintf("Failed PUT to %s%s, reason: %v", metricsHost, batchUrl, response.Err)
status.Content = string(response.Body)
case response != nil && response.Status != 202:
status.Code = response.Status
status.Warning = fmt.Sprintf("Failed PUT to %s%s. See content for details.", metricsHost, batchUrl)
status.Content = string(response.Body)
default:
status.Code = response.Status
status.Warning = "N/A"
status.Content = string(response.Body)
}
return stdoutDump(nil, status)
}
func WaitTelemetry() {
defer common.Timeline("wait telemetry done")
common.Debug("wait telemetry to complete")
runtime.Gosched()
telemetryBarrier.Wait()
common.Debug("telemetry sending completed")
}