Skip to content

Prototype for a new way to handle performance data #119

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions examples/check_example2/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ func main() {
check.ExitError(err)
}

check1.Perfdata.Add(&perfdata.Perfdata{
pd := &perfdata.Perfdata{
Label: "foo",
Value: 23,
})
Value: perfdata.NewPdvUint64(23),
}

check1.Perfdata.Add(pd)

check2 := result.PartialResult{}

Expand All @@ -34,14 +36,17 @@ func main() {
check.ExitError(err)
}

check2.Perfdata.Add(&perfdata.Perfdata{
pd2 := &perfdata.Perfdata{
Label: "bar",
Value: 42,
})
check2.Perfdata.Add(&perfdata.Perfdata{
Value: perfdata.NewPdvUint64(42),
}
check2.Perfdata.Add(pd2)

pd3 := &perfdata.Perfdata{
Label: "foo2 bar",
Value: 46,
})
Value: perfdata.NewPdvUint64(46),
}
check2.Perfdata.Add(pd3)

overall.AddSubcheck(check1)
overall.AddSubcheck(check2)
Expand Down
12 changes: 6 additions & 6 deletions perfdata/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (

func ExamplePerfdataList() {
list := PerfdataList{}
list.Add(&Perfdata{Label: "test1", Value: 23})
list.Add(&Perfdata{Label: "test2", Value: 42})
list.Add(&Perfdata{Label: "test1", Value: NewPdvUint64(23)})
list.Add(&Perfdata{Label: "test2", Value: NewPdvUint64(42)})

fmt.Println(list)

Expand All @@ -20,8 +20,8 @@ func ExamplePerfdataList() {

func TestPerfdataListFormating(t *testing.T) {
list := PerfdataList{}
list.Add(&Perfdata{Label: "test1", Value: 23})
list.Add(&Perfdata{Label: "test2", Value: 42})
list.Add(&Perfdata{Label: "test1", Value: NewPdvUint64(23)})
list.Add(&Perfdata{Label: "test2", Value: NewPdvUint64(42)})

assert.Equal(t, "test1=23 test2=42", list.String())
}
Expand All @@ -30,8 +30,8 @@ func BenchmarkPerfdataListFormating(b *testing.B) {
b.ReportAllocs()

list := PerfdataList{}
list.Add(&Perfdata{Label: "test1", Value: 23})
list.Add(&Perfdata{Label: "test2", Value: 42})
list.Add(&Perfdata{Label: "test1", Value: NewPdvUint64(23)})
list.Add(&Perfdata{Label: "test2", Value: NewPdvUint64(42)})

for i := 0; i < b.N; i++ {
l := list.String()
Expand Down
85 changes: 58 additions & 27 deletions perfdata/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package perfdata

import (
"errors"
"fmt"
"math"
"strconv"
"strings"

"github.com/NETWAYS/go-check"
Expand All @@ -19,32 +19,26 @@ var replacer = strings.NewReplacer("=", "_", "`", "_", "'", "_", "\"", "_")
// represent a valid measurement, e.g INF for floats
// This error can probably ignored in most cases and the perfdata point omitted,
// but silently dropping the value and returning the empty strings seems like bad style
func formatNumeric(value interface{}) (string, error) {
switch v := value.(type) {
case float64:
if math.IsInf(v, 0) {
return "", errors.New("Perfdata value is inifinite")
func formatNumeric(value Value) (string, error) {
switch value.kind {
case floatType:
if math.IsInf(value.floatVal, 0) {
return "", errors.New("perfdata value is inifinite")
}

if math.IsNaN(v) {
return "", errors.New("Perfdata value is inifinite")
if math.IsNaN(value.floatVal) {
return "", errors.New("perfdata value is NaN")
}

return check.FormatFloat(v), nil
case float32:
if math.IsInf(float64(v), 0) {
return "", errors.New("Perfdata value is inifinite")
}

if math.IsNaN(float64(v)) {
return "", errors.New("Perfdata value is inifinite")
}

return check.FormatFloat(float64(v)), nil
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
return fmt.Sprintf("%d", v), nil
return check.FormatFloat(value.floatVal), nil
case intType:
return strconv.FormatInt(value.intVal, 10), nil
case uintType:
return strconv.FormatUint(value.uintVal, 10), nil
case noneType:
return "", errors.New("value was not set")
default:
panic(fmt.Sprintf("unsupported type for perfdata: %T", value))
return "", errors.New("this should not happen")
}
}

Expand All @@ -61,13 +55,50 @@ func formatNumeric(value interface{}) (string, error) {
// https://icinga.com/docs/icinga-2/latest/doc/05-service-monitoring/#unit-of-measurement-uom
type Perfdata struct {
Label string
Value interface{}
Value Value
// Uom is the unit-of-measurement, see links above for details.
Uom string
Warn *check.Threshold
Crit *check.Threshold
Min interface{}
Max interface{}
Min Value
Max Value
}

type perfdataValueTypeEnum int

const (
noneType perfdataValueTypeEnum = iota
intType
uintType
floatType
)

type Value struct {
kind perfdataValueTypeEnum
uintVal uint64
intVal int64
floatVal float64
}

func NewPdvUint64(val uint64) Value {
return Value{
kind: uintType,
uintVal: val,
}
}

func NewPdvInt64(val int64) Value {
return Value{
kind: intType,
intVal: val,
}
}

func NewPdvFloat64(val float64) Value {
return Value{
kind: floatType,
floatVal: val,
}
}

// String returns the proper format for the plugin output
Expand Down Expand Up @@ -109,10 +140,10 @@ func (p Perfdata) ValidatedString() (string, error) {
}

// Limits
for _, value := range []interface{}{p.Min, p.Max} {
for _, value := range []Value{p.Min, p.Max} {
sb.WriteString(";")

if value != nil {
if value.kind != noneType {
pfVal, err := formatNumeric(value)
// Attention: we ignore limits if they are faulty
if err == nil {
Expand Down
32 changes: 16 additions & 16 deletions perfdata/type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ func BenchmarkPerfdataString(b *testing.B) {

perf := Perfdata{
Label: "test test=test",
Value: 10.1,
Value: NewPdvFloat64(10.1),
Uom: "%",
Warn: &check.Threshold{Upper: 80},
Crit: &check.Threshold{Upper: 90},
Min: 0,
Max: 100}
Min: NewPdvUint64(0),
Max: NewPdvInt64(100)}

for i := 0; i < b.N; i++ {
p := perf.String()
Expand All @@ -34,36 +34,36 @@ func TestRenderPerfdata(t *testing.T) {
"simple": {
perf: Perfdata{
Label: "test",
Value: 2,
Value: NewPdvUint64(2),
},
expected: "test=2",
},
"with-quotes": {
perf: Perfdata{
Label: "te's\"t",
Value: 2,
Value: NewPdvInt64(2),
},
expected: "te_s_t=2",
},
"with-special-chars": {
perf: Perfdata{
Label: "test_🖥️_'test",
Value: 2,
Value: NewPdvUint64(2),
},
expected: "test_🖥️__test=2",
},
"with-uom": {
perf: Perfdata{
Label: "test",
Value: 2,
Value: NewPdvInt64(2),
Uom: "%",
},
expected: "test=2%",
},
"with-thresholds": {
perf: Perfdata{
Label: "foo bar",
Value: 2.76,
Value: NewPdvFloat64(2.76),
Uom: "m",
Warn: &check.Threshold{Lower: 10, Upper: 25, Inside: true},
Crit: &check.Threshold{Lower: 15, Upper: 20, Inside: false},
Expand All @@ -79,7 +79,7 @@ func TestRenderPerfdata(t *testing.T) {
"invalid-value": {
perf: Perfdata{
Label: "to infinity",
Value: math.Inf(+1),
Value: NewPdvFloat64(math.Inf(+1)),
},
expected: "",
},
Expand All @@ -104,34 +104,34 @@ func TestRenderPerfdata(t *testing.T) {

type pfFormatTest struct {
Result string
InputValue interface{}
InputValue Value
}

func TestFormatNumeric(t *testing.T) {
testdata := []pfFormatTest{
{
Result: "10",
InputValue: 10,
InputValue: NewPdvUint64(10),
},
{
Result: "-10",
InputValue: -10,
InputValue: NewPdvInt64(-10),
},
{
Result: "10",
InputValue: uint8(10),
InputValue: NewPdvUint64(10),
},
{
Result: "1234.567",
InputValue: float64(1234.567),
InputValue: NewPdvFloat64(1234.567),
},
{
Result: "3456.789",
InputValue: float32(3456.789),
InputValue: NewPdvFloat64(3456.789),
},
{
Result: "1234567890.988",
InputValue: 1234567890.9877,
InputValue: NewPdvFloat64(1234567890.9877),
},
}

Expand Down
74 changes: 37 additions & 37 deletions result/overall.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,53 +98,53 @@ func (o *Overall) GetStatus() int {
return check.Warning
} else if o.oks > 0 {
return check.OK
} else {
return check.Unknown
}
} else {
// state not set explicitly!
if len(o.PartialResults) == 0 {
return check.Unknown
}

var (
criticals int
warnings int
oks int
unknowns int
)
return check.Unknown
}

for _, sc := range o.PartialResults {
switch sc.GetStatus() {
case check.Critical:
criticals++
case check.Warning:
warnings++
case check.Unknown:
unknowns++
case check.OK:
oks++
}
}
// state not set explicitly!
if len(o.PartialResults) == 0 {
return check.Unknown
}

if criticals > 0 {
return check.Critical
var (
criticals int
warnings int
oks int
unknowns int
)

for _, sc := range o.PartialResults {
switch sc.GetStatus() {
case check.Critical:
criticals++
case check.Warning:
warnings++
case check.Unknown:
unknowns++
case check.OK:
oks++
}
}

if unknowns > 0 {
return check.Unknown
}
if criticals > 0 {
return check.Critical
}

if warnings > 0 {
return check.Warning
}
if unknowns > 0 {
return check.Unknown
}

if oks > 0 {
return check.OK
}
if warnings > 0 {
return check.Warning
}

return check.Unknown
if oks > 0 {
return check.OK
}

return check.Unknown
}

// GetSummary returns a text representation of the current state of the Overall
Expand Down
Loading
Loading