// Package `perfdata` provides representations for a monitoring plugin's // performance data. package perfdata // import nocternity.net/gomonop/pkg/perfdata import ( "fmt" "regexp" "strings" ) // Units of measurement, which may be used to qualify the performance data. type UnitOfMeasurement int const ( UomNone UnitOfMeasurement = iota UomSeconds UomPercent UomBytes UomKilobytes UomMegabytes UomGigabytes UomTerabytes UomCounter ) func (u UnitOfMeasurement) String() string { return [...]string{"", "s", "%", "B", "KB", "MB", "GB", "TB", "c"}[u] } // Flags indicating which elements of performance data have been set. type perfDataBits int const ( PDatWarn perfDataBits = 1 << iota PDatCrit PDatMin PDatMax ) // Regexps used to check values and ranges in performance data records. var ( // 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 + `|^~$`) ) // Performance data range. type PDRange struct { start string end string inside bool } // Creates a performance data range from -inf to 0 and from the specified // value to +inf. func PDRMax(max string) *PDRange { if !valueCheck.MatchString(max) { panic("invalid performance data range maximum value") } pdRange := &PDRange{} pdRange.start = "0" pdRange.end = max return pdRange } // Creates a performance data range from -inf to the specified minimal value // and from the specified maximal value to +inf. func PDRMinMax(min, max string) *PDRange { if !valueCheck.MatchString(max) { panic("invalid performance data range maximum value") } if !rangeMinCheck.MatchString(min) { panic("invalid performance data range minimum value") } pdRange := &PDRange{} pdRange.start = min pdRange.end = max return pdRange } // Inverts the range. func (r *PDRange) Inside() *PDRange { r.inside = true return r } // Generates the range's string representation so it can be sent to the // monitoring system. func (r *PDRange) String() string { var start, inside string switch r.start { case "": start = "~" case "0": start = "" default: start = r.start } if r.inside { inside = "@" } return inside + start + ":" + r.end } // Performance data, including a label, units, a value, warning/critical // ranges and min/max boundaries. type PerfData struct { Label string units UnitOfMeasurement bits perfDataBits value string warn, crit PDRange min, max string } // Create performance data using the specified label and units. func New(label string, units UnitOfMeasurement, value string) *PerfData { if value != "" && !valueCheck.MatchString(value) { panic("invalid value") } pdRange := &PerfData{} pdRange.Label = label pdRange.units = units if value == "" { pdRange.value = "U" } else { pdRange.value = value } return pdRange } // Set the warning range for the performance data record. func (d *PerfData) SetWarn(r *PDRange) { d.warn = *r d.bits |= PDatWarn } // Set the critical range for the performance data record. func (d *PerfData) SetCrit(r *PDRange) { d.crit = *r d.bits |= PDatCrit } // Set the performance data's minimal value. func (d *PerfData) SetMin(min string) { if !valueCheck.MatchString(min) { panic("invalid value") } d.min = min d.bits |= PDatMin } // Set the performance data's maximal value. func (d *PerfData) SetMax(max string) { if !valueCheck.MatchString(max) { panic("invalid value") } d.max = max d.bits |= PDatMax } // Converts performance data to a string which may be read by the monitoring // system. func (d *PerfData) String() string { var strBuilder strings.Builder needsQuotes := strings.ContainsAny(d.Label, " '=\"") if needsQuotes { strBuilder.WriteString("'") } strBuilder.WriteString(strings.ReplaceAll(d.Label, "'", "''")) if needsQuotes { strBuilder.WriteString("'") } strBuilder.WriteString("=") strBuilder.WriteString(fmt.Sprintf("%s%s;", d.value, d.units.String())) if d.bits&PDatWarn != 0 { strBuilder.WriteString(d.warn.String()) } strBuilder.WriteString(";") if d.bits&PDatCrit != 0 { strBuilder.WriteString(d.crit.String()) } strBuilder.WriteString(";") if d.bits&PDatMin != 0 { strBuilder.WriteString(d.min) } strBuilder.WriteString(";") if d.bits&PDatMax != 0 { strBuilder.WriteString(d.max) } return strBuilder.String() }