forked from influxdata/telegraf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nowmetric.go
137 lines (114 loc) · 3.28 KB
/
nowmetric.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
package nowmetric
import (
"bytes"
"encoding/json"
"fmt"
"time"
"github.com/influxdata/telegraf"
)
type serializer struct {
TimestampUnits time.Duration
}
/*
Example for the JSON generated and pushed to the MID
{
"metric_type":"cpu_usage_system",
"resource":"",
"node":"ASGARD",
"value": 0.89,
"timestamp":1487365430,
"ci2metric_id":{"node":"ASGARD"},
"source":"Telegraf"
}
*/
type OIMetric struct {
Metric string `json:"metric_type"`
Resource string `json:"resource"`
Node string `json:"node"`
Value interface{} `json:"value"`
Timestamp int64 `json:"timestamp"`
CiMapping map[string]string `json:"ci2metric_id"`
Source string `json:"source"`
}
type OIMetrics []OIMetric
func NewSerializer() (*serializer, error) {
s := &serializer{}
return s, nil
}
func (s *serializer) Serialize(metric telegraf.Metric) (out []byte, err error) {
serialized, err := s.createObject(metric)
if err != nil {
return []byte{}, nil
}
return serialized, err
}
func (s *serializer) SerializeBatch(metrics []telegraf.Metric) (out []byte, err error) {
objects := make([]byte, 0)
for _, metric := range metrics {
m, err := s.createObject(metric)
if err != nil {
return nil, fmt.Errorf("D! [serializer.nowmetric] Dropping invalid metric: %s", metric.Name())
} else if m != nil {
objects = append(objects, m...)
}
}
replaced := bytes.Replace(objects, []byte("]["), []byte(","), -1)
return replaced, nil
}
func (s *serializer) createObject(metric telegraf.Metric) ([]byte, error) {
/* ServiceNow Operational Intelligence supports an array of JSON objects.
** Following elements accepted in the request body:
** metric_type: The name of the metric
** resource: Information about the resource for which metric data is being collected. In the example below, C:\ is the resource for which metric data is collected
** node: IP, FQDN, name of the CI, or host
** value: Value of the metric
** timestamp: Epoch timestamp of the metric in milliseconds
** ci2metric_id: List of key-value pairs to identify the CI.
** source: Data source monitoring the metric type
*/
var allmetrics OIMetrics
var oimetric OIMetric
oimetric.Source = "Telegraf"
// Process Tags to extract node & resource name info
for _, tag := range metric.TagList() {
if tag.Key == "" || tag.Value == "" {
continue
}
if tag.Key == "objectname" {
oimetric.Resource = tag.Value
}
if tag.Key == "host" {
oimetric.Node = tag.Value
}
}
// Format timestamp to UNIX epoch
oimetric.Timestamp = (metric.Time().UnixNano() / int64(time.Millisecond))
// Loop of fields value pair and build datapoint for each of them
for _, field := range metric.FieldList() {
if !verifyValue(field.Value) {
// Ignore String
continue
}
if field.Key == "" {
// Ignore Empty Key
continue
}
oimetric.Metric = field.Key
oimetric.Value = field.Value
if oimetric.Node != "" {
cimapping := map[string]string{}
cimapping["node"] = oimetric.Node
oimetric.CiMapping = cimapping
}
allmetrics = append(allmetrics, oimetric)
}
metricsJson, err := json.Marshal(allmetrics)
return metricsJson, err
}
func verifyValue(v interface{}) bool {
switch v.(type) {
case string:
return false
}
return true
}