Skip unserializable metric in influxDB UDP output (#4534)
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user