pkg/collectors: Renable white-/blacklisting
Reenable feature to filter the exposition of metric families by their name. This is now done at startup time, thereby not slowing down the critical path.
This commit is contained in:
parent
af34d12ac4
commit
d44a8bc991
2
main.go
2
main.go
|
|
@ -103,9 +103,11 @@ func main() {
|
|||
}
|
||||
if !opts.MetricWhitelist.IsEmpty() {
|
||||
glog.Infof("A metric whitelist has been configured. Only the following metrics will be exposed: %s.", opts.MetricWhitelist.String())
|
||||
collectorBuilder.WithMetricWhitelist(opts.MetricWhitelist)
|
||||
}
|
||||
if !opts.MetricBlacklist.IsEmpty() {
|
||||
glog.Infof("A metric blacklist has been configured. The following metrics will not be exposed: %s.", opts.MetricBlacklist.String())
|
||||
collectorBuilder.WithMetricBlacklist(opts.MetricBlacklist)
|
||||
}
|
||||
|
||||
proc.StartReaper()
|
||||
|
|
|
|||
16
main_test.go
16
main_test.go
|
|
@ -17,9 +17,9 @@ limitations under the License.
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
// "fmt"
|
||||
// "io/ioutil"
|
||||
"context"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
|
@ -82,6 +82,7 @@ func BenchmarkKubeStateMetrics(t *testing.B) {
|
|||
func injectFixtures(client *fake.Clientset, multiplier int) error {
|
||||
creators := []func(*fake.Clientset, int) error{
|
||||
configMap,
|
||||
service,
|
||||
pod,
|
||||
}
|
||||
|
||||
|
|
@ -111,6 +112,19 @@ func configMap(client *fake.Clientset, index int) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func service(client *fake.Clientset, index int) error {
|
||||
i := strconv.Itoa(index)
|
||||
|
||||
service := v1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "service" + i,
|
||||
ResourceVersion: "123456",
|
||||
},
|
||||
}
|
||||
_, err := client.CoreV1().Services(metav1.NamespaceDefault).Create(&service)
|
||||
return err
|
||||
}
|
||||
|
||||
func pod(client *fake.Clientset, index int) error {
|
||||
i := strconv.Itoa(index)
|
||||
|
||||
|
|
|
|||
|
|
@ -20,16 +20,16 @@ package collectors
|
|||
import (
|
||||
"strings"
|
||||
|
||||
apps "k8s.io/api/apps/v1beta1"
|
||||
autoscaling "k8s.io/api/autoscaling/v2beta1"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
batchv1beta1 "k8s.io/api/batch/v1beta1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
// apps "k8s.io/api/apps/v1beta1"
|
||||
// autoscaling "k8s.io/api/autoscaling/v2beta1"
|
||||
// batchv1 "k8s.io/api/batch/v1"
|
||||
// batchv1beta1 "k8s.io/api/batch/v1beta1"
|
||||
// extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"golang.org/x/net/context"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/api/policy/v1beta1"
|
||||
// "k8s.io/api/policy/v1beta1"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/kube-state-metrics/pkg/metrics"
|
||||
|
|
@ -45,6 +45,8 @@ type Builder struct {
|
|||
opts *options.Options
|
||||
ctx context.Context
|
||||
enabledCollectors options.CollectorSet
|
||||
metricWhitelist map[string]struct{}
|
||||
metricBlacklist map[string]struct{}
|
||||
}
|
||||
|
||||
// NewBuilder returns a new builder.
|
||||
|
|
@ -73,6 +75,18 @@ func (b *Builder) WithKubeClient(c clientset.Interface) {
|
|||
b.kubeClient = c
|
||||
}
|
||||
|
||||
// WithMetricWhitelist configures the whitelisted metrics to be exposed by the
|
||||
// collectors build by the Builder
|
||||
func (b *Builder) WithMetricWhitelist(l map[string]struct{}) {
|
||||
b.metricWhitelist = l
|
||||
}
|
||||
|
||||
// WithMetricBlacklist configures the blacklisted metrics to be exposed by the
|
||||
// collectors build by the Builder
|
||||
func (b *Builder) WithMetricBlacklist(l map[string]struct{}) {
|
||||
b.metricBlacklist = l
|
||||
}
|
||||
|
||||
// Build initializes and registers all enabled collectors.
|
||||
func (b *Builder) Build() []*Collector {
|
||||
|
||||
|
|
@ -95,174 +109,170 @@ func (b *Builder) Build() []*Collector {
|
|||
}
|
||||
|
||||
var availableCollectors = map[string]func(f *Builder) *Collector{
|
||||
"configmaps": func(b *Builder) *Collector { return b.buildConfigMapCollector() },
|
||||
"cronjobs": func(b *Builder) *Collector { return b.buildCronJobCollector() },
|
||||
"daemonsets": func(b *Builder) *Collector { return b.buildDaemonSetCollector() },
|
||||
"deployments": func(b *Builder) *Collector { return b.buildDeploymentCollector() },
|
||||
"endpoints": func(b *Builder) *Collector { return b.buildEndpointsCollector() },
|
||||
"horizontalpodautoscalers": func(b *Builder) *Collector { return b.buildHPACollector() },
|
||||
"jobs": func(b *Builder) *Collector { return b.buildJobCollector() },
|
||||
"limitranges": func(b *Builder) *Collector { return b.buildLimitRangeCollector() },
|
||||
"namespaces": func(b *Builder) *Collector { return b.buildNamespaceCollector() },
|
||||
"nodes": func(b *Builder) *Collector { return b.buildNodeCollector() },
|
||||
"persistentvolumeclaims": func(b *Builder) *Collector { return b.buildPersistentVolumeClaimCollector() },
|
||||
"persistentvolumes": func(b *Builder) *Collector { return b.buildPersistentVolumeCollector() },
|
||||
"poddisruptionbudgets": func(b *Builder) *Collector { return b.buildPodDisruptionBudgetCollector() },
|
||||
"pods": func(b *Builder) *Collector { return b.buildPodCollector() },
|
||||
"replicasets": func(b *Builder) *Collector { return b.buildReplicaSetCollector() },
|
||||
"replicationcontrollers": func(b *Builder) *Collector { return b.buildReplicationControllerCollector() },
|
||||
"resourcequotas": func(b *Builder) *Collector { return b.buildResourceQuotaCollector() },
|
||||
"secrets": func(b *Builder) *Collector { return b.buildSecretCollector() },
|
||||
"services": func(b *Builder) *Collector { return b.buildServiceCollector() },
|
||||
"statefulsets": func(b *Builder) *Collector { return b.buildStatefulSetCollector() },
|
||||
}
|
||||
|
||||
func (b *Builder) buildPodCollector() *Collector {
|
||||
genFunc := func(obj interface{}) []*metrics.Metric {
|
||||
return generatePodMetrics(b.opts.DisablePodNonGenericResourceMetrics, obj)
|
||||
}
|
||||
store := metricsstore.NewMetricsStore(genFunc)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &v1.Pod{}, store, b.namespaces, createPodListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildCronJobCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generateCronJobMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &batchv1beta1.CronJob{}, store, b.namespaces, createCronJobListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildConfigMapCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generateConfigMapMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &v1.ConfigMap{}, store, b.namespaces, createConfigMapListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildDaemonSetCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generateDaemonSetMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &extensions.DaemonSet{}, store, b.namespaces, createDaemonSetListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildDeploymentCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generateDeploymentMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &extensions.Deployment{}, store, b.namespaces, createDeploymentListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildEndpointsCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generateEndpointsMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &v1.Endpoints{}, store, b.namespaces, createEndpointsListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildHPACollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generateHPAMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &autoscaling.HorizontalPodAutoscaler{}, store, b.namespaces, createHPAListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildJobCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generateJobMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &batchv1.Job{}, store, b.namespaces, createJobListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildLimitRangeCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generateLimitRangeMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &v1.LimitRange{}, store, b.namespaces, createLimitRangeListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildNamespaceCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generateNamespaceMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &v1.Namespace{}, store, b.namespaces, createNamespaceListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildNodeCollector() *Collector {
|
||||
genFunc := func(obj interface{}) []*metrics.Metric {
|
||||
return generateNodeMetrics(b.opts.DisableNodeNonGenericResourceMetrics, obj)
|
||||
}
|
||||
store := metricsstore.NewMetricsStore(genFunc)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &v1.Node{}, store, b.namespaces, createNodeListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildPersistentVolumeCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generatePersistentVolumeMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &v1.PersistentVolume{}, store, b.namespaces, createPersistentVolumeListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildPersistentVolumeClaimCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generatePersistentVolumeClaimMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &v1.PersistentVolumeClaim{}, store, b.namespaces, createPersistentVolumeClaimListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildPodDisruptionBudgetCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generatePodDisruptionBudgetMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &v1beta1.PodDisruptionBudget{}, store, b.namespaces, createPodDisruptionBudgetListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildReplicaSetCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generateReplicaSetMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &extensions.ReplicaSet{}, store, b.namespaces, createReplicaSetListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildReplicationControllerCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generateReplicationControllerMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &v1.ReplicationController{}, store, b.namespaces, createReplicationControllerListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildResourceQuotaCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generateResourceQuotaMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &v1.ResourceQuota{}, store, b.namespaces, createResourceQuotaListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildSecretCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generateSecretMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &v1.Secret{}, store, b.namespaces, createSecretListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
// "configmaps": func(b *Builder) *Collector { return b.buildConfigMapCollector() },
|
||||
// "cronjobs": func(b *Builder) *Collector { return b.buildCronJobCollector() },
|
||||
// "daemonsets": func(b *Builder) *Collector { return b.buildDaemonSetCollector() },
|
||||
// "deployments": func(b *Builder) *Collector { return b.buildDeploymentCollector() },
|
||||
// "endpoints": func(b *Builder) *Collector { return b.buildEndpointsCollector() },
|
||||
// "horizontalpodautoscalers": func(b *Builder) *Collector { return b.buildHPACollector() },
|
||||
// "jobs": func(b *Builder) *Collector { return b.buildJobCollector() },
|
||||
// "limitranges": func(b *Builder) *Collector { return b.buildLimitRangeCollector() },
|
||||
// "namespaces": func(b *Builder) *Collector { return b.buildNamespaceCollector() },
|
||||
// "nodes": func(b *Builder) *Collector { return b.buildNodeCollector() },
|
||||
// "persistentvolumeclaims": func(b *Builder) *Collector { return b.buildPersistentVolumeClaimCollector() },
|
||||
// "persistentvolumes": func(b *Builder) *Collector { return b.buildPersistentVolumeCollector() },
|
||||
// "poddisruptionbudgets": func(b *Builder) *Collector { return b.buildPodDisruptionBudgetCollector() },
|
||||
// "pods": func(b *Builder) *Collector { return b.buildPodCollector() },
|
||||
// "replicasets": func(b *Builder) *Collector { return b.buildReplicaSetCollector() },
|
||||
// "replicationcontrollers": func(b *Builder) *Collector { return b.buildReplicationControllerCollector() },
|
||||
// "resourcequotas": func(b *Builder) *Collector { return b.buildResourceQuotaCollector() },
|
||||
// "secrets": func(b *Builder) *Collector { return b.buildSecretCollector() },
|
||||
"services": func(b *Builder) *Collector { return b.buildServiceCollector() },
|
||||
// "statefulsets": func(b *Builder) *Collector { return b.buildStatefulSetCollector() },
|
||||
}
|
||||
|
||||
// func (b *Builder) buildPodCollector() *Collector {
|
||||
// genFunc := func(obj interface{}) []*metrics.Metric {
|
||||
// return generatePodMetrics(b.opts.DisablePodNonGenericResourceMetrics, obj)
|
||||
// }
|
||||
// store := metricsstore.NewMetricsStore(genFunc)
|
||||
// reflectorPerNamespace(b.ctx, b.kubeClient, &v1.Pod{}, store, b.namespaces, createPodListWatch)
|
||||
//
|
||||
// return NewCollector(store)
|
||||
// }
|
||||
//
|
||||
// func (b *Builder) buildCronJobCollector() *Collector {
|
||||
// store := metricsstore.NewMetricsStore(generateCronJobMetrics)
|
||||
// reflectorPerNamespace(b.ctx, b.kubeClient, &batchv1beta1.CronJob{}, store, b.namespaces, createCronJobListWatch)
|
||||
//
|
||||
// return NewCollector(store)
|
||||
// }
|
||||
//
|
||||
// func (b *Builder) buildConfigMapCollector() *Collector {
|
||||
// store := metricsstore.NewMetricsStore(generateConfigMapMetrics)
|
||||
// reflectorPerNamespace(b.ctx, b.kubeClient, &v1.ConfigMap{}, store, b.namespaces, createConfigMapListWatch)
|
||||
//
|
||||
// return NewCollector(store)
|
||||
// }
|
||||
//
|
||||
// func (b *Builder) buildDaemonSetCollector() *Collector {
|
||||
// store := metricsstore.NewMetricsStore(generateDaemonSetMetrics)
|
||||
// reflectorPerNamespace(b.ctx, b.kubeClient, &extensions.DaemonSet{}, store, b.namespaces, createDaemonSetListWatch)
|
||||
//
|
||||
// return NewCollector(store)
|
||||
// }
|
||||
//
|
||||
// func (b *Builder) buildDeploymentCollector() *Collector {
|
||||
// store := metricsstore.NewMetricsStore(generateDeploymentMetrics)
|
||||
// reflectorPerNamespace(b.ctx, b.kubeClient, &extensions.Deployment{}, store, b.namespaces, createDeploymentListWatch)
|
||||
//
|
||||
// return NewCollector(store)
|
||||
// }
|
||||
//
|
||||
// func (b *Builder) buildEndpointsCollector() *Collector {
|
||||
// store := metricsstore.NewMetricsStore(generateEndpointsMetrics)
|
||||
// reflectorPerNamespace(b.ctx, b.kubeClient, &v1.Endpoints{}, store, b.namespaces, createEndpointsListWatch)
|
||||
//
|
||||
// return NewCollector(store)
|
||||
// }
|
||||
//
|
||||
// func (b *Builder) buildHPACollector() *Collector {
|
||||
// store := metricsstore.NewMetricsStore(generateHPAMetrics)
|
||||
// reflectorPerNamespace(b.ctx, b.kubeClient, &autoscaling.HorizontalPodAutoscaler{}, store, b.namespaces, createHPAListWatch)
|
||||
//
|
||||
// return NewCollector(store)
|
||||
// }
|
||||
//
|
||||
// func (b *Builder) buildJobCollector() *Collector {
|
||||
// store := metricsstore.NewMetricsStore(generateJobMetrics)
|
||||
// reflectorPerNamespace(b.ctx, b.kubeClient, &batchv1.Job{}, store, b.namespaces, createJobListWatch)
|
||||
//
|
||||
// return NewCollector(store)
|
||||
// }
|
||||
//
|
||||
// func (b *Builder) buildLimitRangeCollector() *Collector {
|
||||
// store := metricsstore.NewMetricsStore(generateLimitRangeMetrics)
|
||||
// reflectorPerNamespace(b.ctx, b.kubeClient, &v1.LimitRange{}, store, b.namespaces, createLimitRangeListWatch)
|
||||
//
|
||||
// return NewCollector(store)
|
||||
// }
|
||||
func (b *Builder) buildServiceCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generateServiceMetrics)
|
||||
filteredMetricFamilies := filterMetricFamilies(b.metricWhitelist, b.metricBlacklist, serviceMetricFamilies)
|
||||
|
||||
store := metricsstore.NewMetricsStore(
|
||||
composeMetricGenFuncs(filteredMetricFamilies),
|
||||
)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &v1.Service{}, store, b.namespaces, createServiceListWatch)
|
||||
|
||||
return NewCollector(store)
|
||||
}
|
||||
|
||||
func (b *Builder) buildStatefulSetCollector() *Collector {
|
||||
store := metricsstore.NewMetricsStore(generateStatefulSetMetrics)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &apps.StatefulSet{}, store, b.namespaces, createStatefulSetListWatch)
|
||||
// func (b *Builder) buildNodeCollector() *Collector {
|
||||
// genFunc := func(obj interface{}) []*metrics.Metric {
|
||||
// return generateNodeMetrics(b.opts.DisableNodeNonGenericResourceMetrics, obj)
|
||||
// }
|
||||
//
|
||||
// return newCollector(store)
|
||||
// }
|
||||
|
||||
return NewCollector(store)
|
||||
// composeMetricGenFuncs takes a slice of metric families and returns a function
|
||||
// that composes their metric generation functions into a single one.
|
||||
func composeMetricGenFuncs(families []metrics.MetricFamily) func(obj interface{}) []*metrics.Metric {
|
||||
funcs := []func(obj interface{}) []*metrics.Metric{}
|
||||
|
||||
for _, f := range families {
|
||||
funcs = append(funcs, f.GenerateFunc)
|
||||
}
|
||||
|
||||
return func(obj interface{}) []*metrics.Metric {
|
||||
metrics := []*metrics.Metric{}
|
||||
|
||||
for _, f := range funcs {
|
||||
metrics = append(metrics, f(obj)...)
|
||||
}
|
||||
|
||||
return metrics
|
||||
}
|
||||
}
|
||||
|
||||
// filterMetricFamilies takes a white- and a blacklist and a slice of metric
|
||||
// families and returns a filtered slice.
|
||||
func filterMetricFamilies(white, black map[string]struct{}, families []metrics.MetricFamily) []metrics.MetricFamily {
|
||||
if len(white) != 0 && len(black) != 0 {
|
||||
panic("Whitelist and blacklist are both set. They are mutually exclusive, only one of them can be set.")
|
||||
}
|
||||
|
||||
filtered := []metrics.MetricFamily{}
|
||||
|
||||
if len(white) != 0 {
|
||||
for _, f := range families {
|
||||
if _, whitelisted := white[f.Name]; whitelisted {
|
||||
filtered = append(filtered, f)
|
||||
}
|
||||
}
|
||||
|
||||
return filtered
|
||||
}
|
||||
|
||||
for _, f := range families {
|
||||
if _, blacklisted := black[f.Name]; !blacklisted {
|
||||
filtered = append(filtered, f)
|
||||
}
|
||||
}
|
||||
|
||||
return filtered
|
||||
}
|
||||
|
||||
//
|
||||
// func (b *Builder) buildStatefulSetCollector() *Collector {
|
||||
// store := metricsstore.NewMetricsStore(generateStatefulSetMetrics)
|
||||
// reflectorPerNamespace(b.ctx, b.kubeClient, &apps.StatefulSet{}, store, b.namespaces, createStatefulSetListWatch)
|
||||
//
|
||||
// return newCollector(store)
|
||||
// }
|
||||
|
||||
// reflectorPerNamespace creates a Kubernetes client-go reflector with the given
|
||||
// listWatchFunc for each given namespace and registers it with the given store.
|
||||
func reflectorPerNamespace(
|
||||
ctx context.Context,
|
||||
kubeClient clientset.Interface,
|
||||
|
|
|
|||
|
|
@ -32,63 +32,163 @@ var (
|
|||
descServiceLabelsHelp = "Kubernetes labels converted to Prometheus labels."
|
||||
descServiceLabelsDefaultLabels = []string{"namespace", "service"}
|
||||
|
||||
descServiceInfo = metrics.NewMetricFamilyDef(
|
||||
"kube_service_info",
|
||||
"Information about service.",
|
||||
append(descServiceLabelsDefaultLabels, "cluster_ip", "external_name", "load_balancer_ip"),
|
||||
nil,
|
||||
)
|
||||
serviceMetricFamilies = []metrics.MetricFamily{
|
||||
{
|
||||
"kube_service_info",
|
||||
"Information about service.",
|
||||
func(obj interface{}) []*metrics.Metric {
|
||||
sPointer := obj.(*v1.Service)
|
||||
s := *sPointer
|
||||
|
||||
descServiceCreated = metrics.NewMetricFamilyDef(
|
||||
"kube_service_created",
|
||||
"Unix creation timestamp",
|
||||
descServiceLabelsDefaultLabels,
|
||||
nil,
|
||||
)
|
||||
return []*metrics.Metric{
|
||||
newServiceMetric(
|
||||
sPointer,
|
||||
"kube_service_info",
|
||||
[]string{"cluster_ip", "external_name", "load_balancer_ip"},
|
||||
[]string{s.Spec.ClusterIP, s.Spec.ExternalName, s.Spec.LoadBalancerIP},
|
||||
1,
|
||||
),
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"kube_service_created",
|
||||
"Unix creation timestamp",
|
||||
func(obj interface{}) []*metrics.Metric {
|
||||
sPointer := obj.(*v1.Service)
|
||||
s := *sPointer
|
||||
|
||||
descServiceSpecType = metrics.NewMetricFamilyDef(
|
||||
"kube_service_spec_type",
|
||||
"Type about service.",
|
||||
append(descServiceLabelsDefaultLabels, "type"),
|
||||
nil,
|
||||
)
|
||||
if !s.CreationTimestamp.IsZero() {
|
||||
return []*metrics.Metric{
|
||||
newServiceMetric(
|
||||
sPointer,
|
||||
"kube_service_created",
|
||||
nil,
|
||||
nil,
|
||||
float64(s.CreationTimestamp.Unix()),
|
||||
),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
"kube_service_spec_type",
|
||||
"Type about service.",
|
||||
func(obj interface{}) []*metrics.Metric {
|
||||
sPointer := obj.(*v1.Service)
|
||||
s := *sPointer
|
||||
|
||||
descServiceExternalName = metrics.NewMetricFamilyDef(
|
||||
"kube_service_external_name",
|
||||
"Service external name",
|
||||
append(descServiceLabelsDefaultLabels, "external_name"),
|
||||
nil,
|
||||
)
|
||||
return []*metrics.Metric{
|
||||
newServiceMetric(
|
||||
sPointer,
|
||||
"kube_service_spec_type",
|
||||
[]string{"type"},
|
||||
[]string{string(s.Spec.Type)},
|
||||
1,
|
||||
),
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
descServiceLabelsName,
|
||||
descServiceLabelsHelp,
|
||||
func(obj interface{}) []*metrics.Metric {
|
||||
sPointer := obj.(*v1.Service)
|
||||
s := *sPointer
|
||||
|
||||
descServiceLoadBalancerIP = metrics.NewMetricFamilyDef(
|
||||
"kube_service_load_balancer_ip",
|
||||
"Load balancer IP of service",
|
||||
append(descServiceLabelsDefaultLabels, "load_balancer_ip"),
|
||||
nil,
|
||||
)
|
||||
labelKeys, labelValues := kubeLabelsToPrometheusLabels(s.Labels)
|
||||
return []*metrics.Metric{
|
||||
newServiceMetric(
|
||||
sPointer,
|
||||
descServiceLabelsName,
|
||||
labelKeys,
|
||||
labelValues,
|
||||
1,
|
||||
),
|
||||
}
|
||||
},
|
||||
},
|
||||
// Defined, but not used anywhere. See
|
||||
// https://github.com/kubernetes/kube-state-metrics/pull/571#pullrequestreview-176215628.
|
||||
// {
|
||||
// "kube_service_external_name",
|
||||
// "Service external name",
|
||||
// // []string{"type"},
|
||||
// },
|
||||
// {
|
||||
// "kube_service_load_balancer_ip",
|
||||
// "Load balancer IP of service",
|
||||
// // []string{"load_balancer_ip"},
|
||||
// },
|
||||
{
|
||||
"kube_service_spec_external_ip",
|
||||
"Service external ips. One series for each ip",
|
||||
func(obj interface{}) []*metrics.Metric {
|
||||
sPointer := obj.(*v1.Service)
|
||||
s := *sPointer
|
||||
|
||||
descServiceSpecExternalIP = metrics.NewMetricFamilyDef(
|
||||
"kube_service_spec_external_ip",
|
||||
"Service external ips. One series for each ip",
|
||||
append(descServiceLabelsDefaultLabels, "external_ip"),
|
||||
nil,
|
||||
)
|
||||
metrics := []*metrics.Metric{}
|
||||
|
||||
descServiceLabels = metrics.NewMetricFamilyDef(
|
||||
descServiceLabelsName,
|
||||
descServiceLabelsHelp,
|
||||
descServiceLabelsDefaultLabels,
|
||||
nil,
|
||||
)
|
||||
if len(s.Spec.ExternalIPs) > 0 {
|
||||
for _, externalIP := range s.Spec.ExternalIPs {
|
||||
m := newServiceMetric(
|
||||
sPointer,
|
||||
"kube_service_spec_external_ip",
|
||||
[]string{"external_ip"},
|
||||
[]string{externalIP},
|
||||
1,
|
||||
)
|
||||
|
||||
descServiceStatusLoadBalancerIngress = metrics.NewMetricFamilyDef(
|
||||
"kube_service_status_load_balancer_ingress",
|
||||
"Service load balancer ingress status",
|
||||
append(descServiceLabelsDefaultLabels, "ip", "hostname"),
|
||||
nil,
|
||||
)
|
||||
metrics = append(metrics, m)
|
||||
}
|
||||
}
|
||||
|
||||
return metrics
|
||||
},
|
||||
},
|
||||
{
|
||||
"kube_service_status_load_balancer_ingress",
|
||||
"Service load balancer ingress status",
|
||||
func(obj interface{}) []*metrics.Metric {
|
||||
sPointer := obj.(*v1.Service)
|
||||
s := *sPointer
|
||||
|
||||
metrics := []*metrics.Metric{}
|
||||
|
||||
if len(s.Status.LoadBalancer.Ingress) > 0 {
|
||||
for _, ingress := range s.Status.LoadBalancer.Ingress {
|
||||
m := newServiceMetric(
|
||||
sPointer,
|
||||
"kube_service_status_load_balancer_ingress",
|
||||
[]string{"ip", "hostname"},
|
||||
[]string{ingress.IP, ingress.Hostname},
|
||||
1,
|
||||
)
|
||||
|
||||
metrics = append(metrics, m)
|
||||
}
|
||||
}
|
||||
|
||||
return metrics
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func newServiceMetric(s *v1.Service, name string, lk []string, lv []string, v float64) *metrics.Metric {
|
||||
lk = append(descServiceLabelsDefaultLabels, lk...)
|
||||
lv = append([]string{s.Namespace, s.Name}, lv...)
|
||||
|
||||
m, err := metrics.NewMetric(name, lk, lv, v)
|
||||
if err != nil {
|
||||
// TODO: Move this panic into metrics.NewMetric
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func createServiceListWatch(kubeClient clientset.Interface, ns string) cache.ListWatch {
|
||||
return cache.ListWatch{
|
||||
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
|
||||
|
|
@ -99,56 +199,3 @@ func createServiceListWatch(kubeClient clientset.Interface, ns string) cache.Lis
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
func serviceLabelsDesc(labelKeys []string) *metrics.MetricFamilyDef {
|
||||
return metrics.NewMetricFamilyDef(
|
||||
descServiceLabelsName,
|
||||
descServiceLabelsHelp,
|
||||
append(descServiceLabelsDefaultLabels, labelKeys...),
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
func generateServiceMetrics(obj interface{}) []*metrics.Metric {
|
||||
ms := []*metrics.Metric{}
|
||||
|
||||
// TODO: Refactor
|
||||
sPointer := obj.(*v1.Service)
|
||||
s := *sPointer
|
||||
|
||||
addConstMetric := func(desc *metrics.MetricFamilyDef, v float64, lv ...string) {
|
||||
lv = append([]string{s.Namespace, s.Name}, lv...)
|
||||
|
||||
m, err := metrics.NewMetric(desc.Name, desc.LabelKeys, lv, v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ms = append(ms, m)
|
||||
}
|
||||
addGauge := func(desc *metrics.MetricFamilyDef, v float64, lv ...string) {
|
||||
addConstMetric(desc, v, lv...)
|
||||
}
|
||||
addGauge(descServiceSpecType, 1, string(s.Spec.Type))
|
||||
|
||||
addGauge(descServiceInfo, 1, s.Spec.ClusterIP, s.Spec.ExternalName, s.Spec.LoadBalancerIP)
|
||||
if !s.CreationTimestamp.IsZero() {
|
||||
addGauge(descServiceCreated, float64(s.CreationTimestamp.Unix()))
|
||||
}
|
||||
labelKeys, labelValues := kubeLabelsToPrometheusLabels(s.Labels)
|
||||
addGauge(serviceLabelsDesc(labelKeys), 1, labelValues...)
|
||||
|
||||
if len(s.Status.LoadBalancer.Ingress) > 0 {
|
||||
for _, ingress := range s.Status.LoadBalancer.Ingress {
|
||||
addGauge(descServiceStatusLoadBalancerIngress, 1, ingress.IP, ingress.Hostname)
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.Spec.ExternalIPs) > 0 {
|
||||
for _, external_ip := range s.Spec.ExternalIPs {
|
||||
addGauge(descServiceSpecExternalIP, 1, external_ip)
|
||||
}
|
||||
}
|
||||
|
||||
return ms
|
||||
}
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ func TestServiceCollector(t *testing.T) {
|
|||
},
|
||||
}
|
||||
for i, c := range cases {
|
||||
c.Func = generateServiceMetrics
|
||||
c.Func = composeMetricGenFuncs(serviceMetricFamilies)
|
||||
if err := c.run(); err != nil {
|
||||
t.Errorf("unexpected collecting result in %vth run:\n%s", i, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ type generateMetricsTestCase struct {
|
|||
|
||||
func (testCase *generateMetricsTestCase) run() error {
|
||||
metrics := testCase.Func(testCase.Obj)
|
||||
|
||||
metrics = filterMetrics(metrics, testCase.MetricNames)
|
||||
|
||||
out := ""
|
||||
|
|
|
|||
|
|
@ -22,11 +22,6 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
"k8s.io/kube-state-metrics/pkg/options"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -42,6 +37,13 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
// MetricFamily represents a set of metrics with the same name and help text.
|
||||
type MetricFamily struct {
|
||||
Name string
|
||||
Help string
|
||||
GenerateFunc func(obj interface{}) []*Metric
|
||||
}
|
||||
|
||||
// Metric represents a single line entry in the /metrics export format
|
||||
type Metric string
|
||||
|
||||
|
|
@ -121,64 +123,3 @@ func writeFloat(w *strings.Builder, f float64) {
|
|||
numBufPool.Put(bp)
|
||||
}
|
||||
}
|
||||
|
||||
// MetricFamilyDesc represents the HELP and TYPE string above a metric family list
|
||||
type MetricFamilyDesc string
|
||||
|
||||
type gathererFunc func() ([]*dto.MetricFamily, error)
|
||||
|
||||
func (f gathererFunc) Gather() ([]*dto.MetricFamily, error) {
|
||||
return f()
|
||||
}
|
||||
|
||||
// FilteredGatherer wraps a prometheus.Gatherer to filter metrics based on a
|
||||
// white or blacklist. Whitelist and blacklist are mutually exclusive.
|
||||
// TODO: Bring white and blacklisting back
|
||||
func FilteredGatherer(r prometheus.Gatherer, whitelist options.MetricSet, blacklist options.MetricSet) prometheus.Gatherer {
|
||||
whitelistEnabled := !whitelist.IsEmpty()
|
||||
blacklistEnabled := !blacklist.IsEmpty()
|
||||
|
||||
if whitelistEnabled {
|
||||
return gathererFunc(func() ([]*dto.MetricFamily, error) {
|
||||
metricFamilies, err := r.Gather()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newMetricFamilies := []*dto.MetricFamily{}
|
||||
for _, metricFamily := range metricFamilies {
|
||||
// deferencing this string may be a performance bottleneck
|
||||
name := *metricFamily.Name
|
||||
_, onWhitelist := whitelist[name]
|
||||
if onWhitelist {
|
||||
newMetricFamilies = append(newMetricFamilies, metricFamily)
|
||||
}
|
||||
}
|
||||
|
||||
return newMetricFamilies, nil
|
||||
})
|
||||
}
|
||||
|
||||
if blacklistEnabled {
|
||||
return gathererFunc(func() ([]*dto.MetricFamily, error) {
|
||||
metricFamilies, err := r.Gather()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newMetricFamilies := []*dto.MetricFamily{}
|
||||
for _, metricFamily := range metricFamilies {
|
||||
name := *metricFamily.Name
|
||||
_, onBlacklist := blacklist[name]
|
||||
if onBlacklist {
|
||||
continue
|
||||
}
|
||||
newMetricFamilies = append(newMetricFamilies, metricFamily)
|
||||
}
|
||||
|
||||
return newMetricFamilies, nil
|
||||
})
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,140 +2,8 @@ package metrics
|
|||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"k8s.io/kube-state-metrics/pkg/options"
|
||||
)
|
||||
|
||||
func TestFiltererdGatherer(t *testing.T) {
|
||||
r := prometheus.NewRegistry()
|
||||
c1 := prometheus.NewCounter(
|
||||
prometheus.CounterOpts{
|
||||
Name: "test1",
|
||||
Help: "test1 help",
|
||||
},
|
||||
)
|
||||
c2 := prometheus.NewCounter(
|
||||
prometheus.CounterOpts{
|
||||
Name: "test2",
|
||||
Help: "test2 help",
|
||||
},
|
||||
)
|
||||
c1.Inc()
|
||||
c1.Inc()
|
||||
c2.Inc()
|
||||
r.MustRegister(c1)
|
||||
r.MustRegister(c2)
|
||||
|
||||
res, err := FilteredGatherer(r, nil, nil).Gather()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
found1 := false
|
||||
found2 := false
|
||||
for _, mf := range res {
|
||||
if *mf.Name == "test1" {
|
||||
found1 = true
|
||||
}
|
||||
if *mf.Name == "test2" {
|
||||
found2 = true
|
||||
}
|
||||
}
|
||||
|
||||
if !found1 || !found2 {
|
||||
t.Fatal("No results expected to be filtered, but results were filtered.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFiltererdGathererWhitelist(t *testing.T) {
|
||||
r := prometheus.NewRegistry()
|
||||
c1 := prometheus.NewCounter(
|
||||
prometheus.CounterOpts{
|
||||
Name: "test1",
|
||||
Help: "test1 help",
|
||||
},
|
||||
)
|
||||
c2 := prometheus.NewCounter(
|
||||
prometheus.CounterOpts{
|
||||
Name: "test2",
|
||||
Help: "test2 help",
|
||||
},
|
||||
)
|
||||
c1.Inc()
|
||||
c1.Inc()
|
||||
c2.Inc()
|
||||
r.MustRegister(c1)
|
||||
r.MustRegister(c2)
|
||||
|
||||
whitelist := options.MetricSet{}
|
||||
whitelist.Set("test1")
|
||||
|
||||
res, err := FilteredGatherer(r, whitelist, nil).Gather()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
found1 := false
|
||||
found2 := false
|
||||
for _, mf := range res {
|
||||
if *mf.Name == "test1" {
|
||||
found1 = true
|
||||
}
|
||||
if *mf.Name == "test2" {
|
||||
found2 = true
|
||||
}
|
||||
}
|
||||
|
||||
if !found1 || found2 {
|
||||
t.Fatalf("Expected `test2` to be filtered and `test1` not. `test1`: %t ; `test2`: %t.", found1, found2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFiltererdGathererBlacklist(t *testing.T) {
|
||||
r := prometheus.NewRegistry()
|
||||
c1 := prometheus.NewCounter(
|
||||
prometheus.CounterOpts{
|
||||
Name: "test1",
|
||||
Help: "test1 help",
|
||||
},
|
||||
)
|
||||
c2 := prometheus.NewCounter(
|
||||
prometheus.CounterOpts{
|
||||
Name: "test2",
|
||||
Help: "test2 help",
|
||||
},
|
||||
)
|
||||
c1.Inc()
|
||||
c1.Inc()
|
||||
c2.Inc()
|
||||
r.MustRegister(c1)
|
||||
r.MustRegister(c2)
|
||||
|
||||
blacklist := options.MetricSet{}
|
||||
blacklist.Set("test1")
|
||||
|
||||
res, err := FilteredGatherer(r, nil, blacklist).Gather()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
found1 := false
|
||||
found2 := false
|
||||
for _, mf := range res {
|
||||
if *mf.Name == "test1" {
|
||||
found1 = true
|
||||
}
|
||||
if *mf.Name == "test2" {
|
||||
found2 = true
|
||||
}
|
||||
}
|
||||
|
||||
if found1 || !found2 {
|
||||
t.Fatalf("Expected `test1` to be filtered and `test2` not. `test1`: %t ; `test2`: %t.", found1, found2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNewMetric(b *testing.B) {
|
||||
tests := []struct {
|
||||
testName string
|
||||
|
|
|
|||
Loading…
Reference in New Issue