feat(serializers.nowmetric): Add option for JSONv2 format (#13722)
This commit is contained in:
parent
8bc6822e28
commit
93bf2becce
|
|
@ -1,16 +1,22 @@
|
|||
# ServiceNow Metrics serializer
|
||||
|
||||
The ServiceNow Metrics serializer outputs metrics in the [ServiceNow Operational Intelligence format][ServiceNow-format].
|
||||
The ServiceNow Metrics serializer outputs metrics in the
|
||||
[ServiceNow Operational Intelligence format][ServiceNow-format] or optionally
|
||||
with the [ServiceNow JSONv2 format][ServiceNow-jsonv2]
|
||||
|
||||
It can be used to write to a file using the file output, or for sending metrics to a MID Server with Enable REST endpoint activated using the standard telegraf HTTP output.
|
||||
If you're using the HTTP output, this serializer knows how to batch the metrics so you don't end up with an HTTP POST per metric.
|
||||
It can be used to write to a file using the file output, or for sending metrics
|
||||
to a MID Server with Enable REST endpoint activated using the standard telegraf
|
||||
HTTP output. If you are using the HTTP output, this serializer knows how to
|
||||
batch the metrics so you do not end up with an HTTP POST per metric.
|
||||
|
||||
[ServiceNow-format]: https://docs.servicenow.com/bundle/london-it-operations-management/page/product/event-management/reference/mid-POST-metrics.html
|
||||
[ServiceNow-jsonv2]: https://docs.servicenow.com/bundle/tokyo-application-development/page/integrate/inbound-other-web-services/concept/c_JSONv2WebService.html
|
||||
|
||||
An example event looks like:
|
||||
An example Operational Intelligence format event looks like:
|
||||
|
||||
```javascript
|
||||
[{
|
||||
```json
|
||||
[
|
||||
{
|
||||
"metric_type": "Disk C: % Free Space",
|
||||
"resource": "C:\\",
|
||||
"node": "lnux100",
|
||||
|
|
@ -19,8 +25,29 @@ An example event looks like:
|
|||
"ci2metric_id": {
|
||||
"node": "lnux100"
|
||||
},
|
||||
"source": “Telegraf”
|
||||
}]
|
||||
"source": "Telegraf"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
An example of the JSONv2 format even looks like:
|
||||
|
||||
```json
|
||||
{
|
||||
"records": [
|
||||
{
|
||||
"metric_type": "Disk C: % Free Space",
|
||||
"resource": "C:\\",
|
||||
"node": "lnux100",
|
||||
"value": 50,
|
||||
"timestamp": 1473183012000,
|
||||
"ci2metric_id": {
|
||||
"node": "lnux100"
|
||||
},
|
||||
"source": "Telegraf"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Using with the HTTP output
|
||||
|
|
@ -55,6 +82,13 @@ To send this data to a ServiceNow MID Server with Web Server extension activated
|
|||
## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md
|
||||
data_format = "nowmetric"
|
||||
|
||||
## Format Type
|
||||
## By default, the serializer returns an array of metrics matching the
|
||||
## Now Metric Operational Intelligence format or with the option set to 'oi'.
|
||||
## Optionally, if set to 'jsonv2' the output format will involve the newer
|
||||
## JSON object based format.
|
||||
# nowmetric_format = "oi"
|
||||
|
||||
## Additional HTTP headers
|
||||
[outputs.http.headers]
|
||||
# # Should be set manually to "application/json" for json data_format
|
||||
|
|
@ -66,6 +100,23 @@ Starting with the [London release](https://docs.servicenow.com/bundle/london-it-
|
|||
),
|
||||
you also need to explicitly create event rule to allow binding of metric events to host CIs.
|
||||
|
||||
## Metric Format
|
||||
|
||||
The following describes the two options of the `nowmetric_format` option:
|
||||
|
||||
The Operational Intelligence format is used along with the
|
||||
`/api/mid/sa/metrics` API endpoint. The payload is requires a JSON array full
|
||||
of metrics. This is the default settings and used when set to `oi`. See the
|
||||
[ServiceNow KB0853084][KB0853084] for more details on this format.
|
||||
|
||||
Another option is the use of the [JSONv2 web service][jsonv2]. This service
|
||||
requires a different format that is [JSON object based][jsonv2_format]. This
|
||||
option is used when set to `jsonv2`.
|
||||
|
||||
[KB0853084]: https://support.servicenow.com/kb?id=kb_article_view&sysparm_article=KB0853084
|
||||
[jsonv2]: https://docs.servicenow.com/bundle/tokyo-application-development/page/integrate/inbound-other-web-services/concept/c_JSONv2WebService.html
|
||||
[jsonv2_format]: https://docs.servicenow.com/bundle/tokyo-application-development/page/integrate/inbound-other-web-services/concept/c_JSONObjectFormat.html
|
||||
|
||||
## Using with the File output
|
||||
|
||||
You can use the file output to output the payload in a file.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package nowmetric
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
|
@ -10,20 +9,9 @@ import (
|
|||
"github.com/influxdata/telegraf/plugins/serializers"
|
||||
)
|
||||
|
||||
type Serializer struct{}
|
||||
|
||||
/*
|
||||
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 Serializer struct {
|
||||
Format string `toml:"nowmetric_format"`
|
||||
}
|
||||
*/
|
||||
|
||||
type OIMetric struct {
|
||||
Metric string `json:"metric_type"`
|
||||
|
|
@ -36,30 +24,47 @@ type OIMetric struct {
|
|||
}
|
||||
|
||||
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) {
|
||||
serialized, err := s.createObject(metric)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
m := s.createObject(metric)
|
||||
|
||||
if s.Format == "jsonv2" {
|
||||
obj := OIMetricsObj{Records: m}
|
||||
return json.Marshal(obj)
|
||||
}
|
||||
return serialized, nil
|
||||
return json.Marshal(m)
|
||||
}
|
||||
|
||||
func (s *Serializer) SerializeBatch(metrics []telegraf.Metric) (out []byte, err error) {
|
||||
objects := make([]byte, 0)
|
||||
objects := make([]OIMetric, 0)
|
||||
for _, metric := range metrics {
|
||||
m, err := s.createObject(metric)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dropping invalid metric: %s", metric.Name())
|
||||
} else if m != nil {
|
||||
objects = append(objects, m...)
|
||||
objects = append(objects, s.createObject(metric)...)
|
||||
}
|
||||
|
||||
if s.Format == "jsonv2" {
|
||||
obj := OIMetricsObj{Records: objects}
|
||||
return json.Marshal(obj)
|
||||
}
|
||||
replaced := bytes.Replace(objects, []byte("]["), []byte(","), -1)
|
||||
return replaced, nil
|
||||
|
||||
return json.Marshal(objects)
|
||||
}
|
||||
|
||||
func (s *Serializer) createObject(metric telegraf.Metric) ([]byte, error) {
|
||||
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
|
||||
|
|
@ -117,9 +122,7 @@ func (s *Serializer) createObject(metric telegraf.Metric) ([]byte, error) {
|
|||
allmetrics = append(allmetrics, oimetric)
|
||||
}
|
||||
|
||||
metricsJSON, err := json.Marshal(allmetrics)
|
||||
|
||||
return metricsJSON, err
|
||||
return allmetrics
|
||||
}
|
||||
|
||||
func verifyValue(v interface{}) bool {
|
||||
|
|
|
|||
|
|
@ -199,3 +199,52 @@ func TestSerializeBatch(t *testing.T) {
|
|||
buf,
|
||||
)
|
||||
}
|
||||
|
||||
func TestSerializeJSONv2Format(t *testing.T) {
|
||||
m := metric.New(
|
||||
"cpu",
|
||||
map[string]string{},
|
||||
map[string]interface{}{
|
||||
"value": 42.0,
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
)
|
||||
s := &Serializer{Format: "jsonv2"}
|
||||
buf, err := s.Serialize(m)
|
||||
require.NoError(t, err)
|
||||
require.Equal(
|
||||
t,
|
||||
[]byte(`{"records":[{"metric_type":"value","resource":"","node":"","value":42,"timestamp":0,"ci2metric_id":null,"source":"Telegraf"}]}`),
|
||||
buf,
|
||||
)
|
||||
}
|
||||
|
||||
func TestSerializeJSONv2FormatBatch(t *testing.T) {
|
||||
m := metric.New(
|
||||
"cpu",
|
||||
map[string]string{},
|
||||
map[string]interface{}{
|
||||
"value": 42.0,
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
)
|
||||
s := &Serializer{Format: "jsonv2"}
|
||||
metrics := []telegraf.Metric{m, m}
|
||||
buf, err := s.SerializeBatch(metrics)
|
||||
require.NoError(t, err)
|
||||
require.Equal(
|
||||
t,
|
||||
[]byte(
|
||||
`{"records":[`+
|
||||
`{"metric_type":"value","resource":"","node":"","value":42,"timestamp":0,"ci2metric_id":null,"source":"Telegraf"},`+
|
||||
`{"metric_type":"value","resource":"","node":"","value":42,"timestamp":0,"ci2metric_id":null,"source":"Telegraf"}`+
|
||||
`]}`,
|
||||
),
|
||||
buf,
|
||||
)
|
||||
}
|
||||
|
||||
func TestSerializeInvalidFormat(t *testing.T) {
|
||||
s := &Serializer{Format: "foo"}
|
||||
require.Error(t, s.Init())
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue