diff --git a/config/config.go b/config/config.go index 12573eb5a..5ef81be33 100644 --- a/config/config.go +++ b/config/config.go @@ -1478,11 +1478,6 @@ func (c *Config) buildSerializerOld(tbl *ast.Table) (telegraf.Serializer, error) c.getFieldString(tbl, "template", &sc.Template) c.getFieldStringSlice(tbl, "templates", &sc.Templates) - c.getFieldBool(tbl, "prometheus_export_timestamp", &sc.PrometheusExportTimestamp) - c.getFieldBool(tbl, "prometheus_sort_metrics", &sc.PrometheusSortMetrics) - c.getFieldBool(tbl, "prometheus_string_as_label", &sc.PrometheusStringAsLabel) - c.getFieldBool(tbl, "prometheus_compact_encoding", &sc.PrometheusCompactEncoding) - if c.hasErrs() { return nil, c.firstErr() } @@ -1548,9 +1543,7 @@ func (c *Config) missingTomlField(_ reflect.Type, key string) error { case "data_type", "influx_parser_type": // Serializer options to ignore - case "prefix", "template", "templates", - "prometheus_export_timestamp", "prometheus_sort_metrics", "prometheus_string_as_label", - "prometheus_compact_encoding": + case "prefix", "template", "templates": default: c.unusedFieldsMutex.Lock() c.UnusedFields[key] = true diff --git a/plugins/outputs/prometheus_client/v2/collector.go b/plugins/outputs/prometheus_client/v2/collector.go index a12c17571..4505c980d 100644 --- a/plugins/outputs/prometheus_client/v2/collector.go +++ b/plugins/outputs/prometheus_client/v2/collector.go @@ -44,18 +44,14 @@ type Collector struct { } func NewCollector(expire time.Duration, stringsAsLabel bool, exportTimestamp bool) *Collector { - config := serializer.FormatConfig{} - if stringsAsLabel { - config.StringHandling = serializer.StringAsLabel - } - - if exportTimestamp { - config.TimestampExport = serializer.ExportTimestamp + cfg := serializer.FormatConfig{ + StringAsLabel: stringsAsLabel, + ExportTimestamp: exportTimestamp, } return &Collector{ expireDuration: expire, - coll: serializer.NewCollection(config), + coll: serializer.NewCollection(cfg), } } diff --git a/plugins/serializers/all/prometheus.go b/plugins/serializers/all/prometheus.go new file mode 100644 index 000000000..2cbe32946 --- /dev/null +++ b/plugins/serializers/all/prometheus.go @@ -0,0 +1,7 @@ +//go:build !custom || serializers || serializers.prometheus + +package all + +import ( + _ "github.com/influxdata/telegraf/plugins/serializers/prometheus" // register plugin +) diff --git a/plugins/serializers/prometheus/collection.go b/plugins/serializers/prometheus/collection.go index 452341278..3754c2920 100644 --- a/plugins/serializers/prometheus/collection.go +++ b/plugins/serializers/prometheus/collection.go @@ -145,7 +145,7 @@ func (c *Collection) createLabels(metric telegraf.Metric) []LabelPair { labels = append(labels, LabelPair{Name: name, Value: tag.Value}) } - if c.config.StringHandling != StringAsLabel { + if !c.config.StringAsLabel { return labels } @@ -352,13 +352,13 @@ func (c *Collection) Expire(now time.Time, age time.Duration) { } } -func (c *Collection) GetEntries(order MetricSortOrder) []Entry { +func (c *Collection) GetEntries() []Entry { entries := make([]Entry, 0, len(c.Entries)) for _, entry := range c.Entries { entries = append(entries, entry) } - if order == SortMetrics { + if c.config.SortMetrics { sort.Slice(entries, func(i, j int) bool { lhs := entries[i].Family rhs := entries[j].Family @@ -372,13 +372,13 @@ func (c *Collection) GetEntries(order MetricSortOrder) []Entry { return entries } -func (c *Collection) GetMetrics(entry Entry, order MetricSortOrder) []*Metric { +func (c *Collection) GetMetrics(entry Entry) []*Metric { metrics := make([]*Metric, 0, len(entry.Metrics)) for _, metric := range entry.Metrics { metrics = append(metrics, metric) } - if order == SortMetrics { + if c.config.SortMetrics { sort.Slice(metrics, func(i, j int) bool { lhs := metrics[i].Labels rhs := metrics[j].Labels @@ -409,7 +409,7 @@ func (c *Collection) GetMetrics(entry Entry, order MetricSortOrder) []*Metric { func (c *Collection) GetProto() []*dto.MetricFamily { result := make([]*dto.MetricFamily, 0, len(c.Entries)) - for _, entry := range c.GetEntries(c.config.MetricSortOrder) { + for _, entry := range c.GetEntries() { mf := &dto.MetricFamily{ Name: proto.String(entry.Family.Name), Type: MetricType(entry.Family.Type), @@ -419,7 +419,7 @@ func (c *Collection) GetProto() []*dto.MetricFamily { mf.Help = proto.String(helpString) } - for _, metric := range c.GetMetrics(entry, c.config.MetricSortOrder) { + for _, metric := range c.GetMetrics(entry) { l := make([]*dto.LabelPair, 0, len(metric.Labels)) for _, label := range metric.Labels { l = append(l, &dto.LabelPair{ @@ -432,7 +432,7 @@ func (c *Collection) GetProto() []*dto.MetricFamily { Label: l, } - if c.config.TimestampExport == ExportTimestamp { + if c.config.ExportTimestamp { m.TimestampMs = proto.Int64(metric.Time.UnixNano() / int64(time.Millisecond)) } diff --git a/plugins/serializers/prometheus/collection_test.go b/plugins/serializers/prometheus/collection_test.go index 67447e664..b386e37e4 100644 --- a/plugins/serializers/prometheus/collection_test.go +++ b/plugins/serializers/prometheus/collection_test.go @@ -830,7 +830,7 @@ func TestExportTimestamps(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - c := NewCollection(FormatConfig{TimestampExport: ExportTimestamp}) + c := NewCollection(FormatConfig{ExportTimestamp: true}) for _, item := range tt.input { c.Add(item.metric, item.addtime) } diff --git a/plugins/serializers/prometheus/prometheus.go b/plugins/serializers/prometheus/prometheus.go index 3be4f4bcf..d259640fb 100644 --- a/plugins/serializers/prometheus/prometheus.go +++ b/plugins/serializers/prometheus/prometheus.go @@ -7,48 +7,21 @@ import ( "github.com/prometheus/common/expfmt" "github.com/influxdata/telegraf" -) - -// TimestampExport controls if the output contains timestamps. -type TimestampExport int - -const ( - NoExportTimestamp TimestampExport = iota - ExportTimestamp -) - -// MetricSortOrder controls if the output is sorted. -type MetricSortOrder int - -const ( - NoSortMetrics MetricSortOrder = iota - SortMetrics -) - -// StringHandling defines how to process string fields. -type StringHandling int - -const ( - DiscardStrings StringHandling = iota - StringAsLabel + "github.com/influxdata/telegraf/plugins/serializers" ) type FormatConfig struct { - TimestampExport TimestampExport - MetricSortOrder MetricSortOrder - StringHandling StringHandling + ExportTimestamp bool `toml:"prometheus_export_timestamp"` + SortMetrics bool `toml:"prometheus_sort_metrics"` + StringAsLabel bool `toml:"prometheus_string_as_label"` // CompactEncoding defines whether to include // HELP metadata in Prometheus payload. Setting to true // helps to reduce payload size. - CompactEncoding bool + CompactEncoding bool `toml:"prometheus_compact_encoding"` } type Serializer struct { - config FormatConfig -} - -func NewSerializer(config FormatConfig) *Serializer { - return &Serializer{config: config} + FormatConfig } func (s *Serializer) Serialize(metric telegraf.Metric) ([]byte, error) { @@ -56,7 +29,7 @@ func (s *Serializer) Serialize(metric telegraf.Metric) ([]byte, error) { } func (s *Serializer) SerializeBatch(metrics []telegraf.Metric) ([]byte, error) { - coll := NewCollection(s.config) + coll := NewCollection(s.FormatConfig) for _, metric := range metrics { coll.Add(metric, time.Now()) } @@ -72,3 +45,21 @@ func (s *Serializer) SerializeBatch(metrics []telegraf.Metric) ([]byte, error) { return buf.Bytes(), nil } + +func init() { + serializers.Add("prometheus", + func() serializers.Serializer { + return &Serializer{} + }, + ) +} + +// InitFromConfig is a compatibility function to construct the parser the old way +func (s *Serializer) InitFromConfig(cfg *serializers.Config) error { + s.FormatConfig.CompactEncoding = cfg.PrometheusCompactEncoding + s.FormatConfig.SortMetrics = cfg.PrometheusSortMetrics + s.FormatConfig.StringAsLabel = cfg.PrometheusStringAsLabel + s.FormatConfig.ExportTimestamp = cfg.PrometheusExportTimestamp + + return nil +} diff --git a/plugins/serializers/prometheus/prometheus_test.go b/plugins/serializers/prometheus/prometheus_test.go index 30518f69f..356e4363c 100644 --- a/plugins/serializers/prometheus/prometheus_test.go +++ b/plugins/serializers/prometheus/prometheus_test.go @@ -141,7 +141,7 @@ http_request_duration_seconds_count 0 { name: "simple with timestamp", config: FormatConfig{ - TimestampExport: ExportTimestamp, + ExportTimestamp: true, }, metric: testutil.MustMetric( "cpu", @@ -182,12 +182,14 @@ cpu_time_idle{host="example.org"} 42 } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - s := NewSerializer(FormatConfig{ - MetricSortOrder: SortMetrics, - TimestampExport: tt.config.TimestampExport, - StringHandling: tt.config.StringHandling, - CompactEncoding: tt.config.CompactEncoding, - }) + s := &Serializer{ + FormatConfig{ + SortMetrics: true, + ExportTimestamp: tt.config.ExportTimestamp, + StringAsLabel: tt.config.StringAsLabel, + CompactEncoding: tt.config.CompactEncoding, + }, + } actual, err := s.Serialize(tt.metric) require.NoError(t, err) @@ -536,7 +538,7 @@ cpu_time_idle 42 { name: "string as label", config: FormatConfig{ - StringHandling: StringAsLabel, + StringAsLabel: true, }, metrics: []telegraf.Metric{ testutil.MustMetric( @@ -558,7 +560,7 @@ cpu_time_idle{cpu="cpu0"} 42 { name: "string as label duplicate tag", config: FormatConfig{ - StringHandling: StringAsLabel, + StringAsLabel: true, }, metrics: []telegraf.Metric{ testutil.MustMetric( @@ -582,7 +584,7 @@ cpu_time_idle{cpu="cpu0"} 42 { name: "replace characters when using string as label", config: FormatConfig{ - StringHandling: StringAsLabel, + StringAsLabel: true, }, metrics: []telegraf.Metric{ testutil.MustMetric( @@ -698,11 +700,13 @@ rpc_duration_seconds_count 2693 } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - s := NewSerializer(FormatConfig{ - MetricSortOrder: SortMetrics, - TimestampExport: tt.config.TimestampExport, - StringHandling: tt.config.StringHandling, - }) + s := &Serializer{ + FormatConfig{ + SortMetrics: true, + ExportTimestamp: tt.config.ExportTimestamp, + StringAsLabel: tt.config.StringAsLabel, + }, + } actual, err := s.SerializeBatch(tt.metrics) require.NoError(t, err) diff --git a/plugins/serializers/registry.go b/plugins/serializers/registry.go index 101498df4..a454c097a 100644 --- a/plugins/serializers/registry.go +++ b/plugins/serializers/registry.go @@ -5,7 +5,6 @@ import ( "time" "github.com/influxdata/telegraf" - "github.com/influxdata/telegraf/plugins/serializers/prometheus" ) // Creator is the function to create a new serializer @@ -154,50 +153,18 @@ type Config struct { // NewSerializer a Serializer interface based on the given config. func NewSerializer(config *Config) (Serializer, error) { - var err error - var serializer Serializer - switch config.DataFormat { - case "prometheus": - serializer, err = NewPrometheusSerializer(config), nil - default: - creator, found := Serializers[config.DataFormat] - if !found { - return nil, fmt.Errorf("invalid data format: %s", config.DataFormat) - } - - // Try to create new-style serializers the old way... - serializer := creator() - p, ok := serializer.(SerializerCompatibility) - if !ok { - return nil, fmt.Errorf("serializer for %q cannot be created the old way", config.DataFormat) - } - err := p.InitFromConfig(config) - - return serializer, err + creator, found := Serializers[config.DataFormat] + if !found { + return nil, fmt.Errorf("invalid data format: %s", config.DataFormat) } + + // Try to create new-style serializers the old way... + serializer := creator() + p, ok := serializer.(SerializerCompatibility) + if !ok { + return nil, fmt.Errorf("serializer for %q cannot be created the old way", config.DataFormat) + } + err := p.InitFromConfig(config) + return serializer, err } - -func NewPrometheusSerializer(config *Config) Serializer { - exportTimestamp := prometheus.NoExportTimestamp - if config.PrometheusExportTimestamp { - exportTimestamp = prometheus.ExportTimestamp - } - - sortMetrics := prometheus.NoSortMetrics - if config.PrometheusExportTimestamp { - sortMetrics = prometheus.SortMetrics - } - - stringAsLabels := prometheus.DiscardStrings - if config.PrometheusStringAsLabel { - stringAsLabels = prometheus.StringAsLabel - } - - return prometheus.NewSerializer(prometheus.FormatConfig{ - TimestampExport: exportTimestamp, - MetricSortOrder: sortMetrics, - StringHandling: stringAsLabels, - CompactEncoding: config.PrometheusCompactEncoding, - }) -}