ℹ️ Select 'Choose Exercise', or randomize 'Next Random Exercise' in selected language.

Choose Exercise:
Timer 00:00
WPM --
Score --
Acc --
Correct chars --

Detect Anomaly with Moving Average

PromQL

Goal -- WPM

Ready
Exercise Algorithm Area
1package main
2
3import (
4 "fmt"
5 "time"
6)
7
8// detectAnomalyWithMovingAverage identifies potential anomalies by comparing a metric
9// against its moving average plus a multiple of its standard deviation.
10func detectAnomalyWithMovingAverage(metricName string, windowDuration time.Duration, stdDevMultiplier float64) string {
11 if metricName == "" {
12 fmt.Println("Error: Metric name cannot be empty.")
13 return ""
14 }
15 if windowDuration <= 0 {
16 fmt.Println("Error: Window duration must be positive.")
17 return ""
18 }
19 if stdDevMultiplier <= 0 {
20 fmt.Println("Error: Standard deviation multiplier must be positive.")
21 return ""
22 }
23
24 // Calculate the moving average.
25 // avg_over_time calculates the average of a metric over a specified time window.
26 movingAvgQuery := fmt.Sprintf("avg_over_time(%s[%s])", metricName, windowDuration)
27
28 // Calculate the standard deviation over the same window.
29 // stddev_over_time calculates the standard deviation.
30 stdDevQuery := fmt.Sprintf("stddev_over_time(%s[%s])", metricName, windowDuration)
31
32 // Construct the anomaly detection query.
33 // An anomaly is detected if the current metric value is significantly higher than the moving average.
34 // We define 'significantly higher' as being more than 'stdDevMultiplier' standard deviations above the average.
35 anomalyQuery := fmt.Sprintf("%s > (%s + %f * %s)",
36 metricName,
37 movingAvgQuery,
38 stdDevMultiplier,
39 stdDevQuery)
40
41 return anomalyQuery
42}
43
44// detectAnomalyWithRateAndStdDev detects anomalies based on the rate of change.
45func detectAnomalyWithRateAndStdDev(metricName string, rateDuration time.Duration, stdDevMultiplier float64) string {
46 if metricName == "" {
47 fmt.Println("Error: Metric name cannot be empty.")
48 return ""
49 }
50 if rateDuration <= 0 {
51 fmt.Println("Error: Rate duration must be positive.")
52 return ""
53 }
54 if stdDevMultiplier <= 0 {
55 fmt.Println("Error: Standard deviation multiplier must be positive.")
56 return ""
57 }
58
59 // Calculate the rate of change.
60 rateQuery := fmt.Sprintf("rate(%s[%s])", metricName, rateDuration)
61
62 // Calculate the standard deviation of the rate.
63 stdDevRateQuery := fmt.Sprintf("stddev_over_time(rate(%s[%s]) offset 1m)", metricName, rateDuration) // Offset to avoid self-correlation
64
65 // Anomaly if the current rate is significantly higher than the average rate.
66 anomalyQuery := fmt.Sprintf("%s > (%s + %f * %s)",
67 rateQuery,
68 rateQuery,
69 stdDevMultiplier,
70 stdDevRateQuery)
71
72 return anomalyQuery
73}
74
75func main() {
76 metric := "http_requests_total"
77 window := 1 * time.Hour
78 multiplier := 3.0
79
80 anomalyDetectionQuery := detectAnomalyWithMovingAverage(metric, window, multiplier)
81 fmt.Printf("Anomaly detection query: %s\n", anomalyDetectionQuery)
82
83 // Example using rate and stddev
84 rateWindow := 5 * time.Minute
85 rateAnomalyQuery := detectAnomalyWithRateAndStdDev(metric, rateWindow, multiplier)
86 fmt.Printf("Anomaly detection query (rate-based): %s\n", rateAnomalyQuery)
87}
Algorithm description viewbox

Detect Anomaly with Moving Average

Algorithm description:

This scenario involves creating a PromQL query to detect anomalies in a time series metric. It calculates a moving average and standard deviation over a specified window and flags data points that deviate significantly (e.g., more than 3 standard deviations) from the expected range. This is useful for identifying unusual spikes or drops in metrics like request rates or error counts.

Algorithm explanation:

Anomaly detection using moving averages and standard deviations is a common statistical technique. In PromQL, `avg_over_time(metric[duration])` calculates the average value of `metric` over the last `duration`. Similarly, `stddev_over_time(metric[duration])` calculates the standard deviation. By comparing the current value of `metric` against `moving_average + multiplier * standard_deviation`, we can identify points that are statistically unusual. A `multiplier` of 3 is often used, as it corresponds to approximately 99.7% of data falling within this range in a normal distribution. Time complexity is O(N*W) where N is the number of series and W is the window duration, as it needs to process data points within the window. Space complexity is O(N*W) to store data for the window. Edge cases include empty metric names, non-positive durations, and invalid multipliers.

Pseudocode:

function detectAnomalyWithMovingAverage(metricName, windowDuration, stdDevMultiplier):
  if metricName is empty or windowDuration or stdDevMultiplier are invalid:
    return error message
  
  movingAvg = "avg_over_time(" + metricName + "[" + windowDuration + "])"
  stdDev = "stddev_over_time(" + metricName + "[" + windowDuration + "])"
  
  anomalyCondition = metricName + " > (" + movingAvg + " + " + stdDevMultiplier + " * " + stdDev + ")"
  return anomalyCondition

function detectAnomalyWithRateAndStdDev(metricName, rateDuration, stdDevMultiplier):
  // Similar checks
  rate = "rate(" + metricName + "[" + rateDuration + "])"
  stdDevRate = "stddev_over_time(rate(" + metricName + "[" + rateDuration + "])") // Potentially with offset
  
  anomalyCondition = rate + " > (" + rate + " + " + stdDevMultiplier + " * " + stdDevRate + ")"
  return anomalyCondition