| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package conditions
- import (
- "math"
- "sort"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/onecloud/pkg/apis/monitor"
- )
- type mathReducer struct {
- // Type is how the timeseries should be reduced.
- // Ex: avg, sum, max, min, count
- Type string
- Opt string
- Params []float64
- }
- func (s *mathReducer) GetParams() []float64 {
- return s.Params
- }
- func (s *mathReducer) GetType() monitor.ReducerType {
- return monitor.ReducerType(s.Type)
- }
- func (s *mathReducer) Reduce(series *monitor.TimeSeries) (*float64, []string) {
- if len(series.Points) == 0 {
- return nil, nil
- }
- value := float64(0)
- allNull := true
- valArr := make([]string, 0)
- switch s.Type {
- case "avg":
- validPointsCount := 0
- for _, point := range series.Points {
- if point.IsValids() {
- values := point.Values()
- tem, err := s.mathValue(values)
- if err != nil {
- return nil, valArr
- }
- value += tem
- validPointsCount++
- allNull = false
- }
- }
- if validPointsCount > 0 {
- value = value / float64(validPointsCount)
- }
- case "sum":
- for _, point := range series.Points {
- if point.IsValids() {
- values := point.Values()
- tem, err := s.mathValue(values)
- if err != nil {
- return nil, valArr
- }
- value += tem
- allNull = false
- }
- }
- case "min":
- value = math.MaxFloat64
- for _, point := range series.Points {
- if point.IsValids() {
- allNull = false
- values := point.Values()
- tem, err := s.mathValue(values)
- if err != nil {
- return nil, valArr
- }
- if value > tem {
- value = tem
- }
- }
- }
- case "max":
- value = -math.MaxFloat64
- for _, point := range series.Points {
- if point.IsValids() {
- allNull = false
- values := point.Values()
- tem, err := s.mathValue(values)
- if err != nil {
- return nil, valArr
- }
- if value < tem {
- value = tem
- }
- }
- }
- case "count":
- value = float64(len(series.Points))
- allNull = false
- case "last":
- points := series.Points
- for i := len(points) - 1; i >= 0; i-- {
- if points[i].IsValids() {
- values := points[i].Values()
- tem, err := s.mathValue(values)
- if err != nil {
- return nil, valArr
- }
- value = tem
- allNull = false
- break
- }
- }
- case "median":
- var values []float64
- for _, point := range series.Points {
- if point.IsValids() {
- allNull = false
- values := point.Values()
- tem, err := s.mathValue(values)
- if err != nil {
- return nil, valArr
- }
- values = append(values, tem)
- }
- }
- if len(values) >= 1 {
- sort.Float64s(values)
- length := len(values)
- if length%2 == 1 {
- value = values[(length-1)/2]
- } else {
- value = (values[(length/2)-1] + values[length/2]) / 2
- }
- }
- case "diff":
- allNull, value = calculateDiff(series, allNull, value, diff)
- case "delta":
- allNull, value = calculateDelta(series, allNull, value)
- case "percent_diff":
- allNull, value = calculateDiff(series, allNull, value, percentDiff)
- case "count_non_null":
- for _, v := range series.Points {
- if v.IsValids() {
- value++
- }
- }
- if value > 0 {
- allNull = false
- }
- }
- if allNull {
- return nil, valArr
- }
- return &value, valArr
- }
- func (reducer *mathReducer) mathValue(values []float64) (float64, error) {
- value := float64(0)
- switch reducer.Opt {
- case "/":
- if len(values) < 2 {
- return value, errors.Errorf("point values length is too short")
- }
- if values[1] == 0 {
- return 1, nil
- }
- return values[0] / values[1], nil
- }
- return value, errors.Errorf("the reducer operator:%s is ilegal", reducer.Opt)
- }
- func newMathReducer(cond *monitor.Condition) (*mathReducer, error) {
- return &mathReducer{
- Type: cond.Type,
- Opt: cond.Operators[0],
- Params: cond.Params,
- }, nil
- }
|