Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Usage metrics #365

Merged
merged 72 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
e2c6c4e
wip metrics
mmetc Mar 11, 2024
4c5261b
golang.org/x/exp/slices -> slices; drop dependency
mmetc Mar 11, 2024
8cf6979
go mod tidy
mmetc Mar 12, 2024
f8bc039
update metrics model
blotus Apr 22, 2024
4f86e59
update nftables pkg
blotus Apr 22, 2024
e484e80
use nft pkg to get metrics about rules
blotus Apr 22, 2024
aa7eddd
lint
blotus Apr 22, 2024
261f693
nftables: create one rule/set per decision origin
blotus Apr 22, 2024
92eee0a
fix nftables tests
blotus Apr 22, 2024
74222e9
fix nftables tests
blotus Apr 22, 2024
bcb3848
lint
blotus Apr 22, 2024
a3a67ba
lint
blotus Apr 22, 2024
3cab884
send proper metrics
blotus Apr 23, 2024
39698f8
up
blotus Apr 23, 2024
9f988df
lint
blotus Apr 23, 2024
9545c5b
fix origin name for nftables
blotus Jun 14, 2024
6768736
use ipset restore to add ips
blotus Jun 14, 2024
32b849d
up
blotus Jun 25, 2024
659f50d
up
blotus Jul 9, 2024
059a900
send delta metrics
blotus Jul 11, 2024
d6281bb
merge from main
blotus Jul 15, 2024
f19b9f2
update go-cs-bouncer dep
mmetc Jul 15, 2024
60da3ea
docker func test
mmetc Jul 15, 2024
60d9e54
update lint config
mmetc Jul 15, 2024
7782feb
add processed bytes/metrics for nftables
blotus Jul 16, 2024
36eaae4
fix ipset mode
blotus Jul 16, 2024
390bde9
only call ipset restore if needed
blotus Jul 16, 2024
af98783
linter
blotus Jul 16, 2024
5426827
fix tests
blotus Jul 16, 2024
e90389b
Merge branch 'main' into usage-metrics
mmetc Jul 17, 2024
d16cf51
setup tracking chain for global processed bytes/packets
blotus Jul 17, 2024
0e59280
do it for all configured chains
blotus Jul 17, 2024
809a359
store all iptables rules in our own chain for easier management
blotus Jul 18, 2024
865eded
try to increase timeout for tests
blotus Jul 18, 2024
ad49f4a
Merge branch 'main' into usage-metrics
mmetc Jul 18, 2024
c34a688
go mod tidy
mmetc Jul 18, 2024
05de936
emit metrics for iptables
blotus Jul 18, 2024
0c3195d
remove unused type
blotus Jul 18, 2024
d443a9c
do not setup chain when in ipset mode
blotus Jul 18, 2024
71ad36d
update go-cs-bouncer
blotus Jul 22, 2024
1108ac4
send absolute value for active_decisions
blotus Jul 22, 2024
32e5a1c
only compute metrics when requested
blotus Jul 22, 2024
23ee2b3
up
blotus Jul 24, 2024
28b98f5
make linter happy
blotus Aug 16, 2024
dfd41d4
go mod tidy
blotus Aug 16, 2024
df780b2
update deps
blotus Aug 16, 2024
863bfe8
up
blotus Aug 16, 2024
cb05888
up
blotus Aug 16, 2024
c4528d8
remove toolchain pin from go.mod
mmetc Aug 19, 2024
541e172
use go 1.22.6
mmetc Aug 19, 2024
69833b2
update go-cs-bouncer; mod tidy + diff
mmetc Aug 19, 2024
c76de26
Merge branch 'main' into usage-metrics
mmetc Aug 19, 2024
460aaef
1.22
mmetc Aug 19, 2024
6673ccd
increase timeout
blotus Aug 22, 2024
f99d61a
increase timeout
blotus Aug 22, 2024
8400998
update set name in iptables tests
blotus Aug 22, 2024
66ca0f2
properly destroy leftover sets in iptables mode on startup
blotus Aug 22, 2024
45e6086
update test
blotus Aug 22, 2024
efb481f
debug
blotus Aug 22, 2024
2c61972
up
blotus Aug 22, 2024
2087894
up
blotus Aug 22, 2024
77c12c1
up
blotus Aug 22, 2024
22f7788
up
blotus Aug 22, 2024
f5eb4d5
CI: don't pin minor go version
mmetc Aug 23, 2024
8a72046
drop useless error return
blotus Aug 23, 2024
30842eb
remove useless ipsetcmd.Delete
blotus Aug 23, 2024
d5b4668
allow log action
blotus Aug 23, 2024
6b9019f
fix some comments
blotus Aug 23, 2024
e34ed07
fix some comments
blotus Aug 23, 2024
bcb6a05
up
blotus Aug 23, 2024
7ab20c7
better support for metrics in ipset only mode
blotus Sep 16, 2024
7b3e2ef
lint
blotus Sep 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 120 additions & 14 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,21 @@
"net/http"
"os"
"os/signal"
"slices"
"strings"
"syscall"
"time"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
io_prometheus_client "github.com/prometheus/client_model/go"
log "github.com/sirupsen/logrus"
"golang.org/x/exp/slices"
"golang.org/x/sync/errgroup"

