github.com/m3db/m3@v1.5.0/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() {}