From e976614645aba906a096f4bdf46e09709f71d096 Mon Sep 17 00:00:00 2001 From: mmetc <92726601+mmetc@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:34:12 +0100 Subject: [PATCH] cscli metrics: rename buckets -> scenarios (#2848) * cscli metrics: rename buckets -> scenarios * update lint configuration * lint --- .golangci.yml | 6 +++++- cmd/crowdsec-cli/metrics.go | 20 ++++++++++++-------- cmd/crowdsec-cli/metrics_table.go | 18 ++++++++++++++---- pkg/exprhelpers/exprlib_test.go | 4 ++-- pkg/parser/README.md | 2 +- pkg/setup/README.md | 2 +- 6 files changed, 35 insertions(+), 17 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index e605ac079..29332447b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -73,6 +73,10 @@ linters-settings: - pkg: "github.com/pkg/errors" desc: "errors.Wrap() is deprecated in favor of fmt.Errorf()" + wsl: + # Allow blocks to end with comments + allow-trailing-comment: true + linters: enable-all: true disable: @@ -105,6 +109,7 @@ linters: # - durationcheck # check for two durations multiplied together # - errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases # - errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13. + # - execinquery # execinquery is a linter about query string checker in Query function which reads your Go src files and warning it finds # - exportloopref # checks for pointers to enclosing loop variables # - funlen # Tool for detection of long functions # - ginkgolinter # enforces standards of using ginkgo and gomega @@ -203,7 +208,6 @@ linters: # # Too strict / too many false positives (for now?) # - - execinquery # execinquery is a linter about query string checker in Query function which reads your Go src files and warning it finds - exhaustruct # Checks if all structure fields are initialized - forbidigo # Forbids identifiers - gochecknoglobals # check that no global variables exist diff --git a/cmd/crowdsec-cli/metrics.go b/cmd/crowdsec-cli/metrics.go index 6e23bcf12..0f9234386 100644 --- a/cmd/crowdsec-cli/metrics.go +++ b/cmd/crowdsec-cli/metrics.go @@ -44,9 +44,8 @@ type ( ) var ( - ErrMissingConfig = errors.New("prometheus section missing, can't show metrics") + ErrMissingConfig = errors.New("prometheus section missing, can't show metrics") ErrMetricsDisabled = errors.New("prometheus is not enabled, can't show metrics") - ) type metricSection interface { @@ -59,7 +58,7 @@ type metricStore map[string]metricSection func NewMetricStore() metricStore { return metricStore{ "acquisition": statAcquis{}, - "buckets": statBucket{}, + "scenarios": statBucket{}, "parsers": statParser{}, "lapi": statLapi{}, "lapi-machine": statLapiMachine{}, @@ -110,7 +109,7 @@ func (ms metricStore) Fetch(url string) error { mAcquis := ms["acquisition"].(statAcquis) mParser := ms["parsers"].(statParser) - mBucket := ms["buckets"].(statBucket) + mBucket := ms["scenarios"].(statBucket) mLapi := ms["lapi"].(statLapi) mLapiMachine := ms["lapi-machine"].(statLapiMachine) mLapiBouncer := ms["lapi-bouncer"].(statLapiBouncer) @@ -361,7 +360,7 @@ cscli metrics --url http://lapi.local:6060/metrics show acquisition parsers cscli metrics list`, Args: cobra.ExactArgs(0), DisableAutoGenTag: true, - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(_ *cobra.Command, _ []string) error { return cli.show(nil, url, noUnit) }, } @@ -383,7 +382,7 @@ func (cli *cliMetrics) expandSectionGroups(args []string) []string { for _, section := range args { switch section { case "engine": - ret = append(ret, "acquisition", "parsers", "buckets", "stash", "whitelists") + ret = append(ret, "acquisition", "parsers", "scenarios", "stash", "whitelists") case "lapi": ret = append(ret, "alerts", "decisions", "lapi", "lapi-bouncer", "lapi-decisions", "lapi-machine") case "appsec": @@ -413,10 +412,13 @@ cscli metrics show cscli metrics show engine # Show some specific metrics, show empty tables, connect to a different url -cscli metrics show acquisition parsers buckets stash --url http://lapi.local:6060/metrics +cscli metrics show acquisition parsers scenarios stash --url http://lapi.local:6060/metrics + +# To list available metric types, use "cscli metrics list" +cscli metrics list; cscli metrics list -o json # Show metrics in json format -cscli metrics show acquisition parsers buckets stash -o json`, +cscli metrics show acquisition parsers scenarios stash -o json`, // Positional args are optional DisableAutoGenTag: true, RunE: func(_ *cobra.Command, args []string) error { @@ -467,12 +469,14 @@ func (cli *cliMetrics) list() error { if err != nil { return fmt.Errorf("failed to marshal metric types: %w", err) } + fmt.Println(string(x)) case "raw": x, err := yaml.Marshal(allMetrics) if err != nil { return fmt.Errorf("failed to marshal metric types: %w", err) } + fmt.Println(string(x)) } diff --git a/cmd/crowdsec-cli/metrics_table.go b/cmd/crowdsec-cli/metrics_table.go index da6ea3d9f..689929500 100644 --- a/cmd/crowdsec-cli/metrics_table.go +++ b/cmd/crowdsec-cli/metrics_table.go @@ -1,6 +1,7 @@ package main import ( + "errors" "fmt" "io" "sort" @@ -13,7 +14,7 @@ import ( ) // ErrNilTable means a nil pointer was passed instead of a table instance. This is a programming error. -var ErrNilTable = fmt.Errorf("nil table") +var ErrNilTable = errors.New("nil table") func lapiMetricsToTable(t *table.Table, stats map[string]map[string]map[string]int) int { // stats: machine -> route -> method -> count @@ -44,6 +45,7 @@ func lapiMetricsToTable(t *table.Table, stats map[string]map[string]map[string]i } t.AddRow(row...) + numRows++ } } @@ -82,6 +84,7 @@ func wlMetricsToTable(t *table.Table, stats map[string]map[string]map[string]int } t.AddRow(row...) + numRows++ } } @@ -120,6 +123,7 @@ func metricsToTable(t *table.Table, stats map[string]map[string]int, keys []stri } t.AddRow(row...) + numRows++ } @@ -127,7 +131,7 @@ func metricsToTable(t *table.Table, stats map[string]map[string]int, keys []stri } func (s statBucket) Description() (string, string) { - return "Bucket Metrics", + return "Scenario Metrics", `Measure events in different scenarios. Current count is the number of buckets during metrics collection. ` + `Overflows are past event-producing buckets, while Expired are the ones that didn’t receive enough events to Overflow.` } @@ -143,13 +147,13 @@ func (s statBucket) Process(bucket, metric string, val int) { func (s statBucket) Table(out io.Writer, noUnit bool, showEmpty bool) { t := newTable(out) t.SetRowLines(false) - t.SetHeaders("Bucket", "Current Count", "Overflows", "Instantiated", "Poured", "Expired") + t.SetHeaders("Scenario", "Current Count", "Overflows", "Instantiated", "Poured", "Expired") t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft) keys := []string{"curr_count", "overflow", "instantiation", "pour", "underflow"} if numRows, err := metricsToTable(t, s, keys, noUnit); err != nil { - log.Warningf("while collecting bucket stats: %s", err) + log.Warningf("while collecting scenario stats: %s", err) } else if numRows > 0 || showEmpty { title, _ := s.Description() renderTableTitle(out, "\n"+title+":") @@ -352,6 +356,7 @@ func (s statStash) Table(out io.Writer, noUnit bool, showEmpty bool) { strconv.Itoa(astats.Count), } t.AddRow(row...) + numRows++ } @@ -400,7 +405,9 @@ func (s statLapi) Table(out io.Writer, noUnit bool, showEmpty bool) { sl, strconv.Itoa(astats[sl]), } + t.AddRow(row...) + numRows++ } } @@ -515,6 +522,7 @@ func (s statLapiDecision) Table(out io.Writer, noUnit bool, showEmpty bool) { strconv.Itoa(hits.Empty), strconv.Itoa(hits.NonEmpty), ) + numRows++ } @@ -560,6 +568,7 @@ func (s statDecision) Table(out io.Writer, noUnit bool, showEmpty bool) { action, strconv.Itoa(hits), ) + numRows++ } } @@ -594,6 +603,7 @@ func (s statAlert) Table(out io.Writer, noUnit bool, showEmpty bool) { scenario, strconv.Itoa(hits), ) + numRows++ } diff --git a/pkg/exprhelpers/exprlib_test.go b/pkg/exprhelpers/exprlib_test.go index 6b9cd15c7..9d5a6556b 100644 --- a/pkg/exprhelpers/exprlib_test.go +++ b/pkg/exprhelpers/exprlib_test.go @@ -200,7 +200,7 @@ func TestDistanceHelper(t *testing.T) { ret, err := expr.Run(vm, env) if test.valid { require.NoError(t, err) - assert.Equal(t, test.dist, ret) + assert.InDelta(t, test.dist, ret, 0.000001) } else { require.Error(t, err) } @@ -592,7 +592,7 @@ func TestAtof(t *testing.T) { require.NoError(t, err) output, err := expr.Run(program, test.env) require.NoError(t, err) - require.Equal(t, test.result, output) + require.InDelta(t, test.result, output, 0.000001) } } diff --git a/pkg/parser/README.md b/pkg/parser/README.md index 62a56e618..0fcccc811 100644 --- a/pkg/parser/README.md +++ b/pkg/parser/README.md @@ -45,7 +45,7 @@ statics: > `filter: "Line.Src endsWith '/foobar'"` - - *optional* `filter` : an [expression](https://github.com/antonmedv/expr/blob/master/docs/Language-Definition.md) that will be evaluated against the runtime of a line (`Event`) + - *optional* `filter` : an [expression](https://github.com/antonmedv/expr/blob/master/docs/language-definition.md) that will be evaluated against the runtime of a line (`Event`) - if the `filter` is present and returns false, node is not evaluated - if `filter` is absent or present and returns true, node is evaluated diff --git a/pkg/setup/README.md b/pkg/setup/README.md index 3585ee8b1..9cdc72439 100644 --- a/pkg/setup/README.md +++ b/pkg/setup/README.md @@ -129,7 +129,7 @@ services: and must all return true for a service to be detected (implied *and* clause, no short-circuit). A missing or empty `when:` section is evaluated as true. The [expression -engine](https://github.com/antonmedv/expr/blob/master/docs/Language-Definition.md) +engine](https://github.com/antonmedv/expr/blob/master/docs/language-definition.md) is the same one used by CrowdSec parser filters. You can force the detection of a process by using the `cscli setup detect... --force-process ` flag. It will always behave as if `` was running.