From 75880cfab952c47c45a05bb016fae9c0399ca307 Mon Sep 17 00:00:00 2001 From: Ahmet Oeztuerk Date: Fri, 29 May 2026 13:41:57 +0200 Subject: [PATCH 1/2] add additional flags to place 'count' and 'problem count' ~ 'failed' perfdata metrics to the front of metrics array. this flag is for CheckData struct prepending is slower than appending if its a long list, so its a flag. behavior is opt-in and not default. toggle this flag for check_service, this was the intended target for this. when each service has its own perfdata metric, the count would be appended to the end and generally truncated in previews. --- pkg/snclient/check_service_linux.go | 2 + pkg/snclient/check_service_windows.go | 2 + pkg/snclient/checkdata.go | 145 ++++++++++++++------------ 3 files changed, 81 insertions(+), 68 deletions(-) diff --git a/pkg/snclient/check_service_linux.go b/pkg/snclient/check_service_linux.go index 635f1db9..5c73ef43 100644 --- a/pkg/snclient/check_service_linux.go +++ b/pkg/snclient/check_service_linux.go @@ -160,7 +160,9 @@ func (l *CheckService) Check(ctx context.Context, snc *Agent, check *CheckData, if len(l.services) == 0 && !check.showAll { check.addCountMetrics = true + check.addCountMetricsToFront = true check.addProblemCountMetrics = true + check.addProblemCountMetricsToFront = true } return check.Finalize() diff --git a/pkg/snclient/check_service_windows.go b/pkg/snclient/check_service_windows.go index d2aa8bc3..7be3ee85 100644 --- a/pkg/snclient/check_service_windows.go +++ b/pkg/snclient/check_service_windows.go @@ -185,7 +185,9 @@ func (l *CheckService) Check(ctx context.Context, _ *Agent, check *CheckData, _ if len(l.services) == 0 && !check.showAll { check.addCountMetrics = true + check.addCountMetricsToFront = true check.addProblemCountMetrics = true + check.addProblemCountMetricsToFront = true } return check.Finalize() diff --git a/pkg/snclient/checkdata.go b/pkg/snclient/checkdata.go index 068ea1fd..0103c14d 100644 --- a/pkg/snclient/checkdata.go +++ b/pkg/snclient/checkdata.go @@ -92,52 +92,54 @@ type CheckAttribute struct { // CheckData contains the runtime data of a generic check plugin type CheckData struct { - noCopy noCopy - name string - description string - docTitle string - usage string - defaultFilter string - conditionAlias map[string]map[string]string // replacement map of equivalent condition values - conditionColAlias map[string][]string // if there are filter for given column, apply to alias columns too - args map[string]CheckArgument - extraArgs map[string]CheckArgument // internal, map of expanded args - argsPassthrough bool // allow arbitrary arguments without complaining about unknown argument - hasArgsSupplied map[string]bool // map which is true if a arg has been specified on the command line - rawArgs []string - filter ConditionList // if set, only show entries matching this filter set - warnThreshold ConditionList - defaultWarning string - critThreshold ConditionList - defaultCritical string - okThreshold ConditionList - detailSyntax string - topSyntax string - okSyntax string - hasArgsFilter bool // will be true if any arg supplied which has isFilter set - emptySyntax string - emptyState int64 - emptyStateSet bool - details map[string]string - listData []map[string]string - listCombine string // join string for detail list - listCombineSet bool // has the listCombine been set by user - showAll bool // flag if check called with show-all - addCountMetrics bool - addProblemCountMetrics bool - result *CheckResult - showHelp ShowHelp - timeout float64 // timeout in seconds - perfConfig []PerfConfig - perfSyntax string - hasInventory InventoryMode - output OutputMode - implemented Implemented - attributes []CheckAttribute - listSorted []string // sort result list by this keys - exampleDefault string - exampleArgs string - timezone *time.Location // timezone used for date output set by --timezone + noCopy noCopy + name string + description string + docTitle string + usage string + defaultFilter string + conditionAlias map[string]map[string]string // replacement map of equivalent condition values + conditionColAlias map[string][]string // if there are filter for given column, apply to alias columns too + args map[string]CheckArgument + extraArgs map[string]CheckArgument // internal, map of expanded args + argsPassthrough bool // allow arbitrary arguments without complaining about unknown argument + hasArgsSupplied map[string]bool // map which is true if a arg has been specified on the command line + rawArgs []string + filter ConditionList // if set, only show entries matching this filter set + warnThreshold ConditionList + defaultWarning string + critThreshold ConditionList + defaultCritical string + okThreshold ConditionList + detailSyntax string + topSyntax string + okSyntax string + hasArgsFilter bool // will be true if any arg supplied which has isFilter set + emptySyntax string + emptyState int64 + emptyStateSet bool + details map[string]string + listData []map[string]string + listCombine string // join string for detail list + listCombineSet bool // has the listCombine been set by user + showAll bool // flag if check called with show-all + addCountMetrics bool + addCountMetricsToFront bool + addProblemCountMetrics bool + addProblemCountMetricsToFront bool + result *CheckResult + showHelp ShowHelp + timeout float64 // timeout in seconds + perfConfig []PerfConfig + perfSyntax string + hasInventory InventoryMode + output OutputMode + implemented Implemented + attributes []CheckAttribute + listSorted []string // sort result list by this keys + exampleDefault string + exampleArgs string + timezone *time.Location // timezone used for date output set by --timezone } func (cd *CheckData) Finalize() (*CheckResult, error) { @@ -388,29 +390,36 @@ func (cd *CheckData) buildListMacrosFromSingleEntry() map[string]string { } func (cd *CheckData) buildCountMetrics(listLen, critLen, warnLen int) { - if cd.addCountMetrics { - cd.result.Metrics = append( - cd.result.Metrics, - &CheckMetric{ - Name: "count", - Value: listLen, - Warning: cd.warnThreshold, - Critical: cd.critThreshold, - Min: &Zero, - }, - ) - } + // prepending is slower, so keep separate flags for adding to front + if cd.addProblemCountMetrics { - cd.result.Metrics = append( - cd.result.Metrics, - &CheckMetric{ - Name: "failed", - Value: critLen + warnLen, - Warning: cd.warnThreshold, - Critical: cd.critThreshold, - Min: &Zero, - }, - ) + metric := &CheckMetric{ + Name: "failed", + Value: critLen + warnLen, + Warning: cd.warnThreshold, + Critical: cd.critThreshold, + Min: &Zero, + } + if cd.addProblemCountMetricsToFront { + cd.result.Metrics = append([]*CheckMetric{metric}, cd.result.Metrics...) + } else { + cd.result.Metrics = append(cd.result.Metrics, metric) + } + } + + if cd.addCountMetrics { + metric := &CheckMetric{ + Name: "count", + Value: listLen, + Warning: cd.warnThreshold, + Critical: cd.critThreshold, + Min: &Zero, + } + if cd.addCountMetricsToFront { + cd.result.Metrics = append([]*CheckMetric{metric}, cd.result.Metrics...) + } else { + cd.result.Metrics = append(cd.result.Metrics, metric) + } } } From d754ee8b2557b30b880bc68a9168f6598db86234 Mon Sep 17 00:00:00 2001 From: Ahmet Oeztuerk Date: Fri, 29 May 2026 14:35:43 +0200 Subject: [PATCH 2/2] if "count" is used in thresholds, stop adding all services individually in perfdata as metric if count is not used, it adds all serices individually --- pkg/snclient/check_service_linux.go | 5 ++++- pkg/snclient/check_service_windows.go | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pkg/snclient/check_service_linux.go b/pkg/snclient/check_service_linux.go index 5c73ef43..d624ca18 100644 --- a/pkg/snclient/check_service_linux.go +++ b/pkg/snclient/check_service_linux.go @@ -212,7 +212,10 @@ func (l *CheckService) addService(ctx context.Context, check *CheckData, service check.listData = append(check.listData, listEntry) - l.addServiceMetrics(service, l.svcStateFloat(listEntry["state"]), check, listEntry) + // if the count is in a condition, we do not want to add services individually to perfdata + if !check.HasThreshold("count") { + l.addServiceMetrics(service, l.svcStateFloat(listEntry["state"]), check, listEntry) + } return nil } diff --git a/pkg/snclient/check_service_windows.go b/pkg/snclient/check_service_windows.go index 7be3ee85..ef259984 100644 --- a/pkg/snclient/check_service_windows.go +++ b/pkg/snclient/check_service_windows.go @@ -262,7 +262,10 @@ func (l *CheckService) addService(ctx context.Context, check *CheckData, ctrlMgr check.listData = append(check.listData, listEntry) - l.addServiceMetrics(service, float64(details.Status.State), check, listEntry) + // if the count is in a condition, we do not want to add services individually to perfdata + if !check.HasThreshold("count") { + l.addServiceMetrics(service, float64(details.Status.State), check, listEntry) + } return nil }