Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
48
plugins/outputs/signalfx/README.md
Normal file
48
plugins/outputs/signalfx/README.md
Normal file
|
@ -0,0 +1,48 @@
|
|||
# SignalFx Output Plugin
|
||||
|
||||
This plugin writes metrics to [SignalFx][docs].
|
||||
|
||||
⭐ Telegraf v1.18.0
|
||||
🏷️ applications
|
||||
💻 all
|
||||
|
||||
[docs]: https://docs.signalfx.com/en/latest/
|
||||
|
||||
## Global configuration options <!-- @/docs/includes/plugin_config.md -->
|
||||
|
||||
In addition to the plugin-specific configuration settings, plugins support
|
||||
additional global and plugin configuration settings. These settings are used to
|
||||
modify metrics, tags, and field or create aliases and configure ordering, etc.
|
||||
See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
||||
|
||||
[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins
|
||||
|
||||
## Secret-store support
|
||||
|
||||
This plugin supports secrets from secret-stores for the `access_token` option.
|
||||
See the [secret-store documentation][SECRETSTORE] for more details on how
|
||||
to use them.
|
||||
|
||||
[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets
|
||||
|
||||
## Configuration
|
||||
|
||||
```toml @sample.conf
|
||||
# Send metrics and events to SignalFx
|
||||
[[outputs.signalfx]]
|
||||
## SignalFx Org Access Token
|
||||
access_token = "my-secret-token"
|
||||
|
||||
## The SignalFx realm that your organization resides in
|
||||
signalfx_realm = "us9" # Required if ingest_url is not set
|
||||
|
||||
## You can optionally provide a custom ingest url instead of the
|
||||
## signalfx_realm option above if you are using a gateway or proxy
|
||||
## instance. This option takes precedence over signalfx_realm.
|
||||
ingest_url = "https://my-custom-ingest/"
|
||||
|
||||
## Event typed metrics are omitted by default,
|
||||
## If you require an event typed metric you must specify the
|
||||
## metric name in the following list.
|
||||
included_event_names = ["plugin.metric_name"]
|
||||
```
|
17
plugins/outputs/signalfx/sample.conf
Normal file
17
plugins/outputs/signalfx/sample.conf
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Send metrics and events to SignalFx
|
||||
[[outputs.signalfx]]
|
||||
## SignalFx Org Access Token
|
||||
access_token = "my-secret-token"
|
||||
|
||||
## The SignalFx realm that your organization resides in
|
||||
signalfx_realm = "us9" # Required if ingest_url is not set
|
||||
|
||||
## You can optionally provide a custom ingest url instead of the
|
||||
## signalfx_realm option above if you are using a gateway or proxy
|
||||
## instance. This option takes precedence over signalfx_realm.
|
||||
ingest_url = "https://my-custom-ingest/"
|
||||
|
||||
## Event typed metrics are omitted by default,
|
||||
## If you require an event typed metric you must specify the
|
||||
## metric name in the following list.
|
||||
included_event_names = ["plugin.metric_name"]
|
241
plugins/outputs/signalfx/signalfx.go
Normal file
241
plugins/outputs/signalfx/signalfx.go
Normal file
|
@ -0,0 +1,241 @@
|
|||
//go:generate ../../../tools/readme_config_includer/generator
|
||||
package signalfx
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/signalfx/golib/v3/datapoint"
|
||||
"github.com/signalfx/golib/v3/datapoint/dpsink"
|
||||
"github.com/signalfx/golib/v3/event"
|
||||
"github.com/signalfx/golib/v3/sfxclient"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/config"
|
||||
"github.com/influxdata/telegraf/plugins/outputs"
|
||||
)
|
||||
|
||||
//go:embed sample.conf
|
||||
var sampleConfig string
|
||||
|
||||
// init initializes the plugin context
|
||||
func init() {
|
||||
outputs.Add("signalfx", func() telegraf.Output {
|
||||
return NewSignalFx()
|
||||
})
|
||||
}
|
||||
|
||||
// SignalFx plugin context
|
||||
type SignalFx struct {
|
||||
AccessToken config.Secret `toml:"access_token"`
|
||||
SignalFxRealm string `toml:"signalfx_realm"`
|
||||
IngestURL string `toml:"ingest_url"`
|
||||
IncludedEventNames []string `toml:"included_event_names"`
|
||||
|
||||
Log telegraf.Logger `toml:"-"`
|
||||
|
||||
includedEventSet map[string]bool
|
||||
client dpsink.Sink
|
||||
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
// GetMetricType returns the equivalent telegraf ValueType for a signalfx metric type
|
||||
func GetMetricType(mtype telegraf.ValueType) (metricType datapoint.MetricType) {
|
||||
switch mtype {
|
||||
case telegraf.Counter:
|
||||
metricType = datapoint.Counter
|
||||
case telegraf.Gauge:
|
||||
metricType = datapoint.Gauge
|
||||
case telegraf.Summary:
|
||||
metricType = datapoint.Gauge
|
||||
case telegraf.Histogram:
|
||||
metricType = datapoint.Gauge
|
||||
case telegraf.Untyped:
|
||||
metricType = datapoint.Gauge
|
||||
default:
|
||||
metricType = datapoint.Gauge
|
||||
}
|
||||
return metricType
|
||||
}
|
||||
|
||||
// NewSignalFx - returns a new context for the SignalFx output plugin
|
||||
func NewSignalFx() *SignalFx {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
return &SignalFx{
|
||||
IncludedEventNames: []string{""},
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
client: sfxclient.NewHTTPSink(),
|
||||
}
|
||||
}
|
||||
|
||||
func (*SignalFx) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
// Connect establishes a connection to SignalFx
|
||||
func (s *SignalFx) Connect() error {
|
||||
client := s.client.(*sfxclient.HTTPSink)
|
||||
|
||||
token, err := s.AccessToken.Get()
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting token failed: %w", err)
|
||||
}
|
||||
client.AuthToken = token.String()
|
||||
token.Destroy()
|
||||
|
||||
if s.IngestURL != "" {
|
||||
client.DatapointEndpoint = datapointEndpointForIngestURL(s.IngestURL)
|
||||
client.EventEndpoint = eventEndpointForIngestURL(s.IngestURL)
|
||||
} else if s.SignalFxRealm != "" {
|
||||
client.DatapointEndpoint = datapointEndpointForRealm(s.SignalFxRealm)
|
||||
client.EventEndpoint = eventEndpointForRealm(s.SignalFxRealm)
|
||||
} else {
|
||||
return errors.New("signalfx_realm or ingest_url must be configured")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes any connections to SignalFx
|
||||
func (s *SignalFx) Close() error {
|
||||
s.cancel()
|
||||
s.client.(*sfxclient.HTTPSink).Client.CloseIdleConnections()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SignalFx) ConvertToSignalFx(metrics []telegraf.Metric) ([]*datapoint.Datapoint, []*event.Event) {
|
||||
var dps []*datapoint.Datapoint
|
||||
var events []*event.Event
|
||||
|
||||
for _, metric := range metrics {
|
||||
s.Log.Debugf("Processing the following measurement: %v", metric)
|
||||
var timestamp = metric.Time()
|
||||
|
||||
metricType := GetMetricType(metric.Type())
|
||||
for field, val := range metric.Fields() {
|
||||
// Copy the metric tags because they are meant to be treated as
|
||||
// immutable
|
||||
var metricDims = metric.Tags()
|
||||
|
||||
// Generate the metric name
|
||||
metricName := getMetricName(metric.Name(), field)
|
||||
|
||||
// Get the metric value as a datapoint value
|
||||
if metricValue, err := datapoint.CastMetricValueWithBool(val); err == nil {
|
||||
var dp = datapoint.New(metricName,
|
||||
metricDims,
|
||||
metricValue,
|
||||
metricType,
|
||||
timestamp)
|
||||
|
||||
s.Log.Debugf("Datapoint: %v", dp.String())
|
||||
|
||||
dps = append(dps, dp)
|
||||
} else {
|
||||
// Skip if it's not an explicitly included event
|
||||
if !s.isEventIncluded(metricName) {
|
||||
continue
|
||||
}
|
||||
|
||||
// We've already type checked field, so set property with value
|
||||
metricProps := map[string]interface{}{"message": val}
|
||||
var ev = event.NewWithProperties(metricName,
|
||||
event.AGENT,
|
||||
metricDims,
|
||||
metricProps,
|
||||
timestamp)
|
||||
|
||||
s.Log.Debugf("Event: %v", ev.String())
|
||||
|
||||
events = append(events, ev)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dps, events
|
||||
}
|
||||
|
||||
// Write call back for writing metrics
|
||||
func (s *SignalFx) Write(metrics []telegraf.Metric) error {
|
||||
dps, events := s.ConvertToSignalFx(metrics)
|
||||
|
||||
if len(dps) > 0 {
|
||||
err := s.client.AddDatapoints(s.ctx, dps)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(events) > 0 {
|
||||
if err := s.client.AddEvents(s.ctx, events); err != nil {
|
||||
// If events error out but we successfully sent some datapoints,
|
||||
// don't return an error so that it won't ever retry -- that way we
|
||||
// don't send the same datapoints twice.
|
||||
if len(dps) == 0 {
|
||||
return err
|
||||
}
|
||||
s.Log.Errorf("Failed to send SignalFx event: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// isEventIncluded - checks whether a metric name for an event was put on the whitelist
|
||||
func (s *SignalFx) isEventIncluded(name string) bool {
|
||||
if s.includedEventSet == nil {
|
||||
s.includedEventSet = make(map[string]bool, len(s.includedEventSet))
|
||||
for _, include := range s.IncludedEventNames {
|
||||
s.includedEventSet[include] = true
|
||||
}
|
||||
}
|
||||
return s.includedEventSet[name]
|
||||
}
|
||||
|
||||
// getMetricName combines telegraf fields and tags into a full metric name
|
||||
func getMetricName(metric, field string) string {
|
||||
name := metric
|
||||
|
||||
// Include field in metric name when it adds to the metric name
|
||||
if field != "value" {
|
||||
name = fmt.Sprintf("%s.%s", name, field)
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
// ingestURLForRealm returns the base ingest URL for a particular SignalFx
|
||||
// realm
|
||||
func ingestURLForRealm(realm string) string {
|
||||
return fmt.Sprintf("https://ingest.%s.signalfx.com", realm)
|
||||
}
|
||||
|
||||
// datapointEndpointForRealm returns the endpoint to which datapoints should be
|
||||
// POSTed for a particular realm.
|
||||
func datapointEndpointForRealm(realm string) string {
|
||||
return datapointEndpointForIngestURL(ingestURLForRealm(realm))
|
||||
}
|
||||
|
||||
// datapointEndpointForRealm returns the endpoint to which datapoints should be
|
||||
// POSTed for a particular ingest base URL.
|
||||
func datapointEndpointForIngestURL(ingestURL string) string {
|
||||
return strings.TrimRight(ingestURL, "/") + "/v2/datapoint"
|
||||
}
|
||||
|
||||
// eventEndpointForRealm returns the endpoint to which events should be
|
||||
// POSTed for a particular realm.
|
||||
func eventEndpointForRealm(realm string) string {
|
||||
return eventEndpointForIngestURL(ingestURLForRealm(realm))
|
||||
}
|
||||
|
||||
// eventEndpointForRealm returns the endpoint to which events should be
|
||||
// POSTed for a particular ingest base URL.
|
||||
func eventEndpointForIngestURL(ingestURL string) string {
|
||||
return strings.TrimRight(ingestURL, "/") + "/v2/event"
|
||||
}
|
652
plugins/outputs/signalfx/signalfx_test.go
Normal file
652
plugins/outputs/signalfx/signalfx_test.go
Normal file
|
@ -0,0 +1,652 @@
|
|||
package signalfx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/signalfx/golib/v3/datapoint"
|
||||
"github.com/signalfx/golib/v3/event"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/metric"
|
||||
"github.com/influxdata/telegraf/plugins/outputs"
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
)
|
||||
|
||||
type sink struct {
|
||||
datapoints []*datapoint.Datapoint
|
||||
events []*event.Event
|
||||
}
|
||||
|
||||
func (s *sink) AddDatapoints(_ context.Context, points []*datapoint.Datapoint) error {
|
||||
s.datapoints = append(s.datapoints, points...)
|
||||
return nil
|
||||
}
|
||||
func (s *sink) AddEvents(_ context.Context, events []*event.Event) error {
|
||||
s.events = append(s.events, events...)
|
||||
return nil
|
||||
}
|
||||
|
||||
type errorsink struct {
|
||||
datapoints []*datapoint.Datapoint
|
||||
events []*event.Event
|
||||
}
|
||||
|
||||
func (*errorsink) AddDatapoints(context.Context, []*datapoint.Datapoint) error {
|
||||
return errors.New("not sending datapoints")
|
||||
}
|
||||
func (*errorsink) AddEvents(context.Context, []*event.Event) error {
|
||||
return errors.New("not sending events")
|
||||
}
|
||||
|
||||
func TestSignalFx_SignalFx(t *testing.T) {
|
||||
type measurement struct {
|
||||
name string
|
||||
tags map[string]string
|
||||
fields map[string]interface{}
|
||||
time time.Time
|
||||
tp telegraf.ValueType
|
||||
}
|
||||
type fields struct {
|
||||
IncludedEvents []string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
measurements []*measurement
|
||||
want errorsink
|
||||
}{
|
||||
{
|
||||
name: "add datapoints of all types",
|
||||
fields: fields{},
|
||||
measurements: []*measurement{
|
||||
{
|
||||
name: "datapoint",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Counter,
|
||||
},
|
||||
{
|
||||
name: "datapoint",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Gauge,
|
||||
},
|
||||
{
|
||||
name: "datapoint",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Summary,
|
||||
},
|
||||
{
|
||||
name: "datapoint",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Histogram,
|
||||
},
|
||||
{
|
||||
name: "datapoint",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Untyped,
|
||||
},
|
||||
{
|
||||
name: "datapoint",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
},
|
||||
{
|
||||
name: "datapoint",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"myboolmeasurement": true},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
},
|
||||
{
|
||||
name: "datapoint",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"myboolmeasurement": false},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
},
|
||||
},
|
||||
want: errorsink{
|
||||
datapoints: []*datapoint.Datapoint{
|
||||
datapoint.New(
|
||||
"datapoint.mymeasurement",
|
||||
map[string]string{
|
||||
"host": "192.168.0.1",
|
||||
},
|
||||
datapoint.NewFloatValue(float64(3.14)),
|
||||
datapoint.Counter,
|
||||
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
|
||||
datapoint.New(
|
||||
"datapoint.mymeasurement",
|
||||
map[string]string{
|
||||
"host": "192.168.0.1",
|
||||
},
|
||||
datapoint.NewFloatValue(float64(3.14)),
|
||||
datapoint.Gauge,
|
||||
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
|
||||
datapoint.New(
|
||||
"datapoint.mymeasurement",
|
||||
map[string]string{
|
||||
"host": "192.168.0.1",
|
||||
},
|
||||
datapoint.NewFloatValue(float64(3.14)),
|
||||
datapoint.Gauge,
|
||||
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
|
||||
datapoint.New(
|
||||
"datapoint.mymeasurement",
|
||||
map[string]string{
|
||||
"host": "192.168.0.1",
|
||||
},
|
||||
datapoint.NewFloatValue(float64(3.14)),
|
||||
datapoint.Gauge,
|
||||
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
|
||||
datapoint.New(
|
||||
"datapoint.mymeasurement",
|
||||
map[string]string{
|
||||
"host": "192.168.0.1",
|
||||
},
|
||||
datapoint.NewFloatValue(float64(3.14)),
|
||||
datapoint.Gauge,
|
||||
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
|
||||
datapoint.New(
|
||||
"datapoint.mymeasurement",
|
||||
map[string]string{
|
||||
"host": "192.168.0.1",
|
||||
},
|
||||
datapoint.NewFloatValue(float64(3.14)),
|
||||
datapoint.Gauge,
|
||||
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
|
||||
datapoint.New(
|
||||
"datapoint.myboolmeasurement",
|
||||
map[string]string{
|
||||
"host": "192.168.0.1",
|
||||
},
|
||||
datapoint.NewIntValue(int64(1)),
|
||||
datapoint.Gauge,
|
||||
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
|
||||
datapoint.New(
|
||||
"datapoint.myboolmeasurement",
|
||||
map[string]string{
|
||||
"host": "192.168.0.1",
|
||||
},
|
||||
datapoint.NewIntValue(int64(0)),
|
||||
datapoint.Gauge,
|
||||
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
|
||||
},
|
||||
events: make([]*event.Event, 0),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "add events of all types",
|
||||
fields: fields{
|
||||
IncludedEvents: []string{"event.mymeasurement"},
|
||||
},
|
||||
measurements: []*measurement{
|
||||
{
|
||||
name: "event",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": "hello world"},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Counter,
|
||||
},
|
||||
{
|
||||
name: "event",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": "hello world"},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Gauge,
|
||||
},
|
||||
{
|
||||
name: "event",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": "hello world"},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Summary,
|
||||
},
|
||||
{
|
||||
name: "event",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": "hello world"},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Histogram,
|
||||
},
|
||||
{
|
||||
name: "event",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": "hello world"},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Untyped,
|
||||
},
|
||||
{
|
||||
name: "event",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": "hello world"},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
},
|
||||
},
|
||||
want: errorsink{
|
||||
datapoints: make([]*datapoint.Datapoint, 0),
|
||||
events: []*event.Event{
|
||||
event.NewWithProperties(
|
||||
"event.mymeasurement",
|
||||
event.AGENT,
|
||||
map[string]string{
|
||||
"host": "192.168.0.1",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"message": "hello world",
|
||||
},
|
||||
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
|
||||
event.NewWithProperties(
|
||||
"event.mymeasurement",
|
||||
event.AGENT,
|
||||
map[string]string{
|
||||
"host": "192.168.0.1",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"message": "hello world",
|
||||
},
|
||||
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
|
||||
event.NewWithProperties(
|
||||
"event.mymeasurement",
|
||||
event.AGENT,
|
||||
map[string]string{
|
||||
"host": "192.168.0.1",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"message": "hello world",
|
||||
},
|
||||
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
|
||||
event.NewWithProperties(
|
||||
"event.mymeasurement",
|
||||
event.AGENT,
|
||||
map[string]string{
|
||||
"host": "192.168.0.1",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"message": "hello world",
|
||||
},
|
||||
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
|
||||
event.NewWithProperties(
|
||||
"event.mymeasurement",
|
||||
event.AGENT,
|
||||
map[string]string{
|
||||
"host": "192.168.0.1",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"message": "hello world",
|
||||
},
|
||||
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
|
||||
event.NewWithProperties(
|
||||
"event.mymeasurement",
|
||||
event.AGENT,
|
||||
map[string]string{
|
||||
"host": "192.168.0.1",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"message": "hello world",
|
||||
},
|
||||
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "exclude events by default",
|
||||
fields: fields{},
|
||||
measurements: []*measurement{
|
||||
{
|
||||
name: "event",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"value": "hello world"},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Gauge,
|
||||
},
|
||||
},
|
||||
want: errorsink{
|
||||
datapoints: make([]*datapoint.Datapoint, 0),
|
||||
events: make([]*event.Event, 0),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "add datapoint with field named value",
|
||||
fields: fields{},
|
||||
measurements: []*measurement{
|
||||
{
|
||||
name: "datapoint",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"value": float64(3.14)},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Gauge,
|
||||
},
|
||||
},
|
||||
want: errorsink{
|
||||
datapoints: []*datapoint.Datapoint{
|
||||
datapoint.New(
|
||||
"datapoint",
|
||||
map[string]string{
|
||||
"host": "192.168.0.1",
|
||||
},
|
||||
datapoint.NewFloatValue(float64(3.14)),
|
||||
datapoint.Gauge,
|
||||
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
|
||||
},
|
||||
events: make([]*event.Event, 0),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "add event",
|
||||
fields: fields{
|
||||
IncludedEvents: []string{"event.mymeasurement"},
|
||||
},
|
||||
measurements: []*measurement{
|
||||
{
|
||||
name: "event",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": "hello world"},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Untyped,
|
||||
},
|
||||
},
|
||||
want: errorsink{
|
||||
datapoints: make([]*datapoint.Datapoint, 0),
|
||||
events: []*event.Event{
|
||||
event.NewWithProperties(
|
||||
"event.mymeasurement",
|
||||
event.AGENT,
|
||||
map[string]string{
|
||||
"host": "192.168.0.1",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"message": "hello world",
|
||||
},
|
||||
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "exclude events that are not explicitly included",
|
||||
fields: fields{},
|
||||
measurements: []*measurement{
|
||||
{
|
||||
name: "event",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"value": "hello world"},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Gauge,
|
||||
},
|
||||
},
|
||||
want: errorsink{
|
||||
datapoints: make([]*datapoint.Datapoint, 0),
|
||||
events: make([]*event.Event, 0),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "malformed metadata event",
|
||||
fields: fields{},
|
||||
measurements: []*measurement{
|
||||
{
|
||||
name: "event",
|
||||
tags: map[string]string{"host": "192.168.0.1", "sf_metric": "objects.host-meta-data"},
|
||||
fields: map[string]interface{}{"value": "hello world"},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Gauge,
|
||||
},
|
||||
},
|
||||
want: errorsink{
|
||||
datapoints: make([]*datapoint.Datapoint, 0),
|
||||
events: make([]*event.Event, 0),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := outputs.Outputs["signalfx"]().(*SignalFx)
|
||||
s.IncludedEventNames = tt.fields.IncludedEvents
|
||||
s.SignalFxRealm = "test"
|
||||
s.Log = testutil.Logger{}
|
||||
|
||||
require.NoError(t, s.Connect())
|
||||
|
||||
s.client = &sink{
|
||||
datapoints: make([]*datapoint.Datapoint, 0),
|
||||
events: make([]*event.Event, 0),
|
||||
}
|
||||
|
||||
measurements := make([]telegraf.Metric, 0, len(tt.measurements))
|
||||
for _, measurement := range tt.measurements {
|
||||
measurements = append(measurements, metric.New(measurement.name, measurement.tags, measurement.fields, measurement.time, measurement.tp))
|
||||
}
|
||||
|
||||
err := s.Write(measurements)
|
||||
require.NoError(t, err)
|
||||
require.Eventually(t, func() bool { return len(s.client.(*sink).datapoints) == len(tt.want.datapoints) }, 5*time.Second, 10*time.Millisecond)
|
||||
require.Eventually(t, func() bool { return len(s.client.(*sink).events) == len(tt.want.events) }, 5*time.Second, 10*time.Millisecond)
|
||||
|
||||
if !reflect.DeepEqual(s.client.(*sink).datapoints, tt.want.datapoints) {
|
||||
t.Errorf("Collected datapoints do not match desired. Collected: %v Desired: %v", s.client.(*sink).datapoints, tt.want.datapoints)
|
||||
}
|
||||
if !reflect.DeepEqual(s.client.(*sink).events, tt.want.events) {
|
||||
t.Errorf("Collected events do not match desired. Collected: %v Desired: %v", s.client.(*sink).events, tt.want.events)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignalFx_Errors(t *testing.T) {
|
||||
type measurement struct {
|
||||
name string
|
||||
tags map[string]string
|
||||
fields map[string]interface{}
|
||||
time time.Time
|
||||
tp telegraf.ValueType
|
||||
}
|
||||
type fields struct {
|
||||
IncludedEvents []string
|
||||
}
|
||||
type want struct {
|
||||
datapoints []*datapoint.Datapoint
|
||||
events []*event.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
measurements []*measurement
|
||||
want want
|
||||
}{
|
||||
{
|
||||
name: "add datapoints of all types",
|
||||
fields: fields{},
|
||||
measurements: []*measurement{
|
||||
{
|
||||
name: "datapoint",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Counter,
|
||||
},
|
||||
{
|
||||
name: "datapoint",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Gauge,
|
||||
},
|
||||
{
|
||||
name: "datapoint",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Summary,
|
||||
},
|
||||
{
|
||||
name: "datapoint",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Histogram,
|
||||
},
|
||||
{
|
||||
name: "datapoint",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Untyped,
|
||||
},
|
||||
{
|
||||
name: "datapoint",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
datapoints: make([]*datapoint.Datapoint, 0),
|
||||
events: make([]*event.Event, 0),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "add events of all types",
|
||||
fields: fields{
|
||||
IncludedEvents: []string{"event.mymeasurement"},
|
||||
},
|
||||
measurements: []*measurement{
|
||||
{
|
||||
name: "event",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": "hello world"},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Counter,
|
||||
},
|
||||
{
|
||||
name: "event",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": "hello world"},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Gauge,
|
||||
},
|
||||
{
|
||||
name: "event",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": "hello world"},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Summary,
|
||||
},
|
||||
{
|
||||
name: "event",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": "hello world"},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Histogram,
|
||||
},
|
||||
{
|
||||
name: "event",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": "hello world"},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
tp: telegraf.Untyped,
|
||||
},
|
||||
{
|
||||
name: "event",
|
||||
tags: map[string]string{"host": "192.168.0.1"},
|
||||
fields: map[string]interface{}{"mymeasurement": "hello world"},
|
||||
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
datapoints: make([]*datapoint.Datapoint, 0),
|
||||
events: make([]*event.Event, 0),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := outputs.Outputs["signalfx"]().(*SignalFx)
|
||||
// constrain the buffer to cover code that emits when batch size is met
|
||||
s.IncludedEventNames = tt.fields.IncludedEvents
|
||||
s.SignalFxRealm = "test"
|
||||
s.Log = testutil.Logger{}
|
||||
|
||||
require.NoError(t, s.Connect())
|
||||
|
||||
s.client = &errorsink{
|
||||
datapoints: make([]*datapoint.Datapoint, 0),
|
||||
events: make([]*event.Event, 0),
|
||||
}
|
||||
|
||||
for _, measurement := range tt.measurements {
|
||||
m := metric.New(
|
||||
measurement.name, measurement.tags, measurement.fields, measurement.time, measurement.tp,
|
||||
)
|
||||
|
||||
err := s.Write([]telegraf.Metric{m})
|
||||
require.Error(t, err)
|
||||
}
|
||||
for len(s.client.(*errorsink).datapoints) != len(tt.want.datapoints) || len(s.client.(*errorsink).events) != len(tt.want.events) {
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
if !reflect.DeepEqual(s.client.(*errorsink).datapoints, tt.want.datapoints) {
|
||||
t.Errorf("Collected datapoints do not match desired. Collected: %v Desired: %v", s.client.(*errorsink).datapoints, tt.want.datapoints)
|
||||
}
|
||||
if !reflect.DeepEqual(s.client.(*errorsink).events, tt.want.events) {
|
||||
t.Errorf("Collected events do not match desired. Collected: %v Desired: %v", s.client.(*errorsink).events, tt.want.events)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMetricName(t *testing.T) {
|
||||
type args struct {
|
||||
metric string
|
||||
field string
|
||||
dims map[string]string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
wantsfx bool
|
||||
}{
|
||||
{
|
||||
name: "fields that equal value should not be append to metricname",
|
||||
args: args{
|
||||
metric: "datapoint",
|
||||
field: "value",
|
||||
dims: map[string]string{
|
||||
"testDimKey": "testDimVal",
|
||||
},
|
||||
},
|
||||
want: "datapoint",
|
||||
},
|
||||
{
|
||||
name: "fields other than 'value' with out sf_metric dim should return measurement.fieldname as metric name",
|
||||
args: args{
|
||||
metric: "datapoint",
|
||||
field: "test",
|
||||
dims: map[string]string{
|
||||
"testDimKey": "testDimVal",
|
||||
},
|
||||
},
|
||||
want: "datapoint.test",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := getMetricName(tt.args.metric, tt.args.field)
|
||||
if got != tt.want {
|
||||
t.Errorf("getMetricName() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue