cscli metrics: rename buckets -> scenarios (#2848)

* cscli metrics: rename buckets -> scenarios
* update lint configuration
* lint
This commit is contained in:
mmetc 2024-02-15 14:34:12 +01:00 committed by GitHub
parent 717fc97ca0
commit e976614645
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 35 additions and 17 deletions

View file

@ -73,6 +73,10 @@ linters-settings:
- pkg: "github.com/pkg/errors" - pkg: "github.com/pkg/errors"
desc: "errors.Wrap() is deprecated in favor of fmt.Errorf()" desc: "errors.Wrap() is deprecated in favor of fmt.Errorf()"
wsl:
# Allow blocks to end with comments
allow-trailing-comment: true
linters: linters:
enable-all: true enable-all: true
disable: disable:
@ -105,6 +109,7 @@ linters:
# - durationcheck # check for two durations multiplied together # - 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 # - 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. # - 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 # - exportloopref # checks for pointers to enclosing loop variables
# - funlen # Tool for detection of long functions # - funlen # Tool for detection of long functions
# - ginkgolinter # enforces standards of using ginkgo and gomega # - ginkgolinter # enforces standards of using ginkgo and gomega
@ -203,7 +208,6 @@ linters:
# #
# Too strict / too many false positives (for now?) # 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 - exhaustruct # Checks if all structure fields are initialized
- forbidigo # Forbids identifiers - forbidigo # Forbids identifiers
- gochecknoglobals # check that no global variables exist - gochecknoglobals # check that no global variables exist

View file

@ -46,7 +46,6 @@ type (
var ( 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") ErrMetricsDisabled = errors.New("prometheus is not enabled, can't show metrics")
) )
type metricSection interface { type metricSection interface {
@ -59,7 +58,7 @@ type metricStore map[string]metricSection
func NewMetricStore() metricStore { func NewMetricStore() metricStore {
return metricStore{ return metricStore{
"acquisition": statAcquis{}, "acquisition": statAcquis{},
"buckets": statBucket{}, "scenarios": statBucket{},
"parsers": statParser{}, "parsers": statParser{},
"lapi": statLapi{}, "lapi": statLapi{},
"lapi-machine": statLapiMachine{}, "lapi-machine": statLapiMachine{},
@ -110,7 +109,7 @@ func (ms metricStore) Fetch(url string) error {
mAcquis := ms["acquisition"].(statAcquis) mAcquis := ms["acquisition"].(statAcquis)
mParser := ms["parsers"].(statParser) mParser := ms["parsers"].(statParser)
mBucket := ms["buckets"].(statBucket) mBucket := ms["scenarios"].(statBucket)
mLapi := ms["lapi"].(statLapi) mLapi := ms["lapi"].(statLapi)
mLapiMachine := ms["lapi-machine"].(statLapiMachine) mLapiMachine := ms["lapi-machine"].(statLapiMachine)
mLapiBouncer := ms["lapi-bouncer"].(statLapiBouncer) mLapiBouncer := ms["lapi-bouncer"].(statLapiBouncer)
@ -361,7 +360,7 @@ cscli metrics --url http://lapi.local:6060/metrics show acquisition parsers
cscli metrics list`, cscli metrics list`,
Args: cobra.ExactArgs(0), Args: cobra.ExactArgs(0),
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(_ *cobra.Command, _ []string) error {
return cli.show(nil, url, noUnit) return cli.show(nil, url, noUnit)
}, },
} }
@ -383,7 +382,7 @@ func (cli *cliMetrics) expandSectionGroups(args []string) []string {
for _, section := range args { for _, section := range args {
switch section { switch section {
case "engine": case "engine":
ret = append(ret, "acquisition", "parsers", "buckets", "stash", "whitelists") ret = append(ret, "acquisition", "parsers", "scenarios", "stash", "whitelists")
case "lapi": case "lapi":
ret = append(ret, "alerts", "decisions", "lapi", "lapi-bouncer", "lapi-decisions", "lapi-machine") ret = append(ret, "alerts", "decisions", "lapi", "lapi-bouncer", "lapi-decisions", "lapi-machine")
case "appsec": case "appsec":
@ -413,10 +412,13 @@ cscli metrics show
cscli metrics show engine cscli metrics show engine
# Show some specific metrics, show empty tables, connect to a different url # 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 # 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 // Positional args are optional
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(_ *cobra.Command, args []string) error { RunE: func(_ *cobra.Command, args []string) error {
@ -467,12 +469,14 @@ func (cli *cliMetrics) list() error {
if err != nil { if err != nil {
return fmt.Errorf("failed to marshal metric types: %w", err) return fmt.Errorf("failed to marshal metric types: %w", err)
} }
fmt.Println(string(x)) fmt.Println(string(x))
case "raw": case "raw":
x, err := yaml.Marshal(allMetrics) x, err := yaml.Marshal(allMetrics)
if err != nil { if err != nil {
return fmt.Errorf("failed to marshal metric types: %w", err) return fmt.Errorf("failed to marshal metric types: %w", err)
} }
fmt.Println(string(x)) fmt.Println(string(x))
} }

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"sort" "sort"
@ -13,7 +14,7 @@ import (
) )
// ErrNilTable means a nil pointer was passed instead of a table instance. This is a programming error. // 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 { func lapiMetricsToTable(t *table.Table, stats map[string]map[string]map[string]int) int {
// stats: machine -> route -> method -> count // 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...) t.AddRow(row...)
numRows++ numRows++
} }
} }
@ -82,6 +84,7 @@ func wlMetricsToTable(t *table.Table, stats map[string]map[string]map[string]int
} }
t.AddRow(row...) t.AddRow(row...)
numRows++ numRows++
} }
} }
@ -120,6 +123,7 @@ func metricsToTable(t *table.Table, stats map[string]map[string]int, keys []stri
} }
t.AddRow(row...) t.AddRow(row...)
numRows++ numRows++
} }
@ -127,7 +131,7 @@ func metricsToTable(t *table.Table, stats map[string]map[string]int, keys []stri
} }
func (s statBucket) Description() (string, string) { 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. ` + `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 didnt receive enough events to Overflow.` `Overflows are past event-producing buckets, while Expired are the ones that didnt 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) { func (s statBucket) Table(out io.Writer, noUnit bool, showEmpty bool) {
t := newTable(out) t := newTable(out)
t.SetRowLines(false) 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) t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft)
keys := []string{"curr_count", "overflow", "instantiation", "pour", "underflow"} keys := []string{"curr_count", "overflow", "instantiation", "pour", "underflow"}
if numRows, err := metricsToTable(t, s, keys, noUnit); err != nil { 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 { } else if numRows > 0 || showEmpty {
title, _ := s.Description() title, _ := s.Description()
renderTableTitle(out, "\n"+title+":") renderTableTitle(out, "\n"+title+":")
@ -352,6 +356,7 @@ func (s statStash) Table(out io.Writer, noUnit bool, showEmpty bool) {
strconv.Itoa(astats.Count), strconv.Itoa(astats.Count),
} }
t.AddRow(row...) t.AddRow(row...)
numRows++ numRows++
} }
@ -400,7 +405,9 @@ func (s statLapi) Table(out io.Writer, noUnit bool, showEmpty bool) {
sl, sl,
strconv.Itoa(astats[sl]), strconv.Itoa(astats[sl]),
} }
t.AddRow(row...) t.AddRow(row...)
numRows++ numRows++
} }
} }
@ -515,6 +522,7 @@ func (s statLapiDecision) Table(out io.Writer, noUnit bool, showEmpty bool) {
strconv.Itoa(hits.Empty), strconv.Itoa(hits.Empty),
strconv.Itoa(hits.NonEmpty), strconv.Itoa(hits.NonEmpty),
) )
numRows++ numRows++
} }
@ -560,6 +568,7 @@ func (s statDecision) Table(out io.Writer, noUnit bool, showEmpty bool) {
action, action,
strconv.Itoa(hits), strconv.Itoa(hits),
) )
numRows++ numRows++
} }
} }
@ -594,6 +603,7 @@ func (s statAlert) Table(out io.Writer, noUnit bool, showEmpty bool) {
scenario, scenario,
strconv.Itoa(hits), strconv.Itoa(hits),
) )
numRows++ numRows++
} }

View file

@ -200,7 +200,7 @@ func TestDistanceHelper(t *testing.T) {
ret, err := expr.Run(vm, env) ret, err := expr.Run(vm, env)
if test.valid { if test.valid {
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, test.dist, ret) assert.InDelta(t, test.dist, ret, 0.000001)
} else { } else {
require.Error(t, err) require.Error(t, err)
} }
@ -592,7 +592,7 @@ func TestAtof(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
output, err := expr.Run(program, test.env) output, err := expr.Run(program, test.env)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, test.result, output) require.InDelta(t, test.result, output, 0.000001)
} }
} }

View file

@ -45,7 +45,7 @@ statics:
> `filter: "Line.Src endsWith '/foobar'"` > `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 the `filter` is present and returns false, node is not evaluated
- if `filter` is absent or present and returns true, node is evaluated - if `filter` is absent or present and returns true, node is evaluated

View file

@ -129,7 +129,7 @@ services:
and must all return true for a service to be detected (implied *and* clause, no 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. short-circuit). A missing or empty `when:` section is evaluated as true.
The [expression 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 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 <processname>` a process by using the `cscli setup detect... --force-process <processname>`
flag. It will always behave as if `<processname>` was running. flag. It will always behave as if `<processname>` was running.