@@ -13,6 +13,7 @@ const (
13
13
14
14
// SLIPlugin will return a query that will fake a burning error budget at the desired speed using
15
15
// `burn_rate` option.
16
+ // The plugins also accepts a `jitter_percent` that will add/remove a jitter in the range of that jitter percent.
16
17
func SLIPlugin (ctx context.Context , meta , labels , options map [string ]string ) (string , error ) {
17
18
objective , err := getSLOObjective (meta )
18
19
if err != nil {
@@ -24,16 +25,28 @@ func SLIPlugin(ctx context.Context, meta, labels, options map[string]string) (st
24
25
return "" , fmt .Errorf ("could not get burn rate: %w" , err )
25
26
}
26
27
28
+ jitter , err := getJitterPercent (options )
29
+ if err != nil {
30
+ return "" , fmt .Errorf ("could not get jitter percent: %w" , err )
31
+ }
32
+
27
33
// Get the error budget.
28
34
errorBudgetPerc := 100 - objective
29
35
errorBudgetRatio := errorBudgetPerc / 100
30
36
31
37
// Apply factor (burn rate) to error budget.
32
38
expectedSLIError := errorBudgetRatio * burnRate
33
39
40
+ // Create regular query and if no jitter required then regular query
34
41
query := fmt .Sprintf (`max_over_time(vector(%f)[{{.window}}:])` , expectedSLIError )
42
+ if jitter == 0 {
43
+ return query , nil
44
+ }
35
45
36
- return query , nil
46
+ // Create jitter (this is the best random I could came up with) and rest to the regular query.
47
+ jitterQuery := fmt .Sprintf (`(%f * (%f - ((time() * minute() * hour() * day_of_week() * month()) %% %f))) / 100` , expectedSLIError , jitter , jitter * 2 )
48
+
49
+ return fmt .Sprintf ("(%s) - (%s)" , query , jitterQuery ), nil
37
50
}
38
51
39
52
func getBurnRate (options map [string ]string ) (float64 , error ) {
@@ -50,6 +63,20 @@ func getBurnRate(options map[string]string) (float64, error) {
50
63
return burnRate , nil
51
64
}
52
65
66
+ func getJitterPercent (options map [string ]string ) (float64 , error ) {
67
+ jitterPercentS , ok := options ["jitter_percent" ]
68
+ if ! ok {
69
+ return 0 , nil
70
+ }
71
+
72
+ jitterPercent , err := strconv .ParseFloat (jitterPercentS , 64 )
73
+ if err != nil {
74
+ return 0 , fmt .Errorf ("not a valid jitter_percent, can't parse to float64: %w" , err )
75
+ }
76
+
77
+ return jitterPercent , nil
78
+ }
79
+
53
80
func getSLOObjective (meta map [string ]string ) (float64 , error ) {
54
81
objectiveS , ok := meta ["objective" ]
55
82
if ! ok {
0 commit comments