Skip unserializable metric in influxDB UDP output (#4534)

This commit is contained in:
Daniel Nelson
2018-08-14 13:36:29 -07:00
committed by Greg
parent 763dc6990c
commit fa30f568ec
5 changed files with 119 additions and 82 deletions

View File

@@ -3,11 +3,11 @@ package influxdb
import (
"context"
"fmt"
"log"
"net"
"net/url"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/serializers"
"github.com/influxdata/telegraf/plugins/serializers/influx"
)
@@ -28,7 +28,7 @@ type Conn interface {
type UDPConfig struct {
MaxPayloadSize int
URL *url.URL
Serializer serializers.Serializer
Serializer *influx.Serializer
Dialer Dialer
}
@@ -65,7 +65,7 @@ func NewUDPClient(config *UDPConfig) (*udpClient, error) {
type udpClient struct {
conn Conn
dialer Dialer
serializer serializers.Serializer
serializer *influx.Serializer
url *url.URL
}
@@ -89,7 +89,11 @@ func (c *udpClient) Write(ctx context.Context, metrics []telegraf.Metric) error
for _, metric := range metrics {
octets, err := c.serializer.Serialize(metric)
if err != nil {
return fmt.Errorf("could not serialize metric: %v", err)
// Since we are serializing multiple metrics, don't fail the
// entire batch just because of one unserializable metric.
log.Printf("E! [outputs.influxdb] when writing to [%s] could not serialize metric: %v",
c.URL(), err)
continue
}
_, err = c.conn.Write(octets)

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"fmt"
"log"
"net"
"net/url"
"sync"
@@ -13,7 +14,6 @@ import (
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/metric"
"github.com/influxdata/telegraf/plugins/outputs/influxdb"
"github.com/influxdata/telegraf/plugins/serializers/influx"
"github.com/stretchr/testify/require"
)
@@ -65,19 +65,6 @@ func (d *MockDialer) DialContext(ctx context.Context, network string, address st
return d.DialContextF(network, address)
}
type MockSerializer struct {
SerializeF func(metric telegraf.Metric) ([]byte, error)
SerializeBatchF func(metrics []telegraf.Metric) ([]byte, error)
}
func (s *MockSerializer) Serialize(metric telegraf.Metric) ([]byte, error) {
return s.SerializeF(metric)
}
func (s *MockSerializer) SerializeBatch(metrics []telegraf.Metric) ([]byte, error) {
return s.SerializeBatchF(metrics)
}
func TestUDP_NewUDPClientNoURL(t *testing.T) {
config := &influxdb.UDPConfig{}
_, err := influxdb.NewUDPClient(config)
@@ -177,28 +164,69 @@ func TestUDP_WriteError(t *testing.T) {
require.True(t, closed)
}
func TestUDP_SerializeError(t *testing.T) {
config := &influxdb.UDPConfig{
URL: getURL(),
Dialer: &MockDialer{
DialContextF: func(network, address string) (influxdb.Conn, error) {
conn := &MockConn{}
return conn, nil
func TestUDP_ErrorLogging(t *testing.T) {
tests := []struct {
name string
config *influxdb.UDPConfig
metrics []telegraf.Metric
logContains string
}{
{
name: "logs need more space",
config: &influxdb.UDPConfig{
MaxPayloadSize: 1,
URL: getURL(),
Dialer: &MockDialer{
DialContextF: func(network, address string) (influxdb.Conn, error) {
conn := &MockConn{}
return conn, nil
},
},
},
metrics: []telegraf.Metric{getMetric()},
logContains: `could not serialize metric: "cpu": need more space`,
},
Serializer: &MockSerializer{
SerializeF: func(metric telegraf.Metric) ([]byte, error) {
return nil, influx.ErrNeedMoreSpace
{
name: "logs series name",
config: &influxdb.UDPConfig{
URL: getURL(),
Dialer: &MockDialer{
DialContextF: func(network, address string) (influxdb.Conn, error) {
conn := &MockConn{}
return conn, nil
},
},
},
metrics: []telegraf.Metric{
func() telegraf.Metric {
metric, _ := metric.New(
"cpu",
map[string]string{
"host": "example.org",
},
map[string]interface{}{},
time.Unix(0, 0),
)
return metric
}(),
},
logContains: `could not serialize metric: "cpu,host=example.org": no serializable fields`,
},
}
client, err := influxdb.NewUDPClient(config)
require.NoError(t, err)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var b bytes.Buffer
log.SetOutput(&b)
ctx := context.Background()
err = client.Write(ctx, []telegraf.Metric{getMetric()})
require.Error(t, err)
require.Contains(t, err.Error(), influx.ErrNeedMoreSpace.Error())
client, err := influxdb.NewUDPClient(tt.config)
require.NoError(t, err)
ctx := context.Background()
err = client.Write(ctx, tt.metrics)
require.NoError(t, err)
require.Contains(t, b.String(), tt.logContains)
})
}
}
func TestUDP_WriteWithRealConn(t *testing.T) {