This repository is currently being migrated. It's locked while the migration is in progress.
forked from opsgenie/opsgenie-go-sdk-v2
/
metric.go
175 lines (151 loc) · 4.73 KB
/
metric.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
174
175
package client
import (
"math/rand"
"net/http"
"strconv"
"sync"
"time"
)
const (
HTTP MetricType = "http"
SDK MetricType = "sdk"
API MetricType = "api"
)
type Metric interface {
Type() string
}
type HttpMetric struct {
TransactionId string `json:"transactionId"`
RetryCount int `json:"retryCount"`
Error error `json:"error,omitempty"`
Duration int64 `json:"duration"`
ResourcePath string `json:"resourcePath"`
Status string `json:"status,omitempty"`
StatusCode int `json:"statusCode,omitempty"`
HttpRequest request `json:"request,omitempty"`
}
func (hm *HttpMetric) Type() string {
return string(HTTP)
}
type ApiMetric struct {
TransactionId string `json:"transactionId"`
Duration int64 `json:"duration"`
ResourcePath string `json:"resourcePath"`
ResultMetadata ResultMetadata `json:"resultMetadata, omitempty"`
HttpResponse http.Response `json:"httpResponse, omitempty"`
}
func (apiMetric *ApiMetric) Type() string {
return string(API)
}
type SdkMetric struct {
TransactionId string `json:"transactionId"`
Duration int64 `json:"duration"`
ErrorType string `json:"errorType"`
ErrorMessage string `json:"errorMessage"`
ResourcePath string `json:"resourcePath"`
SdkRequestDetails ApiRequest `json:"sdkRequestDetails"`
SdkResultDetails ApiResult `json:"sdkResultDetails"`
}
func (apiMetric *SdkMetric) Type() string {
return string(SDK)
}
type Process func(metric Metric) interface{}
type MetricType string
var AvailableMetricTypes = []MetricType{HTTP, API, SDK}
type MetricPublisher struct {
SubscriberMap map[string][]MetricSubscriber
mux sync.Mutex
}
type MetricSubscriber struct {
Process Process
}
func (s *MetricSubscriber) Register(metricType MetricType) {
metricPublisher.mux.Lock()
if metricPublisher.SubscriberMap == nil {
metricPublisher.SubscriberMap = make(map[string][]MetricSubscriber)
}
subs := metricPublisher.SubscriberMap[string(metricType)]
subs = append(subs, *s)
metricPublisher.SubscriberMap[string(metricType)] = subs
metricPublisher.mux.Unlock()
}
func (mp *MetricPublisher) publish(metric Metric) {
for _, sub := range metricPublisher.SubscriberMap[metric.Type()] {
if sub.Process != nil {
m := metric //give copy of the object for all subs
sub.Process(m)
}
}
}
func duration(start, end int64) int64 {
startMillisecond := start / int64(time.Millisecond)
endMillisecond := end / int64(time.Millisecond)
return endMillisecond - startMillisecond
}
func generateTransactionId() string {
return randStringRunes(20)
}
func init() {
rand.Seed(time.Now().UnixNano())
}
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
func randStringRunes(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letterRunes[rand.Intn(len(letterRunes))]
}
return string(b)
}
func buildHttpMetric(transactionId string, resourcePath string, response *http.Response, err error, duration int64, httpRequest request) *HttpMetric {
retryCount, convErr := strconv.Atoi(response.Header.Get("retryCount"))
metric := &HttpMetric{
TransactionId: transactionId,
RetryCount: 0,
Error: err,
Duration: duration,
ResourcePath: resourcePath,
HttpRequest: httpRequest,
Status: response.Status,
StatusCode: response.StatusCode,
}
if convErr == nil {
metric.RetryCount = retryCount
}
return metric
}
func buildSdkMetric(transactionId string, resourcePath string, errorType string, err error, apiRequest ApiRequest, apiResult ApiResult, duration int64) *SdkMetric {
metric := &SdkMetric{}
metric.TransactionId = transactionId
if err != nil {
metric.ErrorMessage = err.Error()
metric.ErrorType = errorType
}
metric.ResourcePath = resourcePath
metric.SdkRequestDetails = apiRequest
metric.Duration = duration
metric.SdkResultDetails = apiResult
return metric
}
func buildApiMetric(transactionId string, resourcePath string, duration int64, metadata ResultMetadata, response *http.Response, err error) *ApiMetric {
metric := &ApiMetric{}
metric.TransactionId = transactionId
metric.ResourcePath = resourcePath
metric.Duration = duration
if err == nil {
metric.ResultMetadata = metadata
} else if ae, ok := err.(*ApiError); ok {
rm := ResultMetadata{}
rm.RequestId = ae.RequestId
rm.ResponseTime = ae.Took
rm.RateLimitPeriod = response.Header.Get("X-RateLimit-Period-In-Sec")
rm.RateLimitReason = response.Header.Get("X-RateLimit-Reason")
rm.RateLimitState = response.Header.Get("X-RateLimit-State")
rc, convErr := strconv.Atoi(response.Header.Get("retryCount"))
if convErr == nil {
rm.RetryCount = rc
}
metric.ResultMetadata = rm
}
metric.HttpResponse = *response
return metric
}