forked from influxdata/telegraf
-
Notifications
You must be signed in to change notification settings - Fork 1
/
nowmetric.go
144 lines (118 loc) · 3.48 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
138
139
140
141
142
143
144
package nowmetric
import (
"encoding/json"
"fmt"
"time"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/serializers"
)
type Serializer struct {
Format string `toml:"nowmetric_format"`
}
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
type OIMetricsObj struct {
Records []OIMetric `json:"records"`
}
func (s *Serializer) Init() error {
switch s.Format {
case "":
s.Format = "oi"
case "oi", "jsonv2":
default:
return fmt.Errorf("invalid format %q", s.Format)
}
return nil
}
func (s *Serializer) Serialize(metric telegraf.Metric) (out []byte, err error) {
m := s.createObject(metric)
if s.Format == "jsonv2" {
obj := OIMetricsObj{Records: m}
return json.Marshal(obj)
}
return json.Marshal(m)
}
func (s *Serializer) SerializeBatch(metrics []telegraf.Metric) (out []byte, err error) {
objects := make([]OIMetric, 0)
for _, metric := range metrics {
objects = append(objects, s.createObject(metric)...)
}
if s.Format == "jsonv2" {
obj := OIMetricsObj{Records: objects}
return json.Marshal(obj)
}
return json.Marshal(objects)
}
func (s *Serializer) createObject(metric telegraf.Metric) OIMetrics {
/* 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 //nolint:prealloc // Pre-allocating may change format of marshaled JSON
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)
}
return allmetrics
}
func verifyValue(v interface{}) bool {
_, ok := v.(string)
return !ok
}
func init() {
serializers.Add("nowmetric",
func() serializers.Serializer {
return &Serializer{}
},
)
}
// InitFromConfig is a compatibility function to construct the parser the old way
func (s *Serializer) InitFromConfig(_ *serializers.Config) error {
return nil
}