Support floats in statsd percentiles (#5572)
This commit is contained in:
parent
70e2ccce75
commit
72c2ac9648
|
@ -48,6 +48,10 @@ type Size struct {
|
||||||
Size int64
|
Size int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Number struct {
|
||||||
|
Value float64
|
||||||
|
}
|
||||||
|
|
||||||
// SetVersion sets the telegraf agent version
|
// SetVersion sets the telegraf agent version
|
||||||
func SetVersion(v string) error {
|
func SetVersion(v string) error {
|
||||||
if version != "" {
|
if version != "" {
|
||||||
|
@ -124,6 +128,16 @@ func (s *Size) UnmarshalTOML(b []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *Number) UnmarshalTOML(b []byte) error {
|
||||||
|
value, err := strconv.ParseFloat(string(b), 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
n.Value = value
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ReadLines reads contents from a file and splits them by new lines.
|
// ReadLines reads contents from a file and splits them by new lines.
|
||||||
// A convenience wrapper to ReadLinesOffsetN(filename, 0, -1).
|
// A convenience wrapper to ReadLinesOffsetN(filename, 0, -1).
|
||||||
func ReadLines(filename string) ([]string, error) {
|
func ReadLines(filename string) ([]string, error) {
|
||||||
|
|
|
@ -34,8 +34,8 @@
|
||||||
## Reset timings & histograms every interval (default=true)
|
## Reset timings & histograms every interval (default=true)
|
||||||
delete_timings = true
|
delete_timings = true
|
||||||
|
|
||||||
## Percentiles to calculate for timing & histogram stats
|
## Percentiles to calculate for timing & histogram stats.
|
||||||
percentiles = [90]
|
percentiles = [50.0, 90.0, 99.0, 99.9, 99.95, 100.0]
|
||||||
|
|
||||||
## separator to use between elements of a statsd metric
|
## separator to use between elements of a statsd metric
|
||||||
metric_separator = "_"
|
metric_separator = "_"
|
||||||
|
|
|
@ -99,7 +99,7 @@ func (rs *RunningStats) Count() int64 {
|
||||||
return rs.n
|
return rs.n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *RunningStats) Percentile(n int) float64 {
|
func (rs *RunningStats) Percentile(n float64) float64 {
|
||||||
if n > 100 {
|
if n > 100 {
|
||||||
n = 100
|
n = 100
|
||||||
}
|
}
|
||||||
|
@ -109,16 +109,16 @@ func (rs *RunningStats) Percentile(n int) float64 {
|
||||||
rs.sorted = true
|
rs.sorted = true
|
||||||
}
|
}
|
||||||
|
|
||||||
i := int(float64(len(rs.perc)) * float64(n) / float64(100))
|
i := float64(len(rs.perc)) * n / float64(100)
|
||||||
return rs.perc[clamp(i, 0, len(rs.perc)-1)]
|
return rs.perc[clamp(i, 0, len(rs.perc)-1)]
|
||||||
}
|
}
|
||||||
|
|
||||||
func clamp(i int, min int, max int) int {
|
func clamp(i float64, min int, max int) int {
|
||||||
if i < min {
|
if i < float64(min) {
|
||||||
return min
|
return min
|
||||||
}
|
}
|
||||||
if i > max {
|
if i > float64(max) {
|
||||||
return max
|
return max
|
||||||
}
|
}
|
||||||
return i
|
return int(i)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,9 @@ func TestRunningStats_Single(t *testing.T) {
|
||||||
if rs.Percentile(100) != 10.1 {
|
if rs.Percentile(100) != 10.1 {
|
||||||
t.Errorf("Expected %v, got %v", 10.1, rs.Percentile(100))
|
t.Errorf("Expected %v, got %v", 10.1, rs.Percentile(100))
|
||||||
}
|
}
|
||||||
|
if rs.Percentile(99.95) != 10.1 {
|
||||||
|
t.Errorf("Expected %v, got %v", 10.1, rs.Percentile(99.95))
|
||||||
|
}
|
||||||
if rs.Percentile(90) != 10.1 {
|
if rs.Percentile(90) != 10.1 {
|
||||||
t.Errorf("Expected %v, got %v", 10.1, rs.Percentile(90))
|
t.Errorf("Expected %v, got %v", 10.1, rs.Percentile(90))
|
||||||
}
|
}
|
||||||
|
@ -67,6 +70,9 @@ func TestRunningStats_Duplicate(t *testing.T) {
|
||||||
if rs.Percentile(100) != 10.1 {
|
if rs.Percentile(100) != 10.1 {
|
||||||
t.Errorf("Expected %v, got %v", 10.1, rs.Percentile(100))
|
t.Errorf("Expected %v, got %v", 10.1, rs.Percentile(100))
|
||||||
}
|
}
|
||||||
|
if rs.Percentile(99.95) != 10.1 {
|
||||||
|
t.Errorf("Expected %v, got %v", 10.1, rs.Percentile(99.95))
|
||||||
|
}
|
||||||
if rs.Percentile(90) != 10.1 {
|
if rs.Percentile(90) != 10.1 {
|
||||||
t.Errorf("Expected %v, got %v", 10.1, rs.Percentile(90))
|
t.Errorf("Expected %v, got %v", 10.1, rs.Percentile(90))
|
||||||
}
|
}
|
||||||
|
@ -108,12 +114,21 @@ func TestRunningStats(t *testing.T) {
|
||||||
if rs.Percentile(100) != 45 {
|
if rs.Percentile(100) != 45 {
|
||||||
t.Errorf("Expected %v, got %v", 45, rs.Percentile(100))
|
t.Errorf("Expected %v, got %v", 45, rs.Percentile(100))
|
||||||
}
|
}
|
||||||
|
if rs.Percentile(99.98) != 45 {
|
||||||
|
t.Errorf("Expected %v, got %v", 45, rs.Percentile(99.98))
|
||||||
|
}
|
||||||
if rs.Percentile(90) != 32 {
|
if rs.Percentile(90) != 32 {
|
||||||
t.Errorf("Expected %v, got %v", 32, rs.Percentile(90))
|
t.Errorf("Expected %v, got %v", 32, rs.Percentile(90))
|
||||||
}
|
}
|
||||||
|
if rs.Percentile(50.1) != 11 {
|
||||||
|
t.Errorf("Expected %v, got %v", 11, rs.Percentile(50.1))
|
||||||
|
}
|
||||||
if rs.Percentile(50) != 11 {
|
if rs.Percentile(50) != 11 {
|
||||||
t.Errorf("Expected %v, got %v", 11, rs.Percentile(50))
|
t.Errorf("Expected %v, got %v", 11, rs.Percentile(50))
|
||||||
}
|
}
|
||||||
|
if rs.Percentile(49.9) != 10 {
|
||||||
|
t.Errorf("Expected %v, got %v", 10, rs.Percentile(49.9))
|
||||||
|
}
|
||||||
if rs.Percentile(0) != 5 {
|
if rs.Percentile(0) != 5 {
|
||||||
t.Errorf("Expected %v, got %v", 5, rs.Percentile(0))
|
t.Errorf("Expected %v, got %v", 5, rs.Percentile(0))
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ type Statsd struct {
|
||||||
|
|
||||||
// Percentiles specifies the percentiles that will be calculated for timing
|
// Percentiles specifies the percentiles that will be calculated for timing
|
||||||
// and histogram stats.
|
// and histogram stats.
|
||||||
Percentiles []int
|
Percentiles []internal.Number
|
||||||
PercentileLimit int
|
PercentileLimit int
|
||||||
|
|
||||||
DeleteGauges bool
|
DeleteGauges bool
|
||||||
|
@ -217,7 +217,7 @@ const sampleConfig = `
|
||||||
delete_timings = true
|
delete_timings = true
|
||||||
|
|
||||||
## Percentiles to calculate for timing & histogram stats
|
## Percentiles to calculate for timing & histogram stats
|
||||||
percentiles = [90]
|
percentiles = [50.0, 90.0, 99.0, 99.9, 99.95, 100.0]
|
||||||
|
|
||||||
## separator to use between elements of a statsd metric
|
## separator to use between elements of a statsd metric
|
||||||
metric_separator = "_"
|
metric_separator = "_"
|
||||||
|
@ -271,8 +271,8 @@ func (s *Statsd) Gather(acc telegraf.Accumulator) error {
|
||||||
fields[prefix+"lower"] = stats.Lower()
|
fields[prefix+"lower"] = stats.Lower()
|
||||||
fields[prefix+"count"] = stats.Count()
|
fields[prefix+"count"] = stats.Count()
|
||||||
for _, percentile := range s.Percentiles {
|
for _, percentile := range s.Percentiles {
|
||||||
name := fmt.Sprintf("%s%v_percentile", prefix, percentile)
|
name := fmt.Sprintf("%s%v_percentile", prefix, percentile.Value)
|
||||||
fields[name] = stats.Percentile(percentile)
|
fields[name] = stats.Percentile(percentile.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/influxdata/telegraf"
|
"github.com/influxdata/telegraf"
|
||||||
|
"github.com/influxdata/telegraf/internal"
|
||||||
"github.com/influxdata/telegraf/testutil"
|
"github.com/influxdata/telegraf/testutil"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -397,7 +398,7 @@ func TestParse_Counters(t *testing.T) {
|
||||||
// Tests low-level functionality of timings
|
// Tests low-level functionality of timings
|
||||||
func TestParse_Timings(t *testing.T) {
|
func TestParse_Timings(t *testing.T) {
|
||||||
s := NewTestStatsd()
|
s := NewTestStatsd()
|
||||||
s.Percentiles = []int{90}
|
s.Percentiles = []internal.Number{{Value: 90.0}}
|
||||||
acc := &testutil.Accumulator{}
|
acc := &testutil.Accumulator{}
|
||||||
|
|
||||||
// Test that counters work
|
// Test that counters work
|
||||||
|
@ -1181,7 +1182,7 @@ func TestParse_MeasurementsWithMultipleValues(t *testing.T) {
|
||||||
func TestParse_TimingsMultipleFieldsWithTemplate(t *testing.T) {
|
func TestParse_TimingsMultipleFieldsWithTemplate(t *testing.T) {
|
||||||
s := NewTestStatsd()
|
s := NewTestStatsd()
|
||||||
s.Templates = []string{"measurement.field"}
|
s.Templates = []string{"measurement.field"}
|
||||||
s.Percentiles = []int{90}
|
s.Percentiles = []internal.Number{{Value: 90.0}}
|
||||||
acc := &testutil.Accumulator{}
|
acc := &testutil.Accumulator{}
|
||||||
|
|
||||||
validLines := []string{
|
validLines := []string{
|
||||||
|
@ -1232,7 +1233,7 @@ func TestParse_TimingsMultipleFieldsWithTemplate(t *testing.T) {
|
||||||
func TestParse_TimingsMultipleFieldsWithoutTemplate(t *testing.T) {
|
func TestParse_TimingsMultipleFieldsWithoutTemplate(t *testing.T) {
|
||||||
s := NewTestStatsd()
|
s := NewTestStatsd()
|
||||||
s.Templates = []string{}
|
s.Templates = []string{}
|
||||||
s.Percentiles = []int{90}
|
s.Percentiles = []internal.Number{{Value: 90.0}}
|
||||||
acc := &testutil.Accumulator{}
|
acc := &testutil.Accumulator{}
|
||||||
|
|
||||||
validLines := []string{
|
validLines := []string{
|
||||||
|
|
Loading…
Reference in New Issue