1package main
2
3import (
4 "fmt"
5 "time"
6)
7
8
9
10
11func calculateDynamicRate(metricData []float64, timestamps []time.Time, maxWindow time.Duration, minDataPoints int) (float64, error) {
12 if len(metricData) == 0 || len(timestamps) == 0 || len(metricData) != len(timestamps) {
13 return 0, fmt.Errorf("invalid input: metricData or timestamps are empty or mismatched lengths")
14 }
15
16
17
18 var optimalWindow time.Duration
19 if len(metricData) < minDataPoints {
20
21 return 0, fmt.Errorf("insufficient data points (%d) for minimum required (%d)", len(metricData), minDataPoints)
22 }
23
24
25 dataSpan := timestamps[len(timestamps)-1].Sub(timestamps[0])
26
27
28 avgInterval := dataSpan / time.Duration(len(timestamps)-1)
29
30
31 requiredWindow := avgInterval * time.Duration(minDataPoints-1)
32
33
34
35 if requiredWindow > maxWindow {
36 optimalWindow = maxWindow
37 } else {
38 optimalWindow = requiredWindow
39 }
40
41
42
43 lastInterval := timestamps[len(timestamps)-1].Sub(timestamps[len(timestamps)-2])
44 if optimalWindow < lastInterval {
45 optimalWindow = lastInterval
46 }
47
48
49 var windowData []float64
50 var windowTimestamps []time.Time
51 windowStartTime := timestamps[len(timestamps)-1].Add(-optimalWindow)
52
53 for i := len(timestamps) - 1; i >= 0; i-- {
54 if timestamps[i].After(windowStartTime) || timestamps[i].Equal(windowStartTime) {
55 windowData = append(windowData, metricData[i])
56 windowTimestamps = append(windowTimestamps, timestamps[i])
57 } else {
58 break
59 }
60 }
61
62
63 for i, j := 0, len(windowData)-1; i < j; i, j = i+1, j-1 {
64 windowData[i], windowData[j] = windowData[j], windowData[i]
65 windowTimestamps[i], windowTimestamps[j] = windowTimestamps[j], windowTimestamps[i]
66 }
67
68
69 if len(windowData) < 2 {
70 return 0, fmt.Errorf("insufficient data points (%d) within the calculated window (%s) for rate calculation", len(windowData), optimalWindow)
71 }
72
73
74 firstValue := windowData[0]
75 lastValue := windowData[len(windowData)-1]
76 timeSpan := windowTimestamps[len(windowTimestamps)-1].Sub(windowTimestamps[0])
77
78 if timeSpan <= 0 {
79
80
81 return 0, fmt.Errorf("time span within window is zero or negative (%s)", timeSpan)
82 }
83
84 rate := (lastValue - firstValue) / timeSpan.Seconds()
85
86 return rate, nil
87}
88
89func main() {
90
91 metricValues := []float64{10, 12, 15, 18, 20, 22, 25, 28, 30, 33}
92 timestamps := []time.Time{
93 time.Now().Add(-9 * time.Minute),
94 time.Now().Add(-8 * time.Minute),
95 time.Now().Add(-7 * time.Minute),
96 time.Now().Add(-6 * time.Minute),
97 time.Now().Add(-5 * time.Minute),
98 time.Now().Add(-4 * time.Minute),
99 time.Now().Add(-3 * time.Minute),
100 time.Now().Add(-2 * time.Minute),
101 time.Now().Add(-1 * time.Minute),
102 time.Now(),
103 }
104
105 maxWindow := 5 * time.Minute
106 minDataPoints := 3
107
108 rate, err := calculateDynamicRate(metricValues, timestamps, maxWindow, minDataPoints)
109 if err != nil {
110 fmt.Printf("Error calculating rate: %v\n", err)
111 } else {
112 fmt.Printf("Calculated rate: %.2f per second\n", rate)
113 }
114
115
116 shortMetric := []float64{10, 12}
117 shortTimestamps := []time.Time{time.Now().Add(-2 * time.Minute), time.Now()}
118 rateShort, errShort := calculateDynamicRate(shortMetric, shortTimestamps, maxWindow, minDataPoints)
119 if errShort != nil {
120 fmt.Printf("Error calculating rate for short data: %v\n", errShort)
121 } else {
122 fmt.Printf("Calculated rate for short data: %.2f per second\n", rateShort)
123 }
124
125
126 sparseMetric := []float64{10, 11, 12, 13}
127 sparseTimestamps := []time.Time{
128 time.Now().Add(-10 * time.Minute),
129 time.Now().Add(-8 * time.Minute),
130 time.Now().Add(-6 * time.Minute),
131 time.Now().Add(-4 * time.Minute),
132 }
133 rateSparse, errSparse := calculateDynamicRate(sparseMetric, sparseTimestamps, maxWindow, minDataPoints)
134 if errSparse != nil {
135 fmt.Printf("Error calculating rate for sparse data: %v\n", errSparse)
136 } else {
137 fmt.Printf("Calculated rate for sparse data: %.2f per second\n", rateSparse)
138 }
139}