-
Notifications
You must be signed in to change notification settings - Fork 417
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: add perfbuf metric per event (METRICS=1)
Enabled only when built with METRICS=1. BPFPerfEventSubmitAttemptsCount and BPFPerfEventSubmitFailuresCount count the number of events processed by the eBPF programs and written to or attempted to be written to the perf buffer. It is incremented right after the attempt of writing the event to the perf buffer, making it possible to measure if the that event was successfully written to the perf buffer or not. This metric can be used to monitor the performance of individual eBPF events and to detect potential bottlenecks.
- Loading branch information
Showing
8 changed files
with
354 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package ebpf | ||
|
||
import ( | ||
"context" | ||
"encoding/binary" | ||
"time" | ||
"unsafe" | ||
|
||
"github.com/aquasecurity/tracee/pkg/events" | ||
"github.com/aquasecurity/tracee/pkg/logger" | ||
) | ||
|
||
// eventStatsValues mirrors the C struct event_stats_values (event_stats_values_t). | ||
type eventStatsValues struct { | ||
submitAttempts uint64 | ||
submitFailures uint64 | ||
} | ||
|
||
// countPerfEventSubmissions is a goroutine that periodically counts the | ||
// number of attempts and failures to submit events to the perf buffer | ||
func (t *Tracee) countPerfEventSubmissions(ctx context.Context) { | ||
logger.Debugw("Starting countPerfEventSubmissions goroutine") | ||
defer logger.Debugw("Stopped countPerfEventSubmissions goroutine") | ||
|
||
evtsCountsBPFMap, err := t.bpfModule.GetMap("events_stats") | ||
if err != nil { | ||
logger.Errorw("Failed to get events_stats map", "error", err) | ||
return | ||
} | ||
|
||
evtStatZero := eventStatsValues{} | ||
for _, id := range t.policyManager.EventsSelected() { | ||
key := uint32(id) | ||
err := evtsCountsBPFMap.Update(unsafe.Pointer(&key), unsafe.Pointer(&evtStatZero)) | ||
if err != nil { | ||
logger.Errorw("Failed to update events_stats map", "error", err) | ||
} | ||
} | ||
|
||
ticker := time.NewTicker(10 * time.Second) | ||
defer ticker.Stop() | ||
|
||
for { | ||
select { | ||
case <-ctx.Done(): | ||
return | ||
case <-ticker.C: | ||
t.stats.BPFPerfEventSubmitAttemptsCount.Reset() | ||
t.stats.BPFPerfEventSubmitFailuresCount.Reset() | ||
|
||
// Get the counts of each event from the BPF map | ||
iter := evtsCountsBPFMap.Iterator() | ||
for iter.Next() { | ||
key := binary.LittleEndian.Uint32(iter.Key()) | ||
value, err := evtsCountsBPFMap.GetValue(unsafe.Pointer(&key)) | ||
if err != nil { | ||
logger.Errorw("Failed to get value from events_stats map", "error", err) | ||
continue | ||
} | ||
|
||
// Get counts | ||
id := events.ID(key) | ||
attempts := binary.LittleEndian.Uint64(value[0:8]) | ||
failures := binary.LittleEndian.Uint64(value[8:16]) | ||
t.stats.BPFPerfEventSubmitAttemptsCount.Set(uint64(id), attempts) | ||
t.stats.BPFPerfEventSubmitFailuresCount.Set(uint64(id), failures) | ||
|
||
// Update Prometheus metrics for current event | ||
evtName := events.Core.GetDefinitionByID(id).GetName() | ||
t.stats.BPFPerfEventSubmitAttemptsCount.GaugeVec().WithLabelValues(evtName).Set(float64(attempts)) | ||
t.stats.BPFPerfEventSubmitFailuresCount.GaugeVec().WithLabelValues(evtName).Set(float64(failures)) | ||
} | ||
|
||
// Log the counts | ||
t.stats.BPFPerfEventSubmitAttemptsCount.Log() | ||
t.stats.BPFPerfEventSubmitFailuresCount.Log() | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package metrics | ||
|
||
import ( | ||
"maps" | ||
"sync" | ||
|
||
"github.com/aquasecurity/tracee/pkg/counter" | ||
"github.com/aquasecurity/tracee/pkg/logger" | ||
"github.com/prometheus/client_golang/prometheus" | ||
) | ||
|
||
type Collector struct { | ||
m sync.RWMutex | ||
description string | ||
values map[uint64]uint64 | ||
gaugeVec *prometheus.GaugeVec | ||
} | ||
|
||
func NewCollector(description string, gv *prometheus.GaugeVec) *Collector { | ||
return &Collector{ | ||
m: sync.RWMutex{}, | ||
description: description, | ||
values: make(map[uint64]uint64), | ||
gaugeVec: gv, | ||
} | ||
} | ||
|
||
func (c *Collector) Get(id uint64) uint64 { | ||
c.m.RLock() | ||
defer c.m.RUnlock() | ||
|
||
return c.values[id] | ||
} | ||
|
||
func (c *Collector) Set(id uint64, v uint64) { | ||
c.m.Lock() | ||
defer c.m.Unlock() | ||
|
||
c.values[id] = v | ||
} | ||
|
||
func (c *Collector) Total() uint64 { | ||
c.m.RLock() | ||
defer c.m.RUnlock() | ||
|
||
total := counter.NewCounter(0) | ||
for _, v := range c.values { | ||
err := total.Increment(v) | ||
if err != nil { | ||
logger.Errorw("Failed to increment total counter", "error", err) | ||
} | ||
} | ||
|
||
return total.Get() | ||
} | ||
|
||
func (c *Collector) Reset() { | ||
c.m.Lock() | ||
defer c.m.Unlock() | ||
|
||
c.values = make(map[uint64]uint64) | ||
} | ||
|
||
func (c *Collector) Description() string { | ||
c.m.RLock() | ||
defer c.m.RUnlock() | ||
|
||
return c.description | ||
} | ||
|
||
func (c *Collector) GaugeVec() *prometheus.GaugeVec { | ||
c.m.RLock() | ||
defer c.m.RUnlock() | ||
|
||
return c.gaugeVec | ||
} | ||
|
||
func (c *Collector) Values() map[uint64]uint64 { | ||
c.m.RLock() | ||
defer c.m.RUnlock() | ||
|
||
return maps.Clone(c.values) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package metrics | ||
|
||
import ( | ||
"github.com/aquasecurity/tracee/pkg/counter" | ||
"github.com/aquasecurity/tracee/pkg/events" | ||
"github.com/aquasecurity/tracee/pkg/logger" | ||
"github.com/prometheus/client_golang/prometheus" | ||
) | ||
|
||
type EventCollector struct { | ||
c *Collector | ||
} | ||
|
||
func NewEventCollector(description string, gv *prometheus.GaugeVec) *EventCollector { | ||
return &EventCollector{ | ||
c: NewCollector(description, gv), | ||
} | ||
} | ||
|
||
func (ec *EventCollector) Get(id uint64) uint64 { | ||
return ec.c.Get(id) | ||
} | ||
|
||
func (ec *EventCollector) Set(id uint64, v uint64) { | ||
ec.c.Set(id, v) | ||
} | ||
|
||
func (ec *EventCollector) Total() uint64 { | ||
return ec.c.Total() | ||
} | ||
|
||
func (ec *EventCollector) Reset() { | ||
ec.c.Reset() | ||
} | ||
|
||
func (ec *EventCollector) Description() string { | ||
return ec.c.Description() | ||
} | ||
|
||
func (ec *EventCollector) GaugeVec() *prometheus.GaugeVec { | ||
return ec.c.GaugeVec() | ||
} | ||
|
||
func (ec *EventCollector) Values() map[uint64]uint64 { | ||
return ec.c.Values() | ||
} | ||
|
||
func (ec *EventCollector) Log() { | ||
values := ec.c.Values() | ||
description := ec.c.Description() | ||
|
||
keyVals := make([]interface{}, 0, len(values)*2+1) | ||
total := counter.NewCounter(0) | ||
for k, v := range values { | ||
keyVals = append(keyVals, | ||
events.Core.GetDefinitionByID(events.ID(k)).GetName(), | ||
v, | ||
) | ||
|
||
err := total.Increment(v) | ||
if err != nil { | ||
logger.Errorw("Failed to increment total counter", "error", err) | ||
} | ||
} | ||
|
||
// Log the counts | ||
keyVals = append(keyVals, "total", total.Get()) | ||
logger.Infow(description, keyVals...) | ||
} |
Oops, something went wrong.