Skip to content
Merged
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
19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,20 @@ The `Exit` function can be used to cause an exit with the given status code.
```go
check.Exit(check.OK, fmt.Sprintf("Everything is fine - value=%d", 42)) // OK, 0

// With perfdata
check.Exit(check.Critical, "CRITICAL", "|", "percent_packet_loss=100") // CRITICAL, 2
// With critical
check.Exit(check.Critical, "Everything is broken", "Do something!") // CRITICAL, 2
```

`ExitError` can be used to cause an exit with the given error.
The `ExitWithPerfdata` function can be used to include performance data in the output.

```go
perfdata := check.PerfdataList{}
perfdata.Add(&check.Perfdata{Label: "packages_lost", Value: 42})

check.ExitWithPerfdata(check.OK, perfdata, "Everything is fine", "Package loss nominal")
```

The `ExitError` function can be used to cause an exit with the given error.

```go
err := fmt.Errorf("connection to %s has been timed out", "localhost:12345")
Expand Down Expand Up @@ -118,9 +127,9 @@ See also: https://www.monitoring-plugins.org/doc/guidelines.html#THRESHOLDFORMAT
The `Perfdata` object represents monitoring plugin performance data that relates to the actual execution of a host or service check.

```go
var pl perfdata.PerfdataList
var pl check.PerfdataList

