github.com/aristanetworks/goarista@v0.0.0-20240514173732-cca2755bbd44/monitor/stats/tracker.go (about)

     1  /*
     2   *
     3   * Copyright 2017 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  // Copyright (c) 2015 Arista Networks, Inc.
    20  // Use of this source code is governed by the Apache License 2.0
    21  // that can be found in the COPYING file.
    22  
    23  package stats
    24  
    25  import (
    26  	"math"
    27  	"sync"
    28  	"time"
    29  )
    30  
    31  // Tracker is a min/max value tracker that keeps track of its min/max values
    32  // over a given period of time, and with a given resolution. The initial min
    33  // and max values are math.MaxInt64 and math.MinInt64 respectively.
    34  type Tracker struct {
    35  	mu           sync.RWMutex
    36  	min, max     int64 // All time min/max.
    37  	minTS, maxTS [3]*timeseries
    38  	lastUpdate   time.Time
    39  }
    40  
    41  // newTracker returns a new Tracker.
    42  func newTracker() *Tracker {
    43  	now := TimeNow()
    44  	t := &Tracker{}
    45  	t.minTS[hour] = newTimeSeries(now, time.Hour, time.Minute)
    46  	t.minTS[tenminutes] = newTimeSeries(now, 10*time.Minute, 10*time.Second)
    47  	t.minTS[minute] = newTimeSeries(now, time.Minute, time.Second)
    48  	t.maxTS[hour] = newTimeSeries(now, time.Hour, time.Minute)
    49  	t.maxTS[tenminutes] = newTimeSeries(now, 10*time.Minute, 10*time.Second)
    50  	t.maxTS[minute] = newTimeSeries(now, time.Minute, time.Second)
    51  	t.init()
    52  	return t
    53  }
    54  
    55  func (t *Tracker) init() {
    56  	t.min = math.MaxInt64
    57  	t.max = math.MinInt64
    58  	for _, ts := range t.minTS {
    59  		ts.set(math.MaxInt64)
    60  	}
    61  	for _, ts := range t.maxTS {
    62  		ts.set(math.MinInt64)
    63  	}
    64  }
    65  
    66  func (t *Tracker) advance() time.Time {
    67  	now := TimeNow()
    68  	for _, ts := range t.minTS {
    69  		ts.advanceTimeWithFill(now, math.MaxInt64)
    70  	}
    71  	for _, ts := range t.maxTS {
    72  		ts.advanceTimeWithFill(now, math.MinInt64)
    73  	}
    74  	return now
    75  }
    76  
    77  // LastUpdate returns the last update time of the range.
    78  func (t *Tracker) LastUpdate() time.Time {
    79  	t.mu.RLock()
    80  	defer t.mu.RUnlock()
    81  	return t.lastUpdate
    82  }
    83  
    84  // Push adds a new value if it is a new minimum or maximum.
    85  func (t *Tracker) Push(value int64) {
    86  	t.mu.Lock()
    87  	defer t.mu.Unlock()
    88  	t.lastUpdate = t.advance()
    89  	if t.min > value {
    90  		t.min = value
    91  	}
    92  	if t.max < value {
    93  		t.max = value
    94  	}
    95  	for _, ts := range t.minTS {
    96  		if ts.headValue() > value {
    97  			ts.set(value)
    98  		}
    99  	}
   100  	for _, ts := range t.maxTS {
   101  		if ts.headValue() < value {
   102  			ts.set(value)
   103  		}
   104  	}
   105  }
   106  
   107  // Min returns the minimum value of the tracker
   108  func (t *Tracker) Min() int64 {
   109  	t.mu.RLock()
   110  	defer t.mu.RUnlock()
   111  	return t.min
   112  }
   113  
   114  // Max returns the maximum value of the tracker.
   115  func (t *Tracker) Max() int64 {
   116  	t.mu.RLock()
   117  	defer t.mu.RUnlock()
   118  	return t.max
   119  }
   120  
   121  // Min1h returns the minimum value for the last hour.
   122  func (t *Tracker) Min1h() int64 {
   123  	t.mu.Lock()
   124  	defer t.mu.Unlock()
   125  	t.advance()
   126  	return t.minTS[hour].min()
   127  }
   128  
   129  // Max1h returns the maximum value for the last hour.
   130  func (t *Tracker) Max1h() int64 {
   131  	t.mu.Lock()
   132  	defer t.mu.Unlock()
   133  	t.advance()
   134  	return t.maxTS[hour].max()
   135  }
   136  
   137  // Min10m returns the minimum value for the last 10 minutes.
   138  func (t *Tracker) Min10m() int64 {
   139  	t.mu.Lock()
   140  	defer t.mu.Unlock()
   141  	t.advance()
   142  	return t.minTS[tenminutes].min()
   143  }
   144  
   145  // Max10m returns the maximum value for the last 10 minutes.
   146  func (t *Tracker) Max10m() int64 {
   147  	t.mu.Lock()
   148  	defer t.mu.Unlock()
   149  	t.advance()
   150  	return t.maxTS[tenminutes].max()
   151  }
   152  
   153  // Min1m returns the minimum value for the last 1 minute.
   154  func (t *Tracker) Min1m() int64 {
   155  	t.mu.Lock()
   156  	defer t.mu.Unlock()
   157  	t.advance()
   158  	return t.minTS[minute].min()
   159  }
   160  
   161  // Max1m returns the maximum value for the last 1 minute.
   162  func (t *Tracker) Max1m() int64 {
   163  	t.mu.Lock()
   164  	defer t.mu.Unlock()
   165  	t.advance()
   166  	return t.maxTS[minute].max()
   167  }
   168  
   169  // Reset resets the range to an empty state.
   170  func (t *Tracker) Reset() {
   171  	t.mu.Lock()
   172  	defer t.mu.Unlock()
   173  	now := TimeNow()
   174  	for _, ts := range t.minTS {
   175  		ts.reset(now)
   176  	}
   177  	for _, ts := range t.maxTS {
   178  		ts.reset(now)
   179  	}
   180  	t.init()
   181  }