csbouncer "github.com/crowdsecurity/go-cs-bouncer"
"github.com/crowdsecurity/go-cs-lib/csdaemon"
"github.com/crowdsecurity/go-cs-lib/csstring"
"github.com/crowdsecurity/go-cs-lib/ptr"
"github.com/crowdsecurity/go-cs-lib/version"

"github.com/crowdsecurity/crowdsec/pkg/models"
Expand All @@ -30,7 +33,9 @@
"github.com/crowdsecurity/cs-firewall-bouncer/pkg/metrics"
)

const name = "crowdsec-firewall-bouncer"
const bouncerType = "crowdsec-firewall-bouncer"

var metricsInterval time.Duration

func backendCleanup(backend *backend.BackendCTX) {
log.Info("Shutting down backend")
Expand Down Expand Up @@ -136,6 +141,98 @@
}
}

func getLabelValue(labels []*io_prometheus_client.LabelPair, key string) string {

for _, label := range labels {
if label.GetName() == key {
return label.GetValue()
}
}

return ""
}

// metricsUpdater receives a metrics struct with basic data and populates it with the current metrics.
func metricsUpdater(met *models.RemediationComponentsMetrics) {
log.Debugf("Updating metrics")

//Most of the common fields are set automatically by the metrics provider
//We only need to care about the metrics themselves

promMetrics, err := prometheus.DefaultGatherer.Gather()

if err != nil {
log.Errorf("unable to gather prometheus metrics: %s", err)
return
}

met.Metrics = append(met.Metrics, &models.DetailedMetrics{
Meta: &models.MetricsMeta{
UtcNowTimestamp: ptr.Of(time.Now().Unix()),
WindowSizeSeconds: ptr.Of(int64(metricsInterval.Seconds())),
},
Items: make([]*models.MetricsDetailItem, 0),
})

for _, metricFamily := range promMetrics {
for _, metric := range metricFamily.GetMetric() {
switch metricFamily.GetName() {
case metrics.ActiveBannedIPsMetricName:
labels := metric.GetLabel()
value := metric.GetGauge().GetValue()
origin := getLabelValue(labels, "origin")
ipType := getLabelValue(labels, "ip_type")
key := origin + ipType
log.Debugf("Sending active decisions for %s %s %f | current value: %f | previous value: %f\n", origin, ipType, value-metrics.LastActiveBannedIPsValue[key], value, metrics.LastActiveBannedIPsValue[key])

Check failure on line 186 in cmd/root.go

View workflow job for this annotation

GitHub Actions / golangci-lint + codeql

line is 205 characters (lll)
met.Metrics[0].Items = append(met.Metrics[0].Items, &models.MetricsDetailItem{
Name: ptr.Of("active_decisions"),
Value: ptr.Of(value - metrics.LastActiveBannedIPsValue[key]),
Labels: map[string]string{
"origin": origin,
"ip_type": ipType,
},
Unit: ptr.Of("ip"),
})
metrics.LastActiveBannedIPsValue[key] = value
case metrics.DroppedBytesMetricName:
labels := metric.GetLabel()
value := metric.GetGauge().GetValue()
origin := getLabelValue(labels, "origin")
ipType := getLabelValue(labels, "ip_type")
key := origin + ipType
log.Debugf("Sending dropped bytes for %s %s %f | current value: %f | previous value: %f\n", origin, ipType, value-metrics.LastDroppedBytesValue[key], value, metrics.LastDroppedBytesValue[key])

Check failure on line 203 in cmd/root.go

View workflow job for this annotation

GitHub Actions / golangci-lint + codeql

line is 196 characters (lll)
met.Metrics[0].Items = append(met.Metrics[0].Items, &models.MetricsDetailItem{
Name: ptr.Of("dropped"),
Value: ptr.Of(value - metrics.LastDroppedBytesValue[key]),
Labels: map[string]string{
"origin": origin,
"ip_type": ipType,
},
Unit: ptr.Of("byte"),
})
metrics.LastDroppedBytesValue[key] = value
case metrics.DroppedPacketsMetricName:
labels := metric.GetLabel()
value := metric.GetGauge().GetValue()
origin := getLabelValue(labels, "origin")
ipType := getLabelValue(labels, "ip_type")
key := origin + ipType
log.Debugf("Sending dropped packets for %s %s %f | current value: %f | previous value: %f\n", origin, ipType, value-metrics.LastDroppedPacketsValue[key], value, metrics.LastDroppedPacketsValue[key])

Check failure on line 220 in cmd/root.go

View workflow job for this annotation

GitHub Actions / golangci-lint + codeql

line is 202 characters (lll)
met.Metrics[0].Items = append(met.Metrics[0].Items, &models.MetricsDetailItem{
Name: ptr.Of("dropped"),
Value: ptr.Of(value - metrics.LastDroppedPacketsValue[key]),
Labels: map[string]string{
"origin": origin,
"ip_type": ipType,
},
Unit: ptr.Of("packet"),
})
metrics.LastDroppedPacketsValue[key] = value
}
}
}
}

func Execute() error {
configPath := flag.String("c", "", "path to crowdsec-firewall-bouncer.yaml")
verbose := flag.Bool("v", false, "set verbose mode")
Expand Down Expand Up @@ -176,7 +273,7 @@
log.SetLevel(log.DebugLevel)
}

log.Infof("Starting crowdsec-firewall-bouncer %s", version.String())
log.Infof("Starting %s %s", bouncerType, version.String())

backend, err := backend.NewBackend(config)
if err != nil {
Expand All @@ -196,7 +293,7 @@
return err
}

bouncer.UserAgent = fmt.Sprintf("%s/%s", name, version.String())
bouncer.UserAgent = fmt.Sprintf("%s/%s", bouncerType, version.String())
if err := bouncer.Init(); err != nil {
return fmt.Errorf("unable to configure bouncer: %w", err)
}
Expand All @@ -217,19 +314,28 @@
return errors.New("bouncer stream halted")
})

if config.PrometheusConfig.Enabled {
if config.Mode == cfg.IptablesMode || config.Mode == cfg.NftablesMode || config.Mode == cfg.IpsetMode || config.Mode == cfg.PfMode {
go backend.CollectMetrics()
metricsInterval = *bouncer.MetricsInterval

if config.Mode == cfg.IpsetMode {
prometheus.MustRegister(metrics.TotalActiveBannedIPs)
} else {
prometheus.MustRegister(metrics.TotalDroppedBytes, metrics.TotalDroppedPackets, metrics.TotalActiveBannedIPs)
}
}
metricsProvider, err := csbouncer.NewMetricsProvider(bouncer.APIClient, bouncerType, metricsInterval, metricsUpdater, log.StandardLogger())
if err != nil {
return fmt.Errorf("unable to create metrics provider: %w", err)
}

g.Go(func() error {
return metricsProvider.Run(ctx)
})

prometheus.MustRegister(csbouncer.TotalLAPICalls, csbouncer.TotalLAPIError)
if config.Mode == cfg.IptablesMode || config.Mode == cfg.NftablesMode || config.Mode == cfg.IpsetMode || config.Mode == cfg.PfMode {
go backend.CollectMetrics()
if config.Mode == cfg.IpsetMode {
prometheus.MustRegister(metrics.TotalActiveBannedIPs)
} else {
prometheus.MustRegister(metrics.TotalDroppedBytes, metrics.TotalDroppedPackets, metrics.TotalActiveBannedIPs)
}
}

prometheus.MustRegister(csbouncer.TotalLAPICalls, csbouncer.TotalLAPIError)
if config.PrometheusConfig.Enabled {
go func() {
http.Handle("/metrics", promhttp.Handler())

Expand Down
28 changes: 15 additions & 13 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
module github.com/crowdsecurity/cs-firewall-bouncer

go 1.21
go 1.22

toolchain go1.22.2

require (
github.com/crowdsecurity/crowdsec v1.6.1
github.com/crowdsecurity/go-cs-bouncer v0.0.13
github.com/crowdsecurity/go-cs-lib v0.0.10
github.com/google/nftables v0.1.1-0.20230710063801-8a10f689006b
github.com/crowdsecurity/crowdsec v1.6.3-0.20240625082021-0bfbd3e2bcd7
github.com/crowdsecurity/go-cs-bouncer v0.0.14-0.20240625082322-2398d05359c7
github.com/crowdsecurity/go-cs-lib v0.0.11
github.com/google/nftables v0.2.0
github.com/prometheus/client_golang v1.17.0
github.com/prometheus/client_model v0.5.0
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.8.4
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
golang.org/x/sync v0.6.0
golang.org/x/sync v0.7.0
golang.org/x/sys v0.19.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v2 v2.4.0
Expand All @@ -21,10 +23,11 @@ require (
github.com/antonmedv/expr v1.15.3 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blackfireio/osinfo v1.0.5 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/go-openapi/analysis v0.21.4 // indirect
github.com/go-openapi/errors v0.20.4 // indirect
github.com/go-openapi/jsonpointer v0.20.0 // indirect
Expand All @@ -36,20 +39,19 @@ require (
github.com/go-openapi/validate v0.22.1 // indirect
github.com/goccy/go-yaml v1.11.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/josharian/native v1.0.0 // indirect
github.com/josharian/native v1.1.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/mdlayher/netlink v1.7.1 // indirect
github.com/mdlayher/socket v0.4.0 // indirect
github.com/mdlayher/netlink v1.7.2 // indirect
github.com/mdlayher/socket v0.5.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
go.mongodb.org/mongo-driver v1.12.1 // indirect
Expand Down
Loading
Loading