ebpf_exporter

Форк
0
/
decoder.go 
153 строки · 3.8 Кб
1
package decoder
2

3
import (
4
	"errors"
5
	"fmt"
6
	"sync"
7

8
	"github.com/cloudflare/ebpf_exporter/v2/config"
9
	"github.com/cloudflare/ebpf_exporter/v2/kallsyms"
10
)
11

12
// ErrSkipLabelSet instructs exporter to skip label set
13
var ErrSkipLabelSet = errors.New("this label set should be skipped")
14

15
// Decoder transforms byte field value into a byte value representing string
16
// to either use as an input for another Decoder or to use as the final
17
// label value for Prometheus metrics
18
type Decoder interface {
19
	Decode([]byte, config.Decoder) ([]byte, error)
20
}
21

22
// Set is a set of Decoders that may be applied to produce a label
23
type Set struct {
24
	mu       sync.Mutex
25
	decoders map[string]Decoder
26
	cache    map[string]map[string][]string
27
}
28

29
// NewSet creates a Set with all known decoders
30
func NewSet() (*Set, error) {
31
	cgroup, err := NewCgroupDecoder()
32
	if err != nil {
33
		return nil, fmt.Errorf("error creating cgroup decoder: %v", err)
34
	}
35

36
	ksym, err := kallsyms.NewDecoder("/proc/kallsyms")
37
	if err != nil {
38
		return nil, fmt.Errorf("error creating ksym decoder: %v", err)
39
	}
40

41
	return &Set{
42
		decoders: map[string]Decoder{
43
			"cgroup":       cgroup,
44
			"dname":        &Dname{},
45
			"ifname":       &IfName{},
46
			"inet_ip":      &InetIP{},
47
			"kstack":       &KStack{ksym},
48
			"ksym":         &KSym{ksym},
49
			"majorminor":   &MajorMinor{},
50
			"pci_class":    &PCIClass{},
51
			"pci_device":   &PCIDevice{},
52
			"pci_subclass": &PCISubClass{},
53
			"pci_vendor":   &PCIVendor{},
54
			"regexp":       &Regexp{},
55
			"static_map":   &StaticMap{},
56
			"string":       &String{},
57
			"syscall":      &Syscall{},
58
			"uint":         &UInt{},
59
		},
60
		cache: map[string]map[string][]string{},
61
	}, nil
62
}
63

64
// decode transforms input byte field into a string according to configuration
65
func (s *Set) decode(in []byte, label config.Label) ([]byte, error) {
66
	result := in
67

68
	for _, decoder := range label.Decoders {
69
		if _, ok := s.decoders[decoder.Name]; !ok {
70
			return result, fmt.Errorf("unknown decoder %q", decoder.Name)
71
		}
72

73
		decoded, err := s.decoders[decoder.Name].Decode(result, decoder)
74
		if err != nil {
75
			if err == ErrSkipLabelSet {
76
				return decoded, err
77
			}
78
			return decoded, fmt.Errorf("error decoding with decoder %q: %s", decoder.Name, err)
79
		}
80

81
		result = decoded
82
	}
83

84
	return result, nil
85
}
86

87
// DecodeLabels transforms eBPF map key bytes into a list of label values
88
// according to configuration (different label sets require different names)
89
func (s *Set) DecodeLabels(in []byte, name string, labels []config.Label) ([]string, error) {
90
	s.mu.Lock()
91
	defer s.mu.Unlock()
92

93
	cache, ok := s.cache[name]
94
	if !ok {
95
		cache = map[string][]string{}
96
		s.cache[name] = cache
97
	}
98

99
	// string(in) must not be a variable to avoid allocation:
100
	// * https://github.com/golang/go/commit/f5f5a8b6209f8
101
	if cached, ok := cache[string(in)]; ok {
102
		return cached, nil
103
	}
104

105
	values, err := s.decodeLabels(in, labels)
106
	if err != nil {
107
		return nil, err
108
	}
109

110
	cache[string(in)] = values
111

112
	return values, nil
113
}
114

115
// decodeLabels is the inner function of DecodeLabels without any caching
116
func (s *Set) decodeLabels(in []byte, labels []config.Label) ([]string, error) {
117
	values := make([]string, len(labels))
118

119
	off := uint(0)
120

121
	totalSize := uint(0)
122
	for _, label := range labels {
123
		size := label.Size
124
		if size == 0 {
125
			return nil, fmt.Errorf("error decoding label %q: size is zero or not set", label.Name)
126
		}
127

128
		totalSize += size
129
	}
130

131
	if totalSize != uint(len(in)) {
132
		return nil, fmt.Errorf("error decoding labels: total size of key %#v is %d bytes, but we have labels to decode %d", in, len(in), totalSize)
133
	}
134

135
	for i, label := range labels {
136
		if len(label.Decoders) == 0 {
137
			return nil, fmt.Errorf("error decoding label %q: no decoders set", label.Name)
138
		}
139

140
		size := label.Size
141

142
		decoded, err := s.decode(in[off:off+size], label)
143
		if err != nil {
144
			return nil, err
145
		}
146

147
		off += size
148

149
		values[i] = string(decoded)
150
	}
151

152
	return values, nil
153
}
154

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.