diff --git a/cmd/alert.go b/cmd/alert.go index 9286572..07b92b9 100644 --- a/cmd/alert.go +++ b/cmd/alert.go @@ -9,8 +9,7 @@ import ( "github.com/NETWAYS/check_prometheus/internal/alert" "github.com/NETWAYS/go-check" - "github.com/NETWAYS/go-check/perfdata" - "github.com/NETWAYS/go-check/result" + goresult "github.com/NETWAYS/go-check/result" "github.com/prometheus/common/model" "github.com/spf13/cobra" ) @@ -88,7 +87,7 @@ inactive = 0`, // If there are no rules we can exit early if len(rules) == 0 { // Just an empty PerfdataList to have consistent perfdata output - pdlist := perfdata.PerfdataList{ + pdlist := check.PerfdataList{ {Label: "total", Value: 0}, {Label: "firing", Value: 0}, {Label: "pending", Value: 0}, @@ -98,10 +97,10 @@ inactive = 0`, // Since the user is expecting the state of a certain alert and // it that is not present it might be noteworthy. if cliAlertConfig.AlertName != nil { - check.ExitRaw(check.Unknown, "No such alert defined", "|", pdlist.String()) + check.ExitWithPerfdata(check.Unknown, pdlist, "No such alert defined") } - check.ExitRaw(noAlertsState, "No alerts defined", "|", pdlist.String()) + check.ExitWithPerfdata(noAlertsState, pdlist, "No alerts defined") } // Set initial capacity to reduce memory allocations @@ -110,7 +109,7 @@ inactive = 0`, l *= len(rl.AlertingRule.Alerts) } - var overall result.Overall + var overall goresult.Overall for _, rl := range rules { // If it's not the Alert we're looking for, Skip! @@ -128,7 +127,7 @@ inactive = 0`, alertMatchedExclude, regexErr := matches(rl.AlertingRule.Name, cliAlertConfig.ExcludeAlerts) if regexErr != nil { - check.ExitRaw(check.Unknown, "Invalid regular expression provided:", regexErr.Error()) + check.Exit(check.Unknown, "Invalid regular expression provided:", regexErr.Error()) } if alertMatchedExclude { @@ -140,7 +139,7 @@ inactive = 0`, labelsMatchedExclude, regexErr := matchesLabel(rl.AlertingRule.Labels, cliAlertConfig.ExcludeLabels) if regexErr != nil { - check.ExitRaw(check.Unknown, "Invalid regular expression provided:", regexErr.Error()) + check.Exit(check.Unknown, "Invalid regular expression provided:", regexErr.Error()) } if len(cliAlertConfig.ExcludeLabels) > 0 && labelsMatchedExclude { @@ -152,6 +151,7 @@ inactive = 0`, if len(rl.AlertingRule.Alerts) == 0 { // Counting states for perfdata. We don't use the state-label override here // to have the acutal count from Prometheus + //nolint: exhaustive switch rl.GetStatus("") { case 0: counterInactive++ @@ -161,7 +161,7 @@ inactive = 0`, counterFiring++ } - sc := result.NewPartialResult() + sc := goresult.NewPartialResult() rlStatus := rl.GetStatus(cliAlertConfig.StateLabelKey) // If the negate flag is set we negate this state @@ -169,8 +169,8 @@ inactive = 0`, rlStatus = negateStatus(rlStatus) } - _ = sc.SetState(rlStatus) - sc.Output = rl.GetOutput() + sc.SetState(rlStatus) + sc.SetOutput(rl.GetOutput()) overall.AddSubcheck(sc) } @@ -180,6 +180,7 @@ inactive = 0`, for _, alert := range rl.AlertingRule.Alerts { // Counting states for perfdata. We don't use the state-label override here // to have the acutal count from Prometheus + //nolint: exhaustive switch rl.GetStatus("") { case 0: counterInactive++ @@ -192,7 +193,7 @@ inactive = 0`, labelsMatchedInclude, regexErr := matchesLabel(alert.Labels, cliAlertConfig.IncludeLabels) if regexErr != nil { - check.ExitRaw(check.Unknown, "Invalid regular expression provided:", regexErr.Error()) + check.Exit(check.Unknown, "Invalid regular expression provided:", regexErr.Error()) } if len(cliAlertConfig.IncludeLabels) > 0 && !labelsMatchedInclude { @@ -203,7 +204,7 @@ inactive = 0`, labelsMatchedExclude, regexErr := matchesLabel(alert.Labels, cliAlertConfig.ExcludeLabels) if regexErr != nil { - check.ExitRaw(check.Unknown, "Invalid regular expression provided:", regexErr.Error()) + check.Exit(check.Unknown, "Invalid regular expression provided:", regexErr.Error()) } if len(cliAlertConfig.ExcludeLabels) > 0 && labelsMatchedExclude { @@ -211,7 +212,7 @@ inactive = 0`, continue } - sc := result.NewPartialResult() + sc := goresult.NewPartialResult() rlStatus := rl.GetStatus(cliAlertConfig.StateLabelKey) // If the negate flag is set we negate this state @@ -219,10 +220,10 @@ inactive = 0`, rlStatus = negateStatus(rlStatus) } - _ = sc.SetState(rlStatus) + sc.SetState(rlStatus) // Set the alert in the internal Type to generate the output rl.Alert = alert - sc.Output = rl.GetOutput() + sc.SetOutput(rl.GetOutput()) overall.AddSubcheck(sc) } } @@ -230,7 +231,7 @@ inactive = 0`, counterAlert := counterFiring + counterPending + counterInactive - perfList := perfdata.PerfdataList{ + perfList := check.PerfdataList{ {Label: "total", Value: counterAlert}, {Label: "firing", Value: counterFiring}, {Label: "pending", Value: counterPending}, @@ -238,24 +239,20 @@ inactive = 0`, } // When there are no alerts we add an empty PartialResult just to have consistent output - if len(overall.PartialResults) == 0 { - sc := result.NewPartialResult() - // We already make sure it's valid - //nolint: errcheck + if l == 0 { + sc := goresult.NewPartialResult() sc.SetDefaultState(noAlertsState) - sc.Output = "No alerts retrieved" + sc.SetOutput("No alerts retrieved") overall.AddSubcheck(sc) } - overall.PartialResults[0].Perfdata = append(overall.PartialResults[0].Perfdata, perfList...) - - overall.Summary = fmt.Sprintf("%d Alerts: %d Firing - %d Pending - %d Inactive", + overall.SetOKSummary(fmt.Sprintf("%d Alerts: %d Firing - %d Pending - %d Inactive", counterAlert, counterFiring, counterPending, - counterInactive) + counterInactive)) - check.ExitRaw(overall.GetStatus(), overall.GetOutput()) + check.ExitWithPerfdata(overall.GetStatus(), perfList, overall.GetOutput()) }, } @@ -300,7 +297,7 @@ func init() { } // Function to convert state to integer. -func convertStateToInt(state string) (int, error) { +func convertStateToInt(state string) (check.Status, error) { state = strings.ToUpper(state) switch state { case "OK", "0": @@ -364,7 +361,7 @@ func matchesLabel(labels model.LabelSet, labelsToMatch []string) (bool, error) { } // negateStatus turns an OK state into critical and a warning/critical state into OK -func negateStatus(state int) int { +func negateStatus(state check.Status) check.Status { switch state { case check.OK: return check.Critical diff --git a/cmd/alert_test.go b/cmd/alert_test.go index edd11fb..bc4e8e1 100644 --- a/cmd/alert_test.go +++ b/cmd/alert_test.go @@ -49,7 +49,7 @@ func TestAlertCmd(t *testing.T) { w.Write([]byte(`{"status":"success","data":{"groups":[]}}`)) })), args: []string{"run", "../main.go", "alert"}, - expected: "[OK] - No alerts defined | total=0 firing=0 pending=0 inactive=0\n", + expected: "[OK] - No alerts defined|total=0 firing=0 pending=0 inactive=0\n", }, { name: "alert-none-with-problems", @@ -58,7 +58,7 @@ func TestAlertCmd(t *testing.T) { w.Write([]byte(`{"status":"success","data":{"groups":[]}}`)) })), args: []string{"run", "../main.go", "alert", "--problems"}, - expected: "[OK] - No alerts defined | total=0 firing=0 pending=0 inactive=0\n", + expected: "[OK] - No alerts defined|total=0 firing=0 pending=0 inactive=0\n", }, { name: "alert-none-with-no-state", @@ -67,7 +67,7 @@ func TestAlertCmd(t *testing.T) { w.Write([]byte(`{"status":"success","data":{"groups":[]}}`)) })), args: []string{"run", "../main.go", "alert", "--no-alerts-state", "3"}, - expected: "[UNKNOWN] - No alerts defined | total=0 firing=0 pending=0 inactive=0\nexit status 3\n", + expected: "[UNKNOWN] - No alerts defined|total=0 firing=0 pending=0 inactive=0\nexit status 3\n", }, { name: "alert-none-with-name", @@ -76,7 +76,7 @@ func TestAlertCmd(t *testing.T) { w.Write([]byte(`{"status":"success","data":{"groups":[]}}`)) })), args: []string{"run", "../main.go", "alert", "--name", "MyPreciousAlert"}, - expected: "[UNKNOWN] - No such alert defined | total=0 firing=0 pending=0 inactive=0\nexit status 3\n", + expected: "[UNKNOWN] - No such alert defined|total=0 firing=0 pending=0 inactive=0\nexit status 3\n", }, { name: "alert-default", diff --git a/cmd/health.go b/cmd/health.go index 07f65bd..dded767 100644 --- a/cmd/health.go +++ b/cmd/health.go @@ -21,9 +21,7 @@ Ready: Checks the readiness of an endpoint, which returns OK if the Prometheus s $ check_prometheus --bearer secrettoken health --ready OK - Prometheus Server is Ready. | statuscode=200`, Run: func(_ *cobra.Command, _ []string) { - var ( - rc int - ) + var rc check.Status overall := result.Overall{} @@ -49,11 +47,11 @@ Ready: Checks the readiness of an endpoint, which returns OK if the Prometheus s partialResult := result.NewPartialResult() - _ = partialResult.SetState(rc) - partialResult.Output = output + partialResult.SetState(rc) + partialResult.SetOutput(output) overall.AddSubcheck(partialResult) - check.ExitRaw(overall.GetStatus(), overall.GetOutput()) + check.Exit(overall.GetStatus(), overall.GetOutput()) } if cliConfig.Info { @@ -65,18 +63,18 @@ Ready: Checks the readiness of an endpoint, which returns OK if the Prometheus s partialResult := result.NewPartialResult() - _ = partialResult.SetState(rc) + partialResult.SetState(rc) - partialResult.Output = "Prometheus Server information\n\n" + + partialResult.SetOutput("Prometheus Server information\n\n" + "Version: " + info.Version + "\n" + "Branch: " + info.Branch + "\n" + "BuildDate: " + info.BuildDate + "\n" + "BuildUser: " + info.BuildUser + "\n" + - "Revision: " + info.Revision + "Revision: " + info.Revision) overall.AddSubcheck(partialResult) - check.ExitRaw(overall.GetStatus(), overall.GetOutput()) + check.Exit(overall.GetStatus(), overall.GetOutput()) } // Getting the health status is the default @@ -87,11 +85,11 @@ Ready: Checks the readiness of an endpoint, which returns OK if the Prometheus s } partialResult := result.NewPartialResult() - _ = partialResult.SetState(rc) - partialResult.Output = output + partialResult.SetState(rc) + partialResult.SetOutput(output) overall.AddSubcheck(partialResult) - check.ExitRaw(overall.GetStatus(), overall.GetOutput()) + check.Exit(overall.GetStatus(), overall.GetOutput()) }, } diff --git a/cmd/query.go b/cmd/query.go index 93bc7bc..dd52318 100644 --- a/cmd/query.go +++ b/cmd/query.go @@ -9,7 +9,6 @@ import ( "time" "github.com/NETWAYS/go-check" - "github.com/NETWAYS/go-check/perfdata" goresult "github.com/NETWAYS/go-check/result" "github.com/prometheus/common/model" "github.com/spf13/cobra" @@ -41,9 +40,9 @@ type Number interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 } -func generatePerfdata[T Number](metric string, value T, warning, critical *check.Threshold) perfdata.Perfdata { +func generatePerfdata[T Number](metric string, value T, warning, critical *check.Threshold) check.Perfdata { // We trim the trailing "} from the string, so that the Perfdata won't have a trailing _ - return perfdata.Perfdata{ + return check.Perfdata{ Label: replacer.Replace(metric), Value: value, Warn: warning, @@ -120,15 +119,15 @@ Note: Time range values e.G. 'go_memstats_alloc_bytes_total[0s]' only the latest partial := goresult.NewPartialResult() if crit.DoesViolate(numberValue) { - _ = partial.SetState(check.Critical) + partial.SetState(check.Critical) } else if warn.DoesViolate(numberValue) { - _ = partial.SetState(check.Warning) + partial.SetState(check.Warning) } else { - _ = partial.SetState(check.OK) + partial.SetState(check.OK) } // Format the metric and RC output for console output - partial.Output = generateMetricOutput(sample.Metric.String(), sample.Value.String()) + partial.SetOutput(generateMetricOutput(sample.Metric.String(), sample.Value.String())) // Generate Perfdata from API return if math.IsInf(numberValue, 0) || math.IsNaN(numberValue) { @@ -136,7 +135,7 @@ Note: Time range values e.G. 'go_memstats_alloc_bytes_total[0s]' only the latest } perf := generatePerfdata(sample.Metric.String(), numberValue, warn, crit) - partial.Perfdata.Add(&perf) + partial.AddPerfdata(&perf) overall.AddSubcheck(partial) } @@ -155,15 +154,15 @@ Note: Time range values e.G. 'go_memstats_alloc_bytes_total[0s]' only the latest partial := goresult.NewPartialResult() if crit.DoesViolate(numberValue) { - _ = partial.SetState(check.Critical) + partial.SetState(check.Critical) } else if warn.DoesViolate(numberValue) { - _ = partial.SetState(check.Warning) + partial.SetState(check.Warning) } else { - _ = partial.SetState(check.OK) + partial.SetState(check.OK) } // Format the metric and RC output for console output - partial.Output = generateMetricOutput(samplepair.String(), samplepair.Value.String()) + partial.SetOutput(generateMetricOutput(samplepair.String(), samplepair.Value.String())) valueString := samplepair.Value.String() @@ -173,7 +172,7 @@ Note: Time range values e.G. 'go_memstats_alloc_bytes_total[0s]' only the latest // Generate Perfdata from API return if !math.IsInf(numberValue, 0) && !math.IsNaN(numberValue) { - partial.Perfdata.Add(&pd) + partial.AddPerfdata(&pd) } } @@ -181,12 +180,12 @@ Note: Time range values e.G. 'go_memstats_alloc_bytes_total[0s]' only the latest } } + var appendum string if len(warnings) != 0 { - appendum := fmt.Sprintf("HTTP Warnings: %v", strings.Join(warnings, ", ")) - overall.Summary = overall.GetOutput() + appendum + appendum = fmt.Sprintf("HTTP Warnings: %v", strings.Join(warnings, ", ")) } - check.ExitRaw(overall.GetStatus(), overall.GetOutput()) + check.Exit(overall.GetStatus(), overall.GetOutput(), appendum) }, } diff --git a/cmd/query_test.go b/cmd/query_test.go index c375d85..d3fedbb 100644 --- a/cmd/query_test.go +++ b/cmd/query_test.go @@ -149,7 +149,6 @@ func TestQueryCmd(t *testing.T) { actual := string(out) if actual != test.expected { - // t.Error("\nActual: ", actual, "\nExpected: ", test.expected) t.Error("\nActual: ", actual, "\nExpected: ", test.expected) } @@ -166,7 +165,7 @@ func TestExtendedQueryCmd(t *testing.T) { w.Write([]byte(`{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"up","instance":"localhost:9100","job":"node"},"value":[1696589905.608,"1"]},{"metric":{"__name__":"up","instance":"localhost:9104","job":"mysqld"},"value":[1696589905.608,"99"]},{"metric":{"__name__":"up","instance":"localhost:9117","job":"apache"},"value":[1696589905.608,"1"]}]}}`)) })), args: []string{"run", "../main.go", "query", "--query", "up", "-w", "100", "-c", "200"}, - expected: "OK] - states: ok=3\n\\_ [OK] up{instance=\"localhost:9100\", job=\"node\"} - value: 1\n\\_ [OK] up{instance=\"localhost:9104\", job=\"mysqld\"} - value: 99\n\\_ [OK] up{instance=\"localhost:9117\", job=\"apache\"} - value: 1\n|up_instance_localhost:9100_job_node=1;100;200 up_instance_localhost:9104_job_mysqld=99;100;200 up_instance_localhost:9117_job_apache=1;100;200\n\n", + expected: "[OK] - states: ok=3\n\\_ [OK] up{instance=\"localhost:9100\", job=\"node\"} - value: 1\n\\_ [OK] up{instance=\"localhost:9104\", job=\"mysqld\"} - value: 99\n\\_ [OK] up{instance=\"localhost:9117\", job=\"apache\"} - value: 1\n|up_instance_localhost:9100_job_node=1;100;200 up_instance_localhost:9104_job_mysqld=99;100;200 up_instance_localhost:9117_job_apache=1;100;200\n\n", }, { name: "vector-multiple-critical", diff --git a/go.mod b/go.mod index 2d5e5bf..6049197 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,9 @@ module github.com/NETWAYS/check_prometheus -go 1.25.0 +go 1.26 require ( - github.com/NETWAYS/go-check v0.6.4 + github.com/NETWAYS/go-check v1.0.0 github.com/prometheus/client_golang v1.23.2 github.com/prometheus/common v0.69.0 github.com/spf13/cobra v1.10.2 diff --git a/go.sum b/go.sum index 995ae6a..9db4663 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/NETWAYS/go-check v0.6.4 h1:4WETSVNZNEP0Yudcp5xlvxq6RGn920cmUKq4fz/P1GQ= -github.com/NETWAYS/go-check v0.6.4/go.mod h1:8/GWnq8SirreAixgRmcp82JG16NnEl38rHq9phICy9s= +github.com/NETWAYS/go-check v1.0.0 h1:YkzTwFfGR+Z+mK3Wsqpnu8wibzsB30im19iPNfCOsMQ= +github.com/NETWAYS/go-check v1.0.0/go.mod h1:8/GWnq8SirreAixgRmcp82JG16NnEl38rHq9phICy9s= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= diff --git a/internal/alert/alert.go b/internal/alert/alert.go index 742583f..9df9a59 100644 --- a/internal/alert/alert.go +++ b/internal/alert/alert.go @@ -70,7 +70,7 @@ func FlattenRules(groups []v1.RuleGroup, wantedGroups []string, alerts []v1.Aler return rules } -func (a *Rule) GetStatus(labelKey string) (status int) { +func (a *Rule) GetStatus(labelKey string) (status check.Status) { state := a.AlertingRule.State switch state { diff --git a/internal/client/client.go b/internal/client/client.go index cd334f4..91a7b21 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -42,7 +42,7 @@ func (c *Client) Connect() error { return nil } -func (c *Client) GetStatus(ctx context.Context, endpoint string) (returncode int, statuscode int, body string, err error) { +func (c *Client) GetStatus(ctx context.Context, endpoint string) (returncode check.Status, statuscode int, body string, err error) { // Parses the response from the Prometheus /healthy and /ready endpoint // Return: Exit Status Code, HTTP Status Code, HTTP Body, Error // Building the final URL with the endpoint parameter