2021-01-07 20:55:10 +01:00
|
|
|
// Package `perfdata` provides representations for a monitoring plugin's
|
|
|
|
// performance data.
|
2024-07-19 14:55:23 +02:00
|
|
|
package perfdata // import nocternity.net/gomonop/pkg/perfdata
|
2021-01-03 10:33:21 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
2021-01-07 20:55:10 +01:00
|
|
|
// Units of measurement, which may be used to qualify the performance data.
|
2021-01-03 10:33:21 +01:00
|
|
|
type UnitOfMeasurement int
|
|
|
|
|
|
|
|
const (
|
|
|
|
UOM_NONE UnitOfMeasurement = iota
|
|
|
|
UOM_SECONDS
|
|
|
|
UOM_PERCENT
|
|
|
|
UOM_BYTES
|
|
|
|
UOM_KILOBYTES
|
|
|
|
UOM_MEGABYTES
|
|
|
|
UOM_GIGABYTES
|
|
|
|
UOM_TERABYTES
|
|
|
|
UOM_COUNTER
|
|
|
|
)
|
|
|
|
|
|
|
|
func (u UnitOfMeasurement) String() string {
|
|
|
|
return [...]string{"", "s", "%", "B", "KB", "MB", "GB", "TB", "c"}[u]
|
|
|
|
}
|
|
|
|
|
2021-01-07 20:55:10 +01:00
|
|
|
// Flags indicating which elements of performance data have been set.
|
|
|
|
type perfDataBits int
|
2021-01-03 10:33:21 +01:00
|
|
|
|
|
|
|
const (
|
2021-01-07 20:55:10 +01:00
|
|
|
PDAT_WARN perfDataBits = 1 << iota
|
2021-01-03 10:33:21 +01:00
|
|
|
PDAT_CRIT
|
|
|
|
PDAT_MIN
|
|
|
|
PDAT_MAX
|
|
|
|
)
|
|
|
|
|
2021-01-07 20:55:10 +01:00
|
|
|
// Regexps used to check values and ranges in performance data records.
|
2021-01-03 10:33:21 +01:00
|
|
|
var (
|
2021-01-07 20:55:10 +01:00
|
|
|
// Common value check regexp
|
|
|
|
vcRegexp = `^-?(0(\.\d*)?|[1-9]\d*(\.\d*)?|\.\d+)$`
|
|
|
|
// Compiled value check regexp
|
|
|
|
valueCheck = regexp.MustCompile(vcRegexp)
|
|
|
|
// Compiled range min value check
|
|
|
|
rangeMinCheck = regexp.MustCompile(vcRegexp + `|^~$`)
|
2021-01-03 10:33:21 +01:00
|
|
|
)
|
|
|
|
|
2021-01-07 20:55:10 +01:00
|
|
|
// Performance data range
|
2021-01-03 10:33:21 +01:00
|
|
|
type PerfDataRange struct {
|
|
|
|
start string
|
|
|
|
end string
|
|
|
|
inside bool
|
|
|
|
}
|
|
|
|
|
2021-01-07 20:55:10 +01:00
|
|
|
// Creates a performance data range from -inf to 0 and from the specified
|
|
|
|
// value to +inf.
|
2021-01-03 10:33:21 +01:00
|
|
|
func PDRMax(max string) *PerfDataRange {
|
|
|
|
if !valueCheck.MatchString(max) {
|
|
|
|
panic("invalid performance data range maximum value")
|
|
|
|
}
|
2021-01-07 20:55:10 +01:00
|
|
|
r := &PerfDataRange{}
|
2021-01-03 10:33:21 +01:00
|
|
|
r.start = "0"
|
|
|
|
r.end = max
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2021-01-07 20:55:10 +01:00
|
|
|
// Creates a performance data range from -inf to the specified minimal value
|
|
|
|
// and from the specified maximal value to +inf.
|
2021-01-03 10:33:21 +01:00
|
|
|
func PDRMinMax(min, max string) *PerfDataRange {
|
|
|
|
if !valueCheck.MatchString(max) {
|
|
|
|
panic("invalid performance data range maximum value")
|
|
|
|
}
|
|
|
|
if !rangeMinCheck.MatchString(min) {
|
|
|
|
panic("invalid performance data range minimum value")
|
|
|
|
}
|
2021-01-07 20:55:10 +01:00
|
|
|
r := &PerfDataRange{}
|
2021-01-03 10:33:21 +01:00
|
|
|
r.start = min
|
|
|
|
r.end = max
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2021-01-07 20:55:10 +01:00
|
|
|
// Inverts the range.
|
2021-01-03 10:33:21 +01:00
|
|
|
func (r *PerfDataRange) Inside() *PerfDataRange {
|
|
|
|
r.inside = true
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2021-01-07 20:55:10 +01:00
|
|
|
// Generates the range's string representation so it can be sent to the
|
|
|
|
// monitoring system.
|
|
|
|
func (r *PerfDataRange) String() string {
|
2021-01-03 10:33:21 +01:00
|
|
|
var start, inside string
|
|
|
|
if r.start == "" {
|
|
|
|
start = "~"
|
|
|
|
} else if r.start == "0" {
|
|
|
|
start = ""
|
|
|
|
} else {
|
|
|
|
start = r.start
|
|
|
|
}
|
|
|
|
if r.inside {
|
|
|
|
inside = "@"
|
|
|
|
} else {
|
|
|
|
inside = ""
|
|
|
|
}
|
|
|
|
return fmt.Sprintf("%s%s:%s", inside, start, r.end)
|
|
|
|
}
|
|
|
|
|
2021-01-07 20:55:10 +01:00
|
|
|
// Performance data, including a label, units, a value, warning/critical
|
|
|
|
// ranges and min/max boundaries.
|
2021-01-03 10:33:21 +01:00
|
|
|
type PerfData struct {
|
|
|
|
Label string
|
|
|
|
units UnitOfMeasurement
|
2021-01-07 20:55:10 +01:00
|
|
|
bits perfDataBits
|
2021-01-03 10:33:21 +01:00
|
|
|
value string
|
|
|
|
warn, crit PerfDataRange
|
|
|
|
min, max string
|
|
|
|
}
|
|
|
|
|
2021-01-07 20:55:10 +01:00
|
|
|
// Create performance data using the specified label and units.
|
|
|
|
func New(label string, units UnitOfMeasurement, value string) *PerfData {
|
2021-01-03 10:33:21 +01:00
|
|
|
if value != "" && !valueCheck.MatchString(value) {
|
|
|
|
panic("invalid value")
|
|
|
|
}
|
2021-01-07 20:55:10 +01:00
|
|
|
r := &PerfData{}
|
2021-01-03 10:33:21 +01:00
|
|
|
r.Label = label
|
|
|
|
r.units = units
|
|
|
|
if value == "" {
|
|
|
|
r.value = "U"
|
|
|
|
} else {
|
|
|
|
r.value = value
|
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2021-01-07 20:55:10 +01:00
|
|
|
// Set the warning range for the performance data record.
|
2021-01-03 10:33:21 +01:00
|
|
|
func (d *PerfData) SetWarn(r *PerfDataRange) {
|
|
|
|
d.warn = *r
|
|
|
|
d.bits = d.bits | PDAT_WARN
|
|
|
|
}
|
|
|
|
|
2021-01-07 20:55:10 +01:00
|
|
|
// Set the critical range for the performance data record.
|
2021-01-03 10:33:21 +01:00
|
|
|
func (d *PerfData) SetCrit(r *PerfDataRange) {
|
|
|
|
d.crit = *r
|
|
|
|
d.bits = d.bits | PDAT_CRIT
|
|
|
|
}
|
|
|
|
|
2021-01-07 20:55:10 +01:00
|
|
|
// Set the performance data's minimal value
|
2021-01-03 10:33:21 +01:00
|
|
|
func (d *PerfData) SetMin(min string) {
|
|
|
|
if !valueCheck.MatchString(min) {
|
|
|
|
panic("invalid value")
|
|
|
|
}
|
|
|
|
d.min = min
|
|
|
|
d.bits = d.bits | PDAT_MIN
|
|
|
|
}
|
|
|
|
|
2021-01-07 20:55:10 +01:00
|
|
|
// Set the performance data's maximal value.
|
2021-01-03 10:33:21 +01:00
|
|
|
func (d *PerfData) SetMax(max string) {
|
|
|
|
if !valueCheck.MatchString(max) {
|
|
|
|
panic("invalid value")
|
|
|
|
}
|
|
|
|
d.max = max
|
|
|
|
d.bits = d.bits | PDAT_MAX
|
|
|
|
}
|
|
|
|
|
2021-01-07 20:55:10 +01:00
|
|
|
// Converts performance data to a string which may be read by the monitoring
|
|
|
|
// system.
|
|
|
|
func (d *PerfData) String() string {
|
2021-01-03 10:33:21 +01:00
|
|
|
var sb strings.Builder
|
|
|
|
needsQuotes := strings.ContainsAny(d.Label, " '=\"")
|
|
|
|
if needsQuotes {
|
|
|
|
sb.WriteString("'")
|
|
|
|
}
|
|
|
|
sb.WriteString(strings.ReplaceAll(d.Label, "'", "''"))
|
|
|
|
if needsQuotes {
|
|
|
|
sb.WriteString("'")
|
|
|
|
}
|
|
|
|
sb.WriteString("=")
|
|
|
|
sb.WriteString(fmt.Sprintf("%s%s;", d.value, d.units.String()))
|
|
|
|
if d.bits&PDAT_WARN != 0 {
|
|
|
|
sb.WriteString(d.warn.String())
|
|
|
|
}
|
|
|
|
sb.WriteString(";")
|
|
|
|
if d.bits&PDAT_CRIT != 0 {
|
|
|
|
sb.WriteString(d.crit.String())
|
|
|
|
}
|
|
|
|
sb.WriteString(";")
|
|
|
|
if d.bits&PDAT_MIN != 0 {
|
|
|
|
sb.WriteString(d.min)
|
|
|
|
}
|
|
|
|
sb.WriteString(";")
|
|
|
|
if d.bits&PDAT_MAX != 0 {
|
|
|
|
sb.WriteString(d.max)
|
|
|
|
}
|
|
|
|
|
|
|
|
return sb.String()
|
|
|
|
}
|