pl.Add(&perfdata.Perfdata{
pl.Add(&check.Perfdata{
Label: "process.cpu.percent",
Value: 25,
Uom: "%",
Expand Down
7 changes: 3 additions & 4 deletions examples/check_example2/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main

import (
"github.com/NETWAYS/go-check"
"github.com/NETWAYS/go-check/perfdata"
"github.com/NETWAYS/go-check/result"
)

Expand All @@ -16,7 +15,7 @@ func main() {
check1.Output = "Check1"
check1.SetState(check.OK)

check1.Perfdata.Add(&perfdata.Perfdata{
check1.Perfdata.Add(&check.Perfdata{
Label: "foo",
Value: 23,
})
Expand All @@ -28,11 +27,11 @@ func main() {
check2.Output = "Check2"
check2.SetState(check.Warning)

check2.Perfdata.Add(&perfdata.Perfdata{
check2.Perfdata.Add(&check.Perfdata{
Label: "bar",
Value: 42,
})
check2.Perfdata.Add(&perfdata.Perfdata{
check2.Perfdata.Add(&check.Perfdata{
Label: "foo2 bar",
Value: 46,
})
Expand Down
32 changes: 31 additions & 1 deletion exit.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ var AllowExit = true
var PrintStack = true

// Exit exits the process with a given return code determined from the given Status
// and a text representation to stdout.
// and the provided text output to stdout.
// To include performance that is recommended to use ExitWithPerfdata instead
// Note that, the text output is not sanitized and will be printed as is.
//
// Example: [OK] - everything is fine
// exit 0
Expand All @@ -37,6 +39,34 @@ func Exit(rc Status, output ...string) {
BaseExit(rc)
}

// ExitWithPerfdata exits the process with a given return code determined from the Status,
// the performance data and the text output to stdout.
//
// The provided text output will be sanitized to avoid multiple performance data
// separators (|).
//
// Example: [OK] - everything is fine | mylabel=1
// exit 0
func ExitWithPerfdata(rc Status, perfdata PerfdataList, output ...string) {
var text strings.Builder

text.WriteString("[" + rc.String() + "] -")

for _, s := range output {
text.WriteString(" " + strings.ReplaceAll(s, PerfdataSeparatorSymbol, " "))
Comment thread
martialblog marked this conversation as resolved.
}

text.WriteString(PerfdataSeparatorSymbol)

text.WriteString(perfdata.String())

text.WriteString("\n")

_, _ = os.Stdout.WriteString(text.String())

BaseExit(rc)
}

// BaseExit exits the process with a given return code.
//
// Can be controlled with the global AllowExit.
Expand Down
10 changes: 10 additions & 0 deletions exit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ func ExampleExit() {
// would exit with code 0
}

func ExampleExitWithPerfdata() {
perfdata := PerfdataList{}
perfdata.Add(&Perfdata{Label: "time_duration", Value: 23})
perfdata.Add(&Perfdata{Label: "packages_lost", Value: 42})

ExitWithPerfdata(Critical, perfdata, "Everything is broken", "Do something")
// Output: [CRITICAL] - Everything is broken Do something|time_duration=23 packages_lost=42
// would exit with code 2
}

func ExampleExitError() {
err := fmt.Errorf("connection to %s has been timed out", "localhost:12345")
ExitError(err)
Expand Down
19 changes: 9 additions & 10 deletions perfdata/perfdata.go → perfdata.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
// Package perfdata provides types and functions to handle check plugin performance data
package perfdata
package check

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

"github.com/NETWAYS/go-check"
)

const PerfdataSeparatorSymbol = "|"

// PerfdataList can store multiple perfdata and implements the fmt.Stringer interface
// to provide formated output for the performance data
type PerfdataList []*Perfdata //nolint: revive
type PerfdataList []*Perfdata

// String returns string representations of all Perfdata added to the list
func (l *PerfdataList) String() string {
Expand Down Expand Up @@ -57,7 +56,7 @@ func formatNumeric(value any) (string, error) {
return "", errors.New("Perfdata value is infinite")
}

return check.FormatFloat(v), nil
return FormatFloat(v), nil
case float32:
if math.IsInf(float64(v), 0) {
return "", errors.New("Perfdata value is infinite")
Expand All @@ -67,7 +66,7 @@ func formatNumeric(value any) (string, error) {
return "", errors.New("Perfdata value is infinite")
}

return check.FormatFloat(float64(v)), nil
return FormatFloat(float64(v)), nil
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
return fmt.Sprintf("%d", v), nil
default:
Expand All @@ -88,8 +87,8 @@ type Perfdata struct {
Value any
// Uom is the unit-of-measurement, see links above for details.
Uom string
Warn *check.Threshold
Crit *check.Threshold
Warn *Threshold
Crit *Threshold
Min any
Max any
}
Expand Down Expand Up @@ -124,7 +123,7 @@ func (p Perfdata) ValidatedString() (string, error) {
sb.WriteString(p.Uom)

// Thresholds
for _, value := range []*check.Threshold{p.Warn, p.Crit} {
for _, value := range []*Threshold{p.Warn, p.Crit} {
sb.WriteString(";")

if value != nil {
Expand Down
12 changes: 5 additions & 7 deletions perfdata/perfdata_test.go → perfdata_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package perfdata
package check

import (
"fmt"
"math"
"testing"

"github.com/NETWAYS/go-check"
)

func ExamplePerfdataList() {
Expand Down Expand Up @@ -52,8 +50,8 @@ func BenchmarkPerfdataString(b *testing.B) {
Label: "test test=test",
Value: 10.1,
Uom: "%",
Warn: &check.Threshold{Upper: 80},
Crit: &check.Threshold{Upper: 90},
Warn: &Threshold{Upper: 80},
Crit: &Threshold{Upper: 90},
Min: 0,
Max: 100}

Expand Down Expand Up @@ -102,8 +100,8 @@ func TestRenderPerfdata(t *testing.T) {
Label: "foo bar",
Value: 2.76,
Uom: "m",
Warn: &check.Threshold{Lower: 10, Upper: 25, Inside: true},
Crit: &check.Threshold{Lower: 15, Upper: 20, Inside: false},
Warn: &Threshold{Lower: 10, Upper: 25, Inside: true},
Crit: &Threshold{Lower: 15, Upper: 20, Inside: false},
},
expected: "'foo bar'=2.76m;@10:25;15:20",
},
Expand Down
11 changes: 5 additions & 6 deletions result/overall.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"sync"

"github.com/NETWAYS/go-check"
"github.com/NETWAYS/go-check/perfdata"
)

// The "width" of the indentation which is added on every level
Expand Down Expand Up @@ -100,14 +99,14 @@ func (o *Overall) GetOutput() string {

// Generate indeted output and perfdata for all partialResults
for i := range o.PartialResults {
output.WriteString(o.PartialResults[i].getOutput(0))
output.WriteString(strings.ReplaceAll(o.PartialResults[i].getOutput(0), check.PerfdataSeparatorSymbol, " "))
pdata.WriteString(" " + o.PartialResults[i].getPerfdata())
}

pdataString := strings.Trim(pdata.String(), " ")

if len(pdataString) > 0 {
output.WriteString("|" + pdataString + "\n")
output.WriteString(check.PerfdataSeparatorSymbol + pdataString + "\n")
}
}

Expand Down Expand Up @@ -144,7 +143,7 @@ func (o *Overall) getStatusCount() statusCount {

// PartialResult represents a sub-result for an Overall struct
type PartialResult struct {
Perfdata perfdata.PerfdataList
Perfdata check.PerfdataList
PartialResults []*PartialResult
Output string

Expand Down Expand Up @@ -183,7 +182,7 @@ func (s *PartialResult) AddSubcheck(subcheck *PartialResult) {

// String returns the status and output of the PartialResult
func (s *PartialResult) String() string {
return fmt.Sprintf("[%s] %s", s.GetStatus(), s.Output)
return fmt.Sprintf("[%s] %s", s.GetStatus(), strings.ReplaceAll(s.Output, check.PerfdataSeparatorSymbol, " "))
}

// SetDefaultState sets a new default state for a PartialResult
Expand Down Expand Up @@ -269,7 +268,7 @@ func (o *Overall) getSummary() string {
checkState := o.GetStatus()

if checkState == check.OK && o.OKSummary != "" {
return o.OKSummary
return strings.ReplaceAll(o.OKSummary, check.PerfdataSeparatorSymbol, " ")
}

if len(o.PartialResults) == 0 {
Expand Down
Loading
Loading