-
Notifications
You must be signed in to change notification settings - Fork 51
/
group.go
115 lines (94 loc) · 3.03 KB
/
group.go
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package grouper
import (
"fmt"
"github.com/newrelic/nri-kubernetes/v3/internal/logutil"
log "github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/labels"
listersv1 "k8s.io/client-go/listers/core/v1"
"github.com/newrelic/nri-kubernetes/v3/src/data"
"github.com/newrelic/nri-kubernetes/v3/src/definition"
"github.com/newrelic/nri-kubernetes/v3/src/prometheus"
)
type grouper struct {
Config
logger *log.Logger
}
type Config struct {
Queries []prometheus.Query
MetricFamiliesGetter prometheus.FetchAndFilterMetricsFamilies
ServicesLister listersv1.ServiceLister
}
type OptionFunc func(kc *grouper) error
// WithLogger returns an OptionFunc to change the logger from the default noop logger.
func WithLogger(logger *log.Logger) OptionFunc {
return func(kc *grouper) error {
kc.logger = logger
return nil
}
}
// New returns a data.Grouper that groups KSM metrics.
func New(config Config, opts ...OptionFunc) (data.Grouper, error) {
if config.MetricFamiliesGetter == nil {
return nil, fmt.Errorf("metric families getter must be set")
}
if config.ServicesLister == nil {
return nil, fmt.Errorf("ServicesLister must be set")
}
g := &grouper{
Config: config,
logger: logutil.Discard,
}
for i, opt := range opts {
if err := opt(g); err != nil {
return nil, fmt.Errorf("applying option #%d: %w", i, err)
}
}
return g, nil
}
// Group implements Grouper interface by fetching Prometheus metrics from KSM and then modifying it
// using Service objects fetched from API server.
func (g *grouper) Group(specGroups definition.SpecGroups) (definition.RawGroups, *data.ErrorGroup) {
mFamily, err := g.MetricFamiliesGetter(g.Queries)
if err != nil {
return nil, &data.ErrorGroup{
Errors: []error{fmt.Errorf("querying KSM: %w", err)},
}
}
groups, errs := prometheus.GroupMetricsBySpec(specGroups, mFamily)
if servicesGroup, ok := groups["service"]; ok {
if err := g.addServiceSpecSelectorToGroup(servicesGroup); err != nil {
errs = append(errs, fmt.Errorf("adding service spec selector to group: %w", err))
}
}
if len(errs) > 0 {
return groups, &data.ErrorGroup{
Recoverable: true,
Errors: errs,
}
}
return groups, nil
}
// addServiceSpecSelectorToGroup adds a new metric to the service group
// which includes the selectors defined in the service spec.
func (g *grouper) addServiceSpecSelectorToGroup(serviceGroup map[string]definition.RawMetrics) error {
services, err := g.ServicesLister.List(labels.Everything())
if err != nil {
return fmt.Errorf("listing services: %w", err)
}
for _, s := range services {
serviceRawMetrics, ok := serviceGroup[fmt.Sprintf("%s_%s", s.Namespace, s.Name)]
if !ok {
g.logger.Debugf("Metrics for service %s.%s not found in cluster", s.Namespace, s.Name)
continue
}
promLabels := prometheus.Labels{}
for key, value := range s.Spec.Selector {
promLabels[fmt.Sprintf("selector_%s", key)] = value
}
serviceRawMetrics["apiserver_kube_service_spec_selectors"] = prometheus.Metric{
Labels: promLabels,
Value: nil,
}
}
return nil
}