-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnrpush.go
149 lines (119 loc) · 3.45 KB
/
nrpush.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
package nrpush
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"regexp"
"strings"
)
// NRPush represents an NewRelic Push data
type NRPush struct {
Endpoint string
InsertKey string
EventType string
}
var (
// Verbose indicates if details of the HTTP request will be displayed
Verbose = false
)
// Endpoint defines the New Relic HTTP URL where the payload will be sent
const Endpoint = "https://insights-collector.newrelic.com/v1/accounts/{:accountID}/events"
// New creates sets a new NRPush configuration.
// `accountID` numeric. Can be found as part of the URL endpoint in Insigts dashboard
func New(insertKey, accountID, eventType string) NRPush {
reg, err := regexp.Compile("[^A-Za-z0-9]+")
if err != nil {
log.Fatal(err)
}
eventType = strings.ReplaceAll(strings.Title(reg.ReplaceAllString(eventType, " ")), " ", "")
return NRPush{
Endpoint: strings.Replace(Endpoint, "{:accountID}", accountID, 1),
InsertKey: insertKey,
EventType: eventType,
}
}
func interfaceToMap(data interface{}) (map[string]interface{}, error) {
var (
body map[string]interface{}
b, err = json.Marshal(data)
)
if err != nil {
return map[string]interface{}{}, fmt.Errorf("JSON transformation Error(1) - %s", err.Error())
}
if err = json.Unmarshal(b, &body); err != nil {
return map[string]interface{}{}, fmt.Errorf("JSON transformation Error(2)- %s", err.Error())
}
return body, nil
}
func mustJSONMarshal(d interface{}) []byte {
b, err := json.Marshal(d)
if err != nil {
panic(fmt.Errorf("mustJSONMarshal - %s", err.Error()))
}
return b
}
func mapSafeReplace(m map[string]interface{}, key string, replace interface{}) map[string]interface{} {
if _, ok := m[key]; ok {
m["_"+key] = m[key]
}
m[key] = replace
return m
}
// PushBatch inserts a batch of new custom data and return the UUID when successful
func (n NRPush) PushBatch(ctx context.Context, data []interface{}) (string, error) {
for i, v := range data {
body, err := interfaceToMap(v)
if err != nil {
return "", err
}
data[i] = mapSafeReplace(body, "eventType", n.EventType)
}
return n.sendWithContext(ctx, mustJSONMarshal(data))
}
// Push inserts a new custom data and return the UUID when successful
func (n NRPush) Push(ctx context.Context, data interface{}) (string, error) {
var (
body map[string]interface{}
err error
)
if body, err = interfaceToMap(data); err != nil {
return "", err
}
// Put in eventType property
body = mapSafeReplace(body, "eventType", n.EventType)
return n.sendWithContext(ctx, mustJSONMarshal(body))
}
func (n NRPush) sendWithContext(ctx context.Context, data []byte) (string, error) {
var (
client = http.Client{}
request *http.Request
response *http.Response
body map[string]interface{}
responseBody []byte
err error
)
if Verbose {
fmt.Printf("URL: %s %s\nInsertKey:%s\nBody:\n%s", n.Endpoint, http.MethodPost, n.InsertKey, string(data))
}
// HTTP
request, err = http.NewRequest(http.MethodPost, n.Endpoint, bytes.NewBuffer(data))
request.Header.Set("Content-Type", "application/json")
request.Header.Set("X-Insert-Key", n.InsertKey)
request.WithContext(ctx)
if err != nil {
return "", err
}
if response, err = client.Do(request); err != nil {
return "", err
}
defer response.Body.Close()
if responseBody, err = ioutil.ReadAll(response.Body); err != nil {
return "", err
}
err = json.Unmarshal(responseBody, &body)
return body["uuid"].(string), err
}