github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/aggregator/aggregation/gauge.go (about) 1 // Copyright (c) 2016 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package aggregation 22 23 import ( 24 "math" 25 "time" 26 27 "github.com/m3db/m3/src/metrics/aggregation" 28 ) 29 30 // Gauge aggregates gauge values. 31 type Gauge struct { 32 Options 33 34 lastAt time.Time 35 annotation []byte 36 sum float64 37 sumSq float64 38 count int64 39 max float64 40 min float64 41 last float64 42 } 43 44 // NewGauge creates a new gauge. 45 func NewGauge(opts Options) Gauge { 46 return Gauge{ 47 Options: opts, 48 max: math.NaN(), 49 min: math.NaN(), 50 } 51 } 52 53 // Update updates the gauge value. 54 func (g *Gauge) Update(timestamp time.Time, value float64, annotation []byte) { 55 g.annotation = MaybeReplaceAnnotation(g.annotation, annotation) 56 g.updateTotals(timestamp, value) 57 } 58 59 // UpdatePrevious removes the prevValue from the aggregation and updates with the new value. 60 func (g *Gauge) UpdatePrevious(timestamp time.Time, value float64, prevValue float64) { 61 // remove the prevValue from the totals. 62 if !math.IsNaN(prevValue) { 63 g.sum -= prevValue 64 if g.HasExpensiveAggregations { 65 g.sumSq -= prevValue * prevValue 66 } 67 } 68 g.count-- 69 // add the new value to the totals. 70 g.updateTotals(timestamp, value) 71 } 72 73 // update the set of aggregated values that are shared between Update and UpdatePrevious. 74 func (g *Gauge) updateTotals(timestamp time.Time, value float64) { 75 if g.lastAt.IsZero() || timestamp.After(g.lastAt) { 76 // NB(r): Only set the last value if this value arrives 77 // after the wall clock timestamp of previous values, not 78 // the arrival time (i.e. order received). 79 g.lastAt = timestamp 80 g.last = value 81 } else { 82 g.Options.Metrics.Gauge.IncValuesOutOfOrder() 83 } 84 85 g.count++ 86 87 if math.IsNaN(value) { 88 return 89 } 90 91 g.sum += value 92 if math.IsNaN(g.max) || g.max < value { 93 g.max = value 94 } 95 96 if math.IsNaN(g.min) || g.min > value { 97 g.min = value 98 } 99 100 if g.HasExpensiveAggregations { 101 g.sumSq += value * value 102 } 103 } 104 105 // LastAt returns the time of the last value received. 106 func (g *Gauge) LastAt() time.Time { return g.lastAt } 107 108 // Last returns the last value received. 109 func (g *Gauge) Last() float64 { return g.last } 110 111 // Count returns the number of values received. 112 func (g *Gauge) Count() int64 { return g.count } 113 114 // Sum returns the sum of gauge values. 115 func (g *Gauge) Sum() float64 { return g.sum } 116 117 // SumSq returns the squared sum of gauge values. 118 func (g *Gauge) SumSq() float64 { return g.sumSq } 119 120 // Mean returns the mean gauge value. 121 func (g *Gauge) Mean() float64 { 122 if g.count == 0 { 123 return 0.0 124 } 125 return g.sum / float64(g.count) 126 } 127 128 // Stdev returns the standard deviation gauge value. 129 func (g *Gauge) Stdev() float64 { 130 return stdev(g.count, g.sumSq, g.sum) 131 } 132 133 // Min returns the minimum gauge value. 134 func (g *Gauge) Min() float64 { 135 return g.min 136 } 137 138 // Max returns the maximum gauge value. 139 func (g *Gauge) Max() float64 { 140 return g.max 141 } 142 143 // ValueOf returns the value for the aggregation type. 144 func (g *Gauge) ValueOf(aggType aggregation.Type) float64 { 145 switch aggType { 146 case aggregation.Last: 147 return g.Last() 148 case aggregation.Min: 149 return g.Min() 150 case aggregation.Max: 151 return g.Max() 152 case aggregation.Mean: 153 return g.Mean() 154 case aggregation.Count: 155 return float64(g.Count()) 156 case aggregation.Sum: 157 return g.Sum() 158 case aggregation.SumSq: 159 return g.SumSq() 160 case aggregation.Stdev: 161 return g.Stdev() 162 default: 163 return 0 164 } 165 } 166 167 // Annotation returns the annotation associated with the gauge. 168 func (g *Gauge) Annotation() []byte { 169 return g.annotation 170 } 171 172 // Close closes the gauge. 173 func (g *Gauge) Close() {}