Skip to content

Commit d7b8c4c

Browse files
Ahmet OeztuerkAhmet Oeztuerk
authored andcommitted
revise performance data collection
should now be thread safe, as each caller manages its own collection and only uses member functions
1 parent 7133b8f commit d7b8c4c

File tree

3 files changed

+207
-81
lines changed

3 files changed

+207
-81
lines changed

Exit.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,20 @@ func ErrorExit(err error) {
1919

2020
// Exit returns with the given returncode and message and optional PerformanceData
2121
func Exit(state State, msg string) {
22-
LongExit(state, msg, "")
22+
LongExit(state, msg, "", nil)
2323
}
2424

2525
// LongExit returns with the given returncode and message and optional PerformanceData and long message
26-
func LongExit(state State, msg, longMsg string) {
27-
if perf := PrintPerformanceData(); perf == "" {
26+
func LongExit(state State, msg, longMsg string, collection *PerformanceDataCollection) {
27+
perfString := ""
28+
if collection != nil {
29+
perfString = collection.PrintAllPerformanceData()
30+
}
31+
32+
if perfString == "" {
2833
fmt.Printf("%s - %s\n%s", state.Name, msg, longMsg)
2934
} else {
30-
fmt.Printf("%s - %s|%s\n%s", state.Name, msg, perf, longMsg)
35+
fmt.Printf("%s - %s|%s\n%s", state.Name, msg, perfString, longMsg)
3136
}
3237
os.Exit(state.Code)
3338
}

PerformanceData.go

Lines changed: 120 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,68 +7,123 @@ import (
77
"sync"
88
)
99

10-
type PerformanceData map[string]interface{}
10+
// PerformanceData is a map with string keys and any values, essentially a dictionary
11+
// Since its an dictionary, always add add a label
12+
// "label" = "health_rate"
13+
// "value" = 80
14+
// "critical" = 160
15+
type PerformanceData map[string]any
1116

12-
var (
13-
p []PerformanceData = []PerformanceData{}
14-
pMutex = &sync.Mutex{}
15-
)
17+
// This is a struct that users of the library should use.
18+
// They have to manage this object through functions in this file
19+
// Library clients should get an instance of this and keep calling its methods
20+
type PerformanceDataCollection struct {
21+
data []PerformanceData
22+
dataMutex *sync.Mutex
23+
}
24+
25+
// Returns an empty PerformanceDataCollection
26+
func NewPerformanceDataCollection() PerformanceDataCollection {
27+
return PerformanceDataCollection{
28+
data: make([]PerformanceData, 0),
29+
dataMutex: &sync.Mutex{},
30+
}
31+
}
1632

17-
// NewPerformanceData adds a PerformanceData object which can be expanded with further information
18-
func NewPerformanceData(label string, value float64) *PerformanceData {
19-
return NewPerformanceDataString(label, strconv.FormatFloat(value, 'f', -1, 64))
33+
// Adds a new PerformanceData element to the data array
34+
// Use the label to get the reference to the PerformanceData later on
35+
func (collection *PerformanceDataCollection) AddPerformanceData(label string, value string) {
36+
collection.dataMutex.Lock()
37+
collection.data = append(collection.data, PerformanceData{"label": label, "value": value})
38+
collection.dataMutex.Unlock()
2039
}
2140

22-
// NewPerformanceDataString adds a PerformanceData object which can be expanded with further information
23-
func NewPerformanceDataString(label, value string) *PerformanceData {
24-
pMutex.Lock()
25-
p = append(p, PerformanceData{"label": label, "value": value})
26-
newOne := &(p[len(p)-1])
27-
pMutex.Unlock()
28-
return newOne
41+
// Calls collection.AddPerformanceData after converting float to string
42+
func (collection *PerformanceDataCollection) AddPerformanceDataFloat64(label string, value float64) {
43+
collection.AddPerformanceData(label, strconv.FormatFloat(value, 'f', -1, 64))
2944
}
3045

31-
// Unit adds an unit string to the PerformanceData
32-
func (p PerformanceData) Unit(unit string) PerformanceData {
33-
p["unit"] = unit
34-
return p
46+
// Internal function to find a PerformanceData with specified label
47+
func (collection *PerformanceDataCollection) findPerformanceData(label string) (*PerformanceData, error) {
48+
for index, pd := range collection.data {
49+
if pd_label, ok := pd["label"]; ok && pd_label == label {
50+
return &collection.data[index], nil
51+
}
52+
}
53+
return nil, fmt.Errorf("no performance data with the label '%s' found", label)
54+
}
55+
56+
// Adds a field called "unit" to the PerformanceData with the label
57+
func (collection *PerformanceDataCollection) Unit(label string, unit string) error {
58+
collection.dataMutex.Lock()
59+
defer collection.dataMutex.Unlock()
60+
pd, err := collection.findPerformanceData(label)
61+
if err != nil {
62+
return err
63+
}
64+
(*pd)["unit"] = unit
65+
return nil
3566
}
3667

37-
// Warn adds the threshold to the PerformanceData
38-
func (p PerformanceData) Warn(warn *Threshold) PerformanceData {
39-
p["warn"] = warn
40-
return p
68+
// Adds a field called "unit" to the PerformanceData with the label
69+
func (collection *PerformanceDataCollection) Warn(label string, warn *Threshold) error {
70+
collection.dataMutex.Lock()
71+
defer collection.dataMutex.Unlock()
72+
pd, err := collection.findPerformanceData(label)
73+
if err != nil {
74+
return err
75+
}
76+
(*pd)["warn"] = warn
77+
return nil
4178
}
4279

43-
// Crit adds the threshold to the PerformanceData
44-
func (p PerformanceData) Crit(crit *Threshold) PerformanceData {
45-
p["crit"] = crit
46-
return p
80+
// Adds a field called "unit" to the PerformanceData with the label
81+
func (collection *PerformanceDataCollection) Crit(label string, crit *Threshold) error {
82+
collection.dataMutex.Lock()
83+
defer collection.dataMutex.Unlock()
84+
pd, err := collection.findPerformanceData(label)
85+
if err != nil {
86+
return err
87+
}
88+
(*pd)["crit"] = crit
89+
return nil
4790
}
4891

49-
// Min adds the float64 to the PerformanceData
50-
func (p PerformanceData) Min(min float64) PerformanceData {
51-
p["min"] = min
52-
return p
92+
// Adds a field called "unit" to the PerformanceData with the label
93+
func (collection *PerformanceDataCollection) Min(label string, min float64) error {
94+
collection.dataMutex.Lock()
95+
defer collection.dataMutex.Unlock()
96+
pd, err := collection.findPerformanceData(label)
97+
if err != nil {
98+
return err
99+
}
100+
(*pd)["min"] = min
101+
return nil
53102
}
54103

55-
// Min adds the float64 to the PerformanceData
56-
func (p PerformanceData) Max(max float64) PerformanceData {
57-
p["max"] = max
58-
return p
104+
// Adds a field called "unit" to the PerformanceData with the label
105+
func (collection *PerformanceDataCollection) Max(label string, max float64) error {
106+
collection.dataMutex.Lock()
107+
defer collection.dataMutex.Unlock()
108+
pd, err := collection.findPerformanceData(label)
109+
if err != nil {
110+
return err
111+
}
112+
(*pd)["max"] = max
113+
return nil
59114
}
60115

61-
// toString prints this PerformanceData
62-
func (p PerformanceData) toString() string {
116+
// internal function to print a PerformanceData
117+
func (pd PerformanceData) toString() string {
63118
var toPrint bytes.Buffer
64119

65-
toPrint.WriteString(fmt.Sprintf("'%s'=%s", p["label"], p["value"]))
66-
if unit, ok := p["unit"]; ok {
120+
toPrint.WriteString(fmt.Sprintf("'%s'=%s", pd["label"], pd["value"]))
121+
if unit, ok := pd["unit"]; ok {
67122
toPrint.WriteString(unit.(string))
68123
}
69124
toPrint.WriteString(";")
70125
addThreshold := func(key string) {
71-
if value, ok := p[key]; ok && value != nil {
126+
if value, ok := pd[key]; ok && value != nil {
72127
if t := value.(*Threshold); t != nil {
73128
toPrint.WriteString(t.input)
74129
}
@@ -79,7 +134,7 @@ func (p PerformanceData) toString() string {
79134
addThreshold("crit")
80135

81136
addFloat := func(key string) {
82-
if value, ok := p[key]; ok {
137+
if value, ok := pd[key]; ok {
83138
toPrint.WriteString(strconv.FormatFloat(value.(float64), 'f', -1, 64))
84139
}
85140
}
@@ -90,14 +145,33 @@ func (p PerformanceData) toString() string {
90145
return toPrint.String()
91146
}
92147

93-
// PrintPerformanceData prints all PerformanceData
94-
func PrintPerformanceData() string {
148+
// Finds and prints the PerformanceData found in this collection
149+
func (collection *PerformanceDataCollection) PrintPerformanceData(label string) (string, error) {
150+
collection.dataMutex.Lock()
151+
defer collection.dataMutex.Unlock()
152+
pd, err := collection.findPerformanceData(label)
153+
if err != nil {
154+
return "", err
155+
}
156+
157+
return (*pd).toString(), nil
158+
}
159+
160+
// Prints all PerformanceData to a string in this collection
161+
func (collection *PerformanceDataCollection) PrintAllPerformanceData() string {
162+
collection.dataMutex.Lock()
163+
defer collection.dataMutex.Unlock()
95164
var toPrint bytes.Buffer
96-
pMutex.Lock()
97-
for _, perfData := range p {
165+
for _, perfData := range collection.data {
98166
toPrint.WriteString(perfData.toString())
99167
toPrint.WriteString(" ")
100168
}
101-
pMutex.Unlock()
102169
return toPrint.String()
103170
}
171+
172+
// Clears all PerformanceData stored in this collection
173+
func (collection *PerformanceDataCollection) ClearPerformanceCollection() {
174+
collection.dataMutex.Lock()
175+
defer collection.dataMutex.Unlock()
176+
collection.data = make([]PerformanceData, 0)
177+
}

PerformanceData_test.go

Lines changed: 78 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,123 @@
11
package check_x
22

33
import (
4-
"reflect"
54
"testing"
65
)
76

87
var perfdataToString = []struct {
9-
f func() PerformanceData
8+
f func() PerformanceDataCollection
109
expected string
1110
}{
12-
{func() PerformanceData {
13-
return *NewPerformanceDataString("a", "1")
11+
{func() PerformanceDataCollection {
12+
col := NewPerformanceDataCollection()
13+
col.AddPerformanceData("a", "1")
14+
return col
1415
}, "'a'=1;;;;"},
15-
{func() PerformanceData {
16+
{func() PerformanceDataCollection {
1617
warn, _ := NewThreshold("10:")
17-
return NewPerformanceDataString("a", "2").Warn(warn)
18+
col := NewPerformanceDataCollection()
19+
col.AddPerformanceData("a", "2")
20+
col.Warn("a", warn)
21+
return col
1822
}, "'a'=2;10:;;;"},
19-
{func() PerformanceData {
23+
{func() PerformanceDataCollection {
2024
warn, _ := NewThreshold("10:")
2125
crit, _ := NewThreshold("@10:20")
22-
return NewPerformanceDataString("a", "3").Warn(warn).Crit(crit)
26+
col := NewPerformanceDataCollection()
27+
col.AddPerformanceData("a", "3")
28+
col.Warn("a", warn)
29+
col.Crit("a", crit)
30+
return col
2331
}, "'a'=3;10:;@10:20;;"},
24-
{func() PerformanceData {
32+
{func() PerformanceDataCollection {
2533
warn, _ := NewThreshold("10:")
2634
crit, _ := NewThreshold("@10:20")
27-
return NewPerformanceDataString("a", "3").Warn(warn).Crit(crit).Min(0)
35+
col := NewPerformanceDataCollection()
36+
col.AddPerformanceData("a", "3")
37+
col.Warn("a", warn)
38+
col.Crit("a", crit)
39+
col.Min("a", 0)
40+
return col
2841
}, "'a'=3;10:;@10:20;0;"},
29-
{func() PerformanceData {
42+
{func() PerformanceDataCollection {
3043
warn, _ := NewThreshold("10:")
3144
crit, _ := NewThreshold("@10:20")
32-
return NewPerformanceDataString("a", "4").Warn(warn).Crit(crit).Min(0).Max(100)
45+
col := NewPerformanceDataCollection()
46+
col.AddPerformanceData("a", "4")
47+
col.Warn("a", warn)
48+
col.Crit("a", crit)
49+
col.Min("a", 0)
50+
col.Max("a", 100)
51+
return col
3352
}, "'a'=4;10:;@10:20;0;100"},
34-
{func() PerformanceData {
53+
{func() PerformanceDataCollection {
3554
warn, _ := NewThreshold("10:")
3655
crit, _ := NewThreshold("@10:20")
37-
return NewPerformanceDataString("a", "5").Warn(warn).Crit(crit).Min(0).Max(100).Unit("C")
56+
col := NewPerformanceDataCollection()
57+
col.AddPerformanceData("a", "5")
58+
col.Warn("a", warn)
59+
col.Crit("a", crit)
60+
col.Min("a", 0)
61+
col.Max("a", 100)
62+
col.Unit("a", "C")
63+
return col
3864
}, "'a'=5C;10:;@10:20;0;100"},
39-
{func() PerformanceData {
65+
{func() PerformanceDataCollection {
4066
warn, _ := NewThreshold("10:")
4167
crit, _ := NewThreshold("@10:20")
42-
return NewPerformanceData("a", 6).Warn(warn).Crit(crit).Min(0).Max(100).Unit("C")
68+
col := NewPerformanceDataCollection()
69+
col.AddPerformanceDataFloat64("a", 6)
70+
col.Warn("a", warn)
71+
col.Crit("a", crit)
72+
col.Min("a", 0)
73+
col.Max("a", 100)
74+
col.Unit("a", "C")
75+
return col
4376
}, "'a'=6C;10:;@10:20;0;100"},
44-
{func() PerformanceData {
77+
{func() PerformanceDataCollection {
4578
warn, _ := NewThreshold("")
4679
crit, _ := NewThreshold("@10:20")
47-
return NewPerformanceData("a", 6).Warn(warn).Crit(crit).Min(0).Max(100).Unit("C")
80+
col := NewPerformanceDataCollection()
81+
col.AddPerformanceDataFloat64("a", 6)
82+
col.Warn("a", warn)
83+
col.Crit("a", crit)
84+
col.Min("a", 0)
85+
col.Max("a", 100)
86+
col.Unit("a", "C")
87+
return col
4888
}, "'a'=6C;;@10:20;0;100"},
49-
{func() PerformanceData {
89+
{func() PerformanceDataCollection {
5090
crit, _ := NewThreshold("@10:20")
51-
return NewPerformanceData("a", 6).Warn(nil).Crit(crit).Min(0).Max(100).Unit("C")
91+
col := NewPerformanceDataCollection()
92+
col.AddPerformanceDataFloat64("a", 6)
93+
col.Warn("a", nil)
94+
col.Crit("a", crit)
95+
col.Min("a", 0)
96+
col.Max("a", 100)
97+
col.Unit("a", "C")
98+
return col
5299
}, "'a'=6C;;@10:20;0;100"},
53100
}
54101

55102
func TestPerformanceData_toString(t *testing.T) {
56103
for i, data := range perfdataToString {
57-
result := data.f()
58-
resultString := result.toString()
59-
if resultString != data.expected {
60-
t.Errorf("%d - Expected: %s, got: %s", i, data.expected, resultString)
104+
collection := data.f()
105+
collectionString, err := collection.PrintPerformanceData("a")
106+
if err != nil {
107+
t.Errorf("Error when finding the performance data: %s", err.Error())
61108
}
62-
if !reflect.DeepEqual(p[i], result) {
63-
t.Errorf("%d - Expected: %s, got: %s", i, p[i], result)
109+
if collectionString != data.expected {
110+
t.Errorf("%d - Expected: %s, got: %s", i, data.expected, collectionString)
64111
}
65112
}
66113
}
67114

68115
func TestPrintPerformanceData(t *testing.T) {
69-
p = []PerformanceData{}
70-
NewPerformanceDataString("a", "1")
71-
NewPerformanceDataString("b", "2")
116+
col := NewPerformanceDataCollection()
117+
col.AddPerformanceData("a", "1")
118+
col.AddPerformanceData("b", "2")
72119
expected := "'a'=1;;;;" + " " + "'b'=2;;;; "
73-
if expected != PrintPerformanceData() {
74-
t.Errorf("Expected: %s, got: %s", expected, PrintPerformanceData())
120+
if expected != col.PrintAllPerformanceData() {
121+
t.Errorf("Expected: %s, got: %s", expected, col.PrintAllPerformanceData())
75122
}
76123
}

0 commit comments

Comments
 (0)