1
0
Fork 0
telegraf/plugins/processors/scale/scale.go
Daniel Baumann 4978089aab
Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-05-24 07:26:29 +02:00

147 lines
3.8 KiB
Go

//go:generate ../../../tools/readme_config_includer/generator
package scale
import (
_ "embed"
"errors"
"fmt"
"strings"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/filter"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/plugins/processors"
)
//go:embed sample.conf
var sampleConfig string
func (*Scale) SampleConfig() string {
return sampleConfig
}
type Scaling struct {
InMin *float64 `toml:"input_minimum"`
InMax *float64 `toml:"input_maximum"`
OutMin *float64 `toml:"output_minimum"`
OutMax *float64 `toml:"output_maximum"`
Factor *float64 `toml:"factor"`
Offset *float64 `toml:"offset"`
Fields []string `toml:"fields"`
fieldFilter filter.Filter
scale float64
shiftIn float64
shiftOut float64
}
type Scale struct {
Scalings []Scaling `toml:"scaling"`
Log telegraf.Logger `toml:"-"`
}
func (s *Scaling) Init() error {
s.scale, s.shiftOut, s.shiftIn = float64(1.0), float64(0.0), float64(0.0)
allMinMaxSet := s.OutMax != nil && s.OutMin != nil && s.InMax != nil && s.InMin != nil
anyMinMaxSet := s.OutMax != nil || s.OutMin != nil || s.InMax != nil || s.InMin != nil
factorSet := s.Factor != nil || s.Offset != nil
if anyMinMaxSet && factorSet {
return fmt.Errorf("cannot use factor/offset and minimum/maximum at the same time for fields %s",
strings.Join(s.Fields, ","))
} else if anyMinMaxSet && !allMinMaxSet {
return fmt.Errorf("all minimum and maximum values need to be set for fields %s", strings.Join(s.Fields, ","))
} else if !anyMinMaxSet && !factorSet {
return fmt.Errorf("no scaling defined for fields %s", strings.Join(s.Fields, ","))
} else if allMinMaxSet {
if *s.InMax == *s.InMin {
return fmt.Errorf("input minimum and maximum are equal for fields %s", strings.Join(s.Fields, ","))
}
if *s.OutMax == *s.OutMin {
return fmt.Errorf("output minimum and maximum are equal for fields %s", strings.Join(s.Fields, ","))
}
s.scale = (*s.OutMax - *s.OutMin) / (*s.InMax - *s.InMin)
s.shiftOut = *s.OutMin
s.shiftIn = *s.InMin
} else {
if s.Factor != nil {
s.scale = *s.Factor
}
if s.Offset != nil {
s.shiftOut = *s.Offset
}
}
scalingFilter, err := filter.Compile(s.Fields)
if err != nil {
return fmt.Errorf("could not compile fields filter: %w", err)
}
s.fieldFilter = scalingFilter
return nil
}
// scale a float according to the input and output range
func (s *Scaling) process(value float64) float64 {
return s.scale*(value-s.shiftIn) + s.shiftOut
}
func (s *Scale) Init() error {
if s.Scalings == nil {
return errors.New("no valid scaling defined")
}
allFields := make(map[string]bool)
for i := range s.Scalings {
for _, field := range s.Scalings[i].Fields {
// only generate a warning for the first duplicate field filter
if warn, ok := allFields[field]; ok && warn {
s.Log.Warnf("Filter field %q used twice in scalings", field)
allFields[field] = false
} else {
allFields[field] = true
}
}
if err := s.Scalings[i].Init(); err != nil {
return fmt.Errorf("scaling %d: %w", i+1, err)
}
}
return nil
}
// handle the scaling process
func (s *Scale) scaleValues(metric telegraf.Metric) {
fields := metric.FieldList()
for _, scaling := range s.Scalings {
for _, field := range fields {
if !scaling.fieldFilter.Match(field.Key) {
continue
}
v, err := internal.ToFloat64(field.Value)
if err != nil {
s.Log.Errorf("Error converting %q to float: %v", field.Key, err)
continue
}
// scale the field values using the defined scaler
field.Value = scaling.process(v)
}
}
}
func (s *Scale) Apply(in ...telegraf.Metric) []telegraf.Metric {
for _, metric := range in {
s.scaleValues(metric)
}
return in
}
func init() {
processors.Add("scale", func() telegraf.Processor {
return &Scale{}
})
}