diff --git a/cmd/collectors/restperf/restperf.go b/cmd/collectors/restperf/restperf.go index 29fad60d4..09cdba4b0 100644 --- a/cmd/collectors/restperf/restperf.go +++ b/cmd/collectors/restperf/restperf.go @@ -852,7 +852,7 @@ func (r *RestPerf) PollData() (map[string]*matrix.Matrix, error) { // calculate timestamp delta first since many counters require it for postprocessing. // Timestamp has "raw" property, so it isn't post-processed automatically - if _, err = timestamp.Delta(prevMat.GetMetric("timestamp"), prevMat, curMat, r.Logger); err != nil { + if _, err = curMat.Delta("timestamp", prevMat, r.Logger); err != nil { r.Logger.Error().Err(err).Msg("(timestamp) calculate delta:") } @@ -878,7 +878,7 @@ func (r *RestPerf) PollData() (map[string]*matrix.Matrix, error) { } // all other properties - first calculate delta - if skips, err = metric.Delta(prevMat.GetMetric(key), prevMat, curMat, r.Logger); err != nil { + if skips, err = curMat.Delta(key, prevMat, r.Logger); err != nil { r.Logger.Error().Err(err).Str("key", key).Msg("Calculate delta") continue } @@ -919,9 +919,9 @@ func (r *RestPerf) PollData() (map[string]*matrix.Matrix, error) { if property == "average" || property == "percent" { if strings.HasSuffix(metric.GetName(), "latency") { - skips, err = metric.DivideWithThreshold(base, r.perfProp.latencyIoReqd, r.Logger) + skips, err = curMat.DivideWithThreshold(key, counter.denominator, r.perfProp.latencyIoReqd, r.Logger) } else { - skips, err = metric.Divide(base, r.Logger) + skips, err = curMat.Divide(key, counter.denominator, r.Logger) } if err != nil { @@ -936,7 +936,7 @@ func (r *RestPerf) PollData() (map[string]*matrix.Matrix, error) { } if property == "percent" { - if skips, err = metric.MultiplyByScalar(100, r.Logger); err != nil { + if skips, err = curMat.MultiplyByScalar(key, 100, r.Logger); err != nil { r.Logger.Error().Err(err).Str("key", key).Msg("Multiply by scalar") } else { totalSkips += skips @@ -958,7 +958,7 @@ func (r *RestPerf) PollData() (map[string]*matrix.Matrix, error) { if counter != nil { property := counter.counterType if property == "rate" { - if skips, err = metric.Divide(timestamp, r.Logger); err != nil { + if skips, err = curMat.Divide(orderedKeys[i], "timestamp", r.Logger); err != nil { r.Logger.Error().Err(err). Int("i", i). Str("metric", metric.GetName()). diff --git a/cmd/collectors/zapiperf/zapiperf.go b/cmd/collectors/zapiperf/zapiperf.go index 1451ad7f9..0ce1621ad 100644 --- a/cmd/collectors/zapiperf/zapiperf.go +++ b/cmd/collectors/zapiperf/zapiperf.go @@ -571,7 +571,7 @@ func (z *ZapiPerf) PollData() (map[string]*matrix.Matrix, error) { // calculate timestamp delta first since many counters require it for postprocessing. // Timestamp has "raw" property, so it isn't post-processed automatically - if _, err = timestamp.Delta(prevMat.GetMetric("timestamp"), prevMat, curMat, z.Logger); err != nil { + if _, err = curMat.Delta("timestamp", prevMat, z.Logger); err != nil { z.Logger.Error().Err(err).Msg("(timestamp) calculate delta:") // @TODO terminate since other counters will be incorrect } @@ -590,7 +590,7 @@ func (z *ZapiPerf) PollData() (map[string]*matrix.Matrix, error) { } // all other properties - first calculate delta - if skips, err = metric.Delta(prevMat.GetMetric(key), prevMat, curMat, z.Logger); err != nil { + if skips, err = curMat.Delta(key, prevMat, z.Logger); err != nil { z.Logger.Error().Err(err).Str("key", key).Msg("Calculate delta") continue } @@ -631,9 +631,9 @@ func (z *ZapiPerf) PollData() (map[string]*matrix.Matrix, error) { if property == "average" || property == "percent" { if strings.HasSuffix(metric.GetName(), "latency") { - skips, err = metric.DivideWithThreshold(base, z.latencyIoReqd, z.Logger) + skips, err = curMat.DivideWithThreshold(key, metric.GetComment(), z.latencyIoReqd, z.Logger) } else { - skips, err = metric.Divide(base, z.Logger) + skips, err = curMat.Divide(key, metric.GetComment(), z.Logger) } if err != nil { @@ -647,7 +647,7 @@ func (z *ZapiPerf) PollData() (map[string]*matrix.Matrix, error) { } if property == "percent" { - if skips, err = metric.MultiplyByScalar(100, z.Logger); err != nil { + if skips, err = curMat.MultiplyByScalar(key, 100, z.Logger); err != nil { z.Logger.Error().Err(err).Str("key", key).Msg("Multiply by scalar") } else { totalSkips += skips @@ -663,7 +663,7 @@ func (z *ZapiPerf) PollData() (map[string]*matrix.Matrix, error) { // calculate rates (which we deferred to calculate averages/percents first) for i, metric := range orderedMetrics { if metric.GetProperty() == "rate" { - if skips, err = metric.Divide(timestamp, z.Logger); err != nil { + if skips, err = curMat.Divide(orderedKeys[i], "timestamp", z.Logger); err != nil { z.Logger.Error().Err(err). Int("i", i). Str("key", orderedKeys[i]). diff --git a/pkg/matrix/matrix.go b/pkg/matrix/matrix.go index f5e0c426e..eadf56fa7 100644 --- a/pkg/matrix/matrix.go +++ b/pkg/matrix/matrix.go @@ -14,6 +14,7 @@ import ( "fmt" "github.com/netapp/harvest/v2/pkg/dict" "github.com/netapp/harvest/v2/pkg/errs" + "github.com/netapp/harvest/v2/pkg/logging" "github.com/netapp/harvest/v2/pkg/tree/node" "strings" ) @@ -303,3 +304,169 @@ func CreateMetric(key string, data *Matrix) error { } return nil } + +// Delta vector arithmetics +func (m *Matrix) Delta(metricKey string, prevMat *Matrix, logger *logging.Logger) (int, error) { + var skips int + prevMetric := prevMat.GetMetric(metricKey) + curMetric := m.GetMetric(metricKey) + prevRaw := prevMetric.values + prevRecord := prevMetric.GetRecords() + for key, currInstance := range m.GetInstances() { + // check if this instance key exists in previous matrix + prevInstance := prevMat.GetInstance(key) + currIndex := currInstance.index + curRaw := curMetric.values[currIndex] + if prevInstance != nil { + prevIndex := prevInstance.index + if curMetric.record[currIndex] && prevRecord[prevIndex] { + curMetric.values[currIndex] -= prevRaw[prevIndex] + // Sometimes ONTAP sends spurious zeroes or values less than the previous poll. + // Detect and don't publish negative deltas or the subsequent poll will show a large spike. + isInvalidZero := (curRaw == 0 || prevRaw[prevIndex] == 0) && curMetric.values[prevIndex] != 0 + isNegative := curMetric.values[currIndex] < 0 + if isInvalidZero || isNegative { + curMetric.record[currIndex] = false + skips++ + logger.Trace(). + Str("metric", curMetric.GetName()). + Float64("currentRaw", curRaw). + Float64("previousRaw", prevRaw[prevIndex]). + Str("instKey", key). + Msg("Negative cooked value") + } + } else { + curMetric.record[currIndex] = false + skips++ + logger.Trace(). + Str("metric", curMetric.GetName()). + Float64("currentRaw", curRaw). + Float64("previousRaw", prevRaw[prevIndex]). + Str("instKey", key). + Msg("Delta calculation skipped") + } + } else { + curMetric.record[currIndex] = false + skips++ + logger.Trace(). + Str("metric", curMetric.GetName()). + Float64("currentRaw", curRaw). + Str("instKey", key). + Msg("New instance added") + } + } + return skips, nil +} + +func (m *Matrix) Divide(metricKey string, baseKey string, logger *logging.Logger) (int, error) { + var skips int + metric := m.GetMetric(metricKey) + base := m.GetMetric(baseKey) + sValues := base.values + sRecord := base.GetRecords() + if len(metric.values) != len(sValues) { + return 0, errs.New(ErrUnequalVectors, fmt.Sprintf("numerator=%d, denominator=%d", len(metric.values), len(sValues))) + } + for i := 0; i < len(metric.values); i++ { + if metric.record[i] && sRecord[i] { + if sValues[i] != 0 { + // Don't pass along the value if the numerator or denominator is < 0 + // A denominator of zero is fine + if metric.values[i] < 0 || sValues[i] < 0 { + metric.record[i] = false + skips++ + logger.Trace(). + Str("metric", metric.GetName()). + Float64("numerator", metric.values[i]). + Float64("denominator", sValues[i]). + Msg("Divide calculation skipped") + } + metric.values[i] /= sValues[i] + } else { + metric.values[i] = 0 + } + } else { + metric.record[i] = false + skips++ + logger.Trace(). + Str("metric", metric.GetName()). + Float64("numerator", metric.values[i]). + Float64("denominator", sValues[i]). + Msg("Divide calculation skipped") + } + } + return skips, nil +} + +func (m *Matrix) DivideWithThreshold(metricKey string, baseKey string, threshold int, logger *logging.Logger) (int, error) { + var skips int + x := float64(threshold) + metric := m.GetMetric(metricKey) + base := m.GetMetric(baseKey) + sValues := base.values + sRecord := base.GetRecords() + if len(metric.values) != len(sValues) { + return 0, errs.New(ErrUnequalVectors, fmt.Sprintf("numerator=%d, denominator=%d", len(metric.values), len(sValues))) + } + for i := 0; i < len(metric.values); i++ { + v := metric.values[i] + // Don't pass along the value if the numerator or denominator is < 0 + // It is important to check sValues[i] < 0 and allow a zero so pass=true and m.values[i] remains unchanged + if metric.values[i] < 0 || sValues[i] < 0 { + metric.record[i] = false + skips++ + logger.Trace(). + Str("metric", metric.GetName()). + Float64("numerator", v). + Float64("denominator", sValues[i]). + Msg("Negative values") + return skips, nil + } + if metric.record[i] && sRecord[i] { + if sValues[i] >= x { + metric.values[i] /= sValues[i] + } else { + metric.values[i] = 0 + } + } else { + metric.record[i] = false + skips++ + logger.Trace(). + Str("metric", metric.GetName()). + Float64("numerator", metric.values[i]). + Float64("denominator", sValues[i]). + Msg("Divide threshold calculation skipped") + } + } + return skips, nil +} + +func (m *Matrix) MultiplyByScalar(metricKey string, s uint, logger *logging.Logger) (int, error) { + var skips int + x := float64(s) + metric := m.GetMetric(metricKey) + for i := 0; i < len(metric.values); i++ { + if metric.record[i] { + // if current is <= 0 + if metric.values[i] < 0 { + metric.record[i] = false + skips++ + logger.Trace(). + Str("metric", metric.GetName()). + Float64("currentRaw", metric.values[i]). + Uint("scalar", s). + Msg("Negative value") + } + metric.values[i] *= x + } else { + metric.record[i] = false + skips++ + logger.Trace(). + Str("metric", metric.GetName()). + Float64("currentRaw", metric.values[i]). + Uint("scalar", s). + Msg("Scalar multiplication skipped") + } + } + return skips, nil +} diff --git a/pkg/matrix/metric.go b/pkg/matrix/metric.go index c0d267c45..ed548d99c 100644 --- a/pkg/matrix/metric.go +++ b/pkg/matrix/metric.go @@ -14,8 +14,6 @@ package matrix import ( "fmt" "github.com/netapp/harvest/v2/pkg/dict" - "github.com/netapp/harvest/v2/pkg/errs" - "github.com/netapp/harvest/v2/pkg/logging" "strconv" ) @@ -288,165 +286,6 @@ func (m *Metric) GetValueBytes(i *Instance) ([]byte, bool) { return []byte(s), ok } -// Delta vector arithmetics -func (m *Metric) Delta(prevMetric *Metric, prevMat *Matrix, curMat *Matrix, logger *logging.Logger) (int, error) { - var skips int - prevRaw := prevMetric.values - prevRecord := prevMetric.GetRecords() - for key, currInstance := range curMat.GetInstances() { - // check if this instance key exists in previous matrix - prevInstance := prevMat.GetInstance(key) - currIndex := currInstance.index - curRaw := m.values[currIndex] - if prevInstance != nil { - prevIndex := prevInstance.index - if m.record[currIndex] && prevRecord[prevIndex] { - m.values[currIndex] -= prevRaw[prevIndex] - // Sometimes ONTAP sends spurious zeroes or values less than the previous poll. - // Detect and don't publish negative deltas or the subsequent poll will show a large spike. - isInvalidZero := (curRaw == 0 || prevRaw[prevIndex] == 0) && m.values[prevIndex] != 0 - isNegative := m.values[currIndex] < 0 - if isInvalidZero || isNegative { - m.record[currIndex] = false - skips++ - logger.Trace(). - Str("metric", m.GetName()). - Float64("currentRaw", curRaw). - Float64("previousRaw", prevRaw[prevIndex]). - Str("instKey", key). - Msg("Negative cooked value") - } - } else { - m.record[currIndex] = false - skips++ - logger.Trace(). - Str("metric", m.GetName()). - Float64("currentRaw", curRaw). - Float64("previousRaw", prevRaw[prevIndex]). - Str("instKey", key). - Msg("Delta calculation skipped") - } - } else { - m.record[currIndex] = false - skips++ - logger.Trace(). - Str("metric", m.GetName()). - Float64("currentRaw", curRaw). - Str("instKey", key). - Msg("New instance added") - } - } - return skips, nil -} - -func (m *Metric) Divide(s *Metric, logger *logging.Logger) (int, error) { - var skips int - sValues := s.values - sRecord := s.GetRecords() - if len(m.values) != len(sValues) { - return 0, errs.New(ErrUnequalVectors, fmt.Sprintf("numerator=%d, denominator=%d", len(m.values), len(sValues))) - } - for i := 0; i < len(m.values); i++ { - if m.record[i] && sRecord[i] { - if sValues[i] != 0 { - // Don't pass along the value if the numerator or denominator is < 0 - // A denominator of zero is fine - if m.values[i] < 0 || sValues[i] < 0 { - m.record[i] = false - skips++ - logger.Trace(). - Str("metric", m.GetName()). - Float64("numerator", m.values[i]). - Float64("denominator", sValues[i]). - Msg("Divide calculation skipped") - } - m.values[i] /= sValues[i] - } else { - m.values[i] = 0 - } - } else { - m.record[i] = false - skips++ - logger.Trace(). - Str("metric", m.GetName()). - Float64("numerator", m.values[i]). - Float64("denominator", sValues[i]). - Msg("Divide calculation skipped") - } - } - return skips, nil -} - -func (m *Metric) DivideWithThreshold(s *Metric, t int, logger *logging.Logger) (int, error) { - var skips int - x := float64(t) - sValues := s.values - sRecord := s.GetRecords() - if len(m.values) != len(sValues) { - return 0, errs.New(ErrUnequalVectors, fmt.Sprintf("numerator=%d, denominator=%d", len(m.values), len(sValues))) - } - for i := 0; i < len(m.values); i++ { - v := m.values[i] - // Don't pass along the value if the numerator or denominator is < 0 - // It's important to check sValues[i] < 0 and allow a zero so pass=true and m.values[i] remains unchanged - if m.values[i] < 0 || sValues[i] < 0 { - m.record[i] = false - skips++ - logger.Trace(). - Str("metric", m.GetName()). - Float64("numerator", v). - Float64("denominator", sValues[i]). - Msg("Negative values") - return skips, nil - } - if m.record[i] && sRecord[i] { - if sValues[i] >= x { - m.values[i] /= sValues[i] - } else { - m.values[i] = 0 - } - } else { - m.record[i] = false - skips++ - logger.Trace(). - Str("metric", m.GetName()). - Float64("numerator", m.values[i]). - Float64("denominator", sValues[i]). - Msg("Divide threshold calculation skipped") - } - } - return skips, nil -} - -func (m *Metric) MultiplyByScalar(s uint, logger *logging.Logger) (int, error) { - var skips int - x := float64(s) - for i := 0; i < len(m.values); i++ { - if m.record[i] { - // if current is <= 0 - if m.values[i] < 0 { - m.record[i] = false - skips++ - logger.Trace(). - Str("metric", m.GetName()). - Float64("currentRaw", m.values[i]). - Uint("scalar", s). - Msg("Negative value") - } - m.values[i] *= x - } else { - m.record[i] = false - skips++ - logger.Trace(). - Str("metric", m.GetName()). - Float64("currentRaw", m.values[i]). - Uint("scalar", s). - Msg("Scalar multiplication skipped") - } - } - return skips, nil -} - func (m *Metric) Print() { for i := range m.values { if m.record[i] { diff --git a/pkg/matrix/metric_test.go b/pkg/matrix/metric_test.go index 4042ec853..32dcc8e1e 100644 --- a/pkg/matrix/metric_test.go +++ b/pkg/matrix/metric_test.go @@ -81,14 +81,13 @@ func setupMatrixAdv(previousRaw []float64, currentRaw []float64) (*Matrix, *Matr } type test struct { - name string - curRaw float64 - prevRaw float64 - cooked []float64 - threshold int - scalar uint - skips int - record []bool + name string + curRaw float64 + prevRaw float64 + cooked []float64 + scalar uint + skips int + record []bool } type testAdv struct { @@ -116,7 +115,7 @@ func TestMetricFloat64_Delta(t *testing.T) { for _, tt := range tests2 { t.Run(tt.name, func(t *testing.T) { previous, current := setupMatrix(tt.prevRaw, tt.curRaw, addInstance) - skips, err := current.GetMetric("speed").Delta(previous.GetMetric("speed"), previous, current, logging.Get()) + skips, err := current.Delta("speed", previous, logging.Get()) matrixTest(t, tt, current, skips, err) }) } @@ -132,7 +131,7 @@ func TestMetricFloat64_Delta(t *testing.T) { for _, tt := range tests3 { t.Run(tt.name, func(t *testing.T) { previous, current := setupMatrix(tt.prevRaw, tt.curRaw, addDeleteInstance) - skips, err := current.GetMetric("speed").Delta(previous.GetMetric("speed"), previous, current, logging.Get()) + skips, err := current.Delta("speed", previous, logging.Get()) matrixTest(t, tt, current, skips, err) }) } @@ -150,90 +149,60 @@ func testDelta(t *testing.T, op matrixOp) { for _, tt := range tests { t.Run(tt.name+"_"+string(op), func(t *testing.T) { previous, current := setupMatrix(tt.prevRaw, tt.curRaw, op) - skips, err := current.GetMetric("speed").Delta(previous.GetMetric("speed"), previous, current, logging.Get()) + skips, err := current.Delta("speed", previous, logging.Get()) matrixTest(t, tt, current, skips, err) }) } } func TestMetricFloat64_Divide(t *testing.T) { - tests := []test{ - {prevRaw: 20, curRaw: 10, cooked: []float64{2}, skips: 0, record: []bool{true}, name: "normal"}, - {prevRaw: -20, curRaw: 10, cooked: []float64{-2}, skips: 1, record: []bool{false}, name: "bug negative num"}, - {prevRaw: 20, curRaw: -10, cooked: []float64{-2}, skips: 1, record: []bool{false}, name: "bug negative den"}, - {prevRaw: -20, curRaw: -10, cooked: []float64{2}, skips: 1, record: []bool{false}, name: "bug negative both"}, - {prevRaw: 20, curRaw: 0, cooked: []float64{0}, skips: 0, record: []bool{true}, name: "allow zero den"}, - {prevRaw: 0, curRaw: 0, cooked: []float64{0}, skips: 0, record: []bool{true}, name: "allow zero both"}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - numerator, denominator := setupMatrix(tt.prevRaw, tt.curRaw, sameInstance) - skips, err := numerator.GetMetric("speed").Divide(denominator.GetMetric("speed"), logging.Get()) - matrixTest(t, tt, numerator, skips, err) - }) - } - testsAdv := []testAdv{ {prevRaw: []float64{10, 5}, curRaw: []float64{20, 10}, cooked: []float64{2}, skips: 0, record: []bool{true}, name: "normal"}, - {prevRaw: []float64{10, 5}, curRaw: []float64{20, 0}, cooked: []float64{10}, skips: 1, record: []bool{false}, name: "denominator record false"}, - {prevRaw: []float64{10, 5}, curRaw: []float64{5, 10}, cooked: []float64{-5}, skips: 1, record: []bool{false}, name: "numerator record false"}, - {prevRaw: []float64{10, 5}, curRaw: []float64{20, 0}, cooked: []float64{10}, skips: 1, record: []bool{false}, name: "numerator denominator record false"}, + {prevRaw: []float64{10, 5}, curRaw: []float64{20, 5}, cooked: []float64{0}, skips: 0, record: []bool{true}, name: "allow zero den"}, + {prevRaw: []float64{10, 5}, curRaw: []float64{10, 5}, cooked: []float64{0}, skips: 0, record: []bool{true}, name: "allow zero both"}, + {prevRaw: []float64{10, 5}, curRaw: []float64{20, 0}, cooked: []float64{10}, skips: 1, record: []bool{false}, name: "bug negative den"}, + {prevRaw: []float64{10, 5}, curRaw: []float64{5, 10}, cooked: []float64{-5}, skips: 1, record: []bool{false}, name: "bug negative num"}, + {prevRaw: []float64{20, 5}, curRaw: []float64{10, 0}, cooked: []float64{-10}, skips: 1, record: []bool{false}, name: "bug negative both"}, } for _, tt := range testsAdv { t.Run(tt.name, func(t *testing.T) { prevMat, curMat := setupMatrixAdv(tt.prevRaw, tt.curRaw) for k := range curMat.GetMetrics() { - _, err := curMat.GetMetric(k).Delta(prevMat.GetMetric(k), prevMat, curMat, logging.Get()) + _, err := curMat.Delta(k, prevMat, logging.Get()) if err != nil { t.Error("unexpected error", err) return } } - skips, err := curMat.GetMetric("average_latency").Divide(curMat.GetMetric("total_ops"), logging.Get()) + skips, err := curMat.Divide("average_latency", "total_ops", logging.Get()) matrixTestAdv(t, tt, curMat, skips, err) }) } } func TestMetricFloat64_DivideWithThreshold(t *testing.T) { - tests := []test{ - {prevRaw: 20, curRaw: 10, threshold: 5, cooked: []float64{2}, skips: 0, record: []bool{true}, name: "normal"}, - {prevRaw: 20, curRaw: 10, threshold: 15, cooked: []float64{0}, skips: 0, record: []bool{true}, name: "normal < threshold"}, - {prevRaw: 20, curRaw: -10, threshold: 5, cooked: []float64{20}, skips: 1, record: []bool{false}, name: "bug negative den"}, - {prevRaw: -20, curRaw: -10, threshold: 5, cooked: []float64{-20}, skips: 1, record: []bool{false}, name: "bug negative both"}, - {prevRaw: 20, curRaw: 0, threshold: 0, cooked: []float64{math.Inf(1)}, skips: 0, record: []bool{true}, name: "allow no threshold"}, - {prevRaw: 0, curRaw: 0, threshold: 5, cooked: []float64{0}, skips: 0, record: []bool{true}, name: "allow zero both"}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - numerator, denominator := setupMatrix(tt.prevRaw, tt.curRaw, sameInstance) - skips, err := numerator.GetMetric("speed"). - DivideWithThreshold(denominator.GetMetric("speed"), tt.threshold, logging.Get()) - matrixTest(t, tt, numerator, skips, err) - }) - } - testsAdv := []testAdv{ {prevRaw: []float64{10, 5}, curRaw: []float64{20, 10}, threshold: 1, cooked: []float64{2}, skips: 0, record: []bool{true}, name: "normal"}, - {prevRaw: []float64{10, 5}, curRaw: []float64{20, 0}, threshold: 1, cooked: []float64{10}, skips: 1, record: []bool{false}, name: "denominator record false"}, - {prevRaw: []float64{10, 5}, curRaw: []float64{5, 10}, threshold: 1, cooked: []float64{-5}, skips: 1, record: []bool{false}, name: "numerator record false"}, - {prevRaw: []float64{10, 5}, curRaw: []float64{20, 0}, threshold: 1, cooked: []float64{10}, skips: 1, record: []bool{false}, name: "numerator denominator record false"}, + {prevRaw: []float64{10, 5}, curRaw: []float64{20, 10}, threshold: 15, cooked: []float64{0}, skips: 0, record: []bool{true}, name: "normal < threshold"}, + {prevRaw: []float64{10, 5}, curRaw: []float64{20, 0}, threshold: 1, cooked: []float64{10}, skips: 1, record: []bool{false}, name: "bug negative den"}, + {prevRaw: []float64{10, 5}, curRaw: []float64{5, 10}, threshold: 1, cooked: []float64{-5}, skips: 1, record: []bool{false}, name: "bug negative num"}, + {prevRaw: []float64{20, 5}, curRaw: []float64{10, 0}, threshold: 1, cooked: []float64{-10}, skips: 1, record: []bool{false}, name: "bug negative both"}, + {prevRaw: []float64{10, 10}, curRaw: []float64{20, 10}, threshold: 0, cooked: []float64{math.Inf(1)}, skips: 0, record: []bool{true}, name: "allow no threshold"}, + {prevRaw: []float64{10, 5}, curRaw: []float64{10, 5}, threshold: 5, cooked: []float64{0}, skips: 0, record: []bool{true}, name: "allow zero both"}, } for _, tt := range testsAdv { t.Run(tt.name, func(t *testing.T) { prevMat, curMat := setupMatrixAdv(tt.prevRaw, tt.curRaw) for k := range curMat.GetMetrics() { - _, err := curMat.GetMetric(k).Delta(prevMat.GetMetric(k), prevMat, curMat, logging.Get()) + _, err := curMat.Delta(k, prevMat, logging.Get()) if err != nil { t.Error("unexpected error", err) return } } - skips, err := curMat.GetMetric("average_latency").DivideWithThreshold(curMat.GetMetric("total_ops"), tt.threshold, logging.Get()) + skips, err := curMat.DivideWithThreshold("average_latency", "total_ops", tt.threshold, logging.Get()) matrixTestAdv(t, tt, curMat, skips, err) }) } @@ -248,7 +217,7 @@ func TestMetricFloat64_MultiplyByScalar(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { _, current := setupMatrix(tt.prevRaw, tt.curRaw, sameInstance) - skips, err := current.GetMetric("speed").MultiplyByScalar(tt.scalar, logging.Get()) + skips, err := current.MultiplyByScalar("speed", tt.scalar, logging.Get()) matrixTest(t, tt, current, skips, err) }) }