-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexit_code.go
113 lines (103 loc) · 2.53 KB
/
exit_code.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package marshaler
import (
"errors"
"reflect"
"strconv"
)
// Calculates the exit code for a given struct
// The struct must have the following tags:
// - warn: warning threshold
// - crit: critical threshold
// - min: minimum value
// - max: maximum value
func ExitCode(v any) (int, error) {
return exitCode(v, OK)
}
// Recursively walks through the struct and calculates the exit code
// The exit code is the highest exit code of all fields
// If a field is a struct, it will be walked through recursively
// If a field is not a struct, it will be compared to the thresholds
func exitCode(v any, code int) (int, error) {
value := reflect.Indirect(reflect.ValueOf(v))
for i := 0; i < value.NumField(); i++ {
fieldType := value.Type().Field(i)
currentField := value.Field(i)
if fieldIsExported(fieldType) {
if currentField.Kind() == reflect.Struct {
c, err := exitCode(currentField.Interface(), code)
if err != nil {
return UNKNOWN, err
}
if c > code {
code = c
}
continue
} else {
warnTag := fieldType.Tag.Get("warn")
critTag := fieldType.Tag.Get("crit")
minTag := fieldType.Tag.Get("min")
maxTag := fieldType.Tag.Get("max")
f, ok := currentField.Interface().(float64)
if !ok {
return 0, errors.New("field is not float64")
}
critWarnCode, err := calculateCritWarnCode(f, critTag, warnTag)
if err != nil {
return UNKNOWN, err
}
minMaxCode, err := calculateMinMaxCode(f, minTag, maxTag)
if err != nil {
return UNKNOWN, err
}
if critWarnCode > code {
code = critWarnCode
} else if minMaxCode > code {
code = minMaxCode
}
}
}
}
return code, nil
}
func calculateCritWarnCode(value float64, critTag, warnTag string) (int, error) {
if critTag == "" && warnTag == "" {
return OK, nil
}
crit, err := strconv.ParseFloat(critTag, 64)
if err != nil {
return UNKNOWN, err
}
warn, err := strconv.ParseFloat(warnTag, 64)
if err != nil {
return UNKNOWN, err
}
if value >= warn && value < crit {
return WARNING, nil
} else if value >= crit {
return CRITICAL, nil
}
return OK, nil
}
func calculateMinMaxCode(value float64, minTag, maxTag string) (int, error) {
if minTag == "" && maxTag == "" {
return OK, nil
}
min, err := strconv.ParseFloat(minTag, 64)
if err != nil {
return UNKNOWN, err
}
max, err := strconv.ParseFloat(maxTag, 64)
if err != nil {
return UNKNOWN, err
}
if value >= min && value <= max {
return OK, nil
}
return CRITICAL, nil
}
const (
OK = 0
WARNING = 1
CRITICAL = 2
UNKNOWN = 3
)