github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/providers/agent/mcorpc/aggregate/average.go (about) 1 // Copyright (c) 2020-2022, R.I. Pienaar and the Choria Project contributors 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 package aggregate 6 7 import ( 8 "encoding/json" 9 "fmt" 10 "strconv" 11 "sync" 12 ) 13 14 // AverageAggregator averages seen values 15 type AverageAggregator struct { 16 sum float64 17 count int 18 args []any 19 format string 20 21 sync.Mutex 22 } 23 24 // NewAverageAggregator creates a new AverageAggregator with the specific options supplied 25 func NewAverageAggregator(args []any) (*AverageAggregator, error) { 26 agg := &AverageAggregator{ 27 args: args, 28 format: parseFormatFromArgs(args), 29 } 30 31 return agg, nil 32 } 33 34 // Type is the type of Aggregator 35 func (a *AverageAggregator) Type() string { 36 return "average" 37 } 38 39 // ProcessValue processes and tracks the specific value 40 func (a *AverageAggregator) ProcessValue(v any) error { 41 a.Lock() 42 defer a.Unlock() 43 44 if a.processInt(v) { 45 return nil 46 } 47 48 if a.processInt64(v) { 49 return nil 50 } 51 52 if a.processFloat(v) { 53 return nil 54 } 55 56 if a.processString(v) { 57 return nil 58 } 59 60 return fmt.Errorf("unsupported data type for average aggregator") 61 } 62 63 // ResultJSON return the results in JSON format preserving types 64 func (a *AverageAggregator) ResultJSON() ([]byte, error) { 65 a.Lock() 66 defer a.Unlock() 67 68 avg := a.sum / float64(a.count) 69 70 return json.Marshal(map[string]float64{ 71 "average": avg, 72 }) 73 } 74 75 // ResultStrings returns a map of results in string format 76 func (a *AverageAggregator) ResultStrings() (map[string]string, error) { 77 a.Lock() 78 defer a.Unlock() 79 80 avg := a.sum / float64(a.count) 81 82 return map[string]string{"Average": fmt.Sprintf("%f", avg)}, nil 83 } 84 85 // ResultFormattedStrings return the results in a formatted way, if no format is given a calculated value is used 86 func (a *AverageAggregator) ResultFormattedStrings(format string) ([]string, error) { 87 a.Lock() 88 defer a.Unlock() 89 90 avg := a.sum / float64(a.count) 91 92 if format == "" { 93 if a.format != "" { 94 format = a.format 95 } else { 96 format = "Average: %.3f" 97 } 98 } 99 100 return []string{fmt.Sprintf(format, avg)}, nil 101 } 102 103 func (a *AverageAggregator) processString(v any) bool { 104 s, ok := v.(string) 105 if !ok { 106 return false 107 } 108 109 f, err := strconv.ParseFloat(s, 64) 110 if err != nil { 111 return false 112 } 113 114 a.sum = a.sum + f 115 a.count++ 116 117 return true 118 } 119 120 func (a *AverageAggregator) processFloat(v any) bool { 121 f, ok := v.(float64) 122 if !ok { 123 return false 124 } 125 126 a.sum = a.sum + f 127 a.count++ 128 129 return true 130 } 131 132 func (a *AverageAggregator) processInt64(v any) bool { 133 i, ok := v.(int64) 134 if !ok { 135 return false 136 } 137 138 a.sum = a.sum + float64(i) 139 a.count++ 140 141 return true 142 } 143 144 func (a *AverageAggregator) processInt(v any) bool { 145 i, ok := v.(int) 146 if !ok { 147 return false 148 } 149 150 a.sum = a.sum + float64(i) 151 a.count++ 152 153 return true 154 }