summaryrefslogtreecommitdiff
path: root/internal/tracepoints/selector.go
blob: af2f39e00217538c2adeb2987258431819c6fbd9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package tracepoints

import (
	"fmt"
	"regexp"
	"slices"
	"strings"
)

// Selector holds compiled include and exclude regexes for choosing which
// tracepoints to attach at BPF probe registration time. It is the single
// authoritative home for tracepoint-selection logic, keeping that concern
// out of the top-level flags.Config.
type Selector struct {
	// Attach is the list of compiled regexes that select which tracepoints to
	// load. An empty list means "attach all non-excluded tracepoints".
	Attach []*regexp.Regexp
	// Exclude is the list of compiled regexes that suppress specific
	// tracepoints even when they match the Attach list.
	Exclude []*regexp.Regexp
}

// ParseSelector parses the comma-separated regex strings for the -tps and
// -tpsExclude CLI flags into a Selector. Either string may be empty, which
// leaves the corresponding list nil (i.e. "match all" for Attach, "exclude
// nothing" for Exclude). An error is returned if any regex fails to compile.
func ParseSelector(attach, exclude string) (Selector, error) {
	attachRegexes, err := parseRegexList(attach)
	if err != nil {
		return Selector{}, err
	}
	excludeRegexes, err := parseRegexList(exclude)
	if err != nil {
		return Selector{}, err
	}
	return Selector{Attach: attachRegexes, Exclude: excludeRegexes}, nil
}

// parseRegexList splits a comma-separated string of regex patterns and
// compiles each one. Returns nil (not an error) when the input is empty.
func parseRegexList(patterns string) ([]*regexp.Regexp, error) {
	if len(patterns) == 0 {
		return nil, nil
	}
	var regexes []*regexp.Regexp
	for _, pattern := range strings.Split(patterns, ",") {
		re, err := regexp.Compile(pattern)
		if err != nil {
			return nil, fmt.Errorf("unable to compile regex %q: %w", pattern, err)
		}
		regexes = append(regexes, re)
	}
	return regexes, nil
}

// ShouldAttach reports whether the given tracepoint name passes the
// selector's attach/exclude regex filters. Exclusions are checked first; if
// the name matches any exclude pattern it is rejected regardless of the attach
// list. When the attach list is empty, all non-excluded tracepoints are
// accepted.
func (s Selector) ShouldAttach(tracepointName string) bool {
	for _, re := range s.Exclude {
		if re.MatchString(tracepointName) {
			return false
		}
	}
	if len(s.Attach) == 0 {
		return true
	}
	for _, re := range s.Attach {
		if re.MatchString(tracepointName) {
			return true
		}
	}
	return false
}

// Clone returns a deep copy of the Selector so that modifications to the
// copy's slices do not affect the original.
func (s Selector) Clone() Selector {
	return Selector{
		Attach:  slices.Clone(s.Attach),
		Exclude: slices.Clone(s.Exclude),
	}
}