1
0
Fork 0

Adding upstream version 1.34.4.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-24 07:26:29 +02:00
parent e393c3af3f
commit 4978089aab
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
4963 changed files with 677545 additions and 0 deletions

View 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"]
```

View 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"]

View 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"
}

View 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)
}
})
}
}