pkg/collectors: Reintroduce help text
This commit is contained in:
parent
d44a8bc991
commit
581c49d593
2
main.go
2
main.go
|
|
@ -253,7 +253,7 @@ func (m *metricHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
for _, c := range m.c {
|
||||
for _, m := range c.Collect() {
|
||||
_, err := fmt.Fprint(writer, *m)
|
||||
_, err := fmt.Fprint(writer, m)
|
||||
if err != nil {
|
||||
// TODO: Handle panic
|
||||
panic(err)
|
||||
|
|
|
|||
|
|
@ -69,6 +69,11 @@ func BenchmarkKubeStateMetrics(t *testing.B) {
|
|||
for i := 0; i < requestCount; i++ {
|
||||
w = httptest.NewRecorder()
|
||||
handler.ServeHTTP(w, req)
|
||||
|
||||
resp := w.Result()
|
||||
if resp.StatusCode != 200 {
|
||||
t.Fatalf("expected 200 status code but got %v", resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
// resp := w.Result()
|
||||
|
|
|
|||
|
|
@ -199,7 +199,10 @@ var availableCollectors = map[string]func(f *Builder) *Collector{
|
|||
func (b *Builder) buildServiceCollector() *Collector {
|
||||
filteredMetricFamilies := filterMetricFamilies(b.metricWhitelist, b.metricBlacklist, serviceMetricFamilies)
|
||||
|
||||
helpTexts := extractHelpText(filteredMetricFamilies)
|
||||
|
||||
store := metricsstore.NewMetricsStore(
|
||||
helpTexts,
|
||||
composeMetricGenFuncs(filteredMetricFamilies),
|
||||
)
|
||||
reflectorPerNamespace(b.ctx, b.kubeClient, &v1.Service{}, store, b.namespaces, createServiceListWatch)
|
||||
|
|
@ -207,28 +210,29 @@ func (b *Builder) buildServiceCollector() *Collector {
|
|||
return NewCollector(store)
|
||||
}
|
||||
|
||||
// func (b *Builder) buildNodeCollector() *Collector {
|
||||
// genFunc := func(obj interface{}) []*metrics.Metric {
|
||||
// return generateNodeMetrics(b.opts.DisableNodeNonGenericResourceMetrics, obj)
|
||||
// }
|
||||
//
|
||||
// return newCollector(store)
|
||||
// }
|
||||
func extractHelpText(families []metrics.MetricFamily) []string {
|
||||
help := make([]string, len(families))
|
||||
for i, f := range families {
|
||||
help[i] = f.Help
|
||||
}
|
||||
|
||||
return help
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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{}
|
||||
return func(obj interface{}) [][]*metrics.Metric {
|
||||
metrics := make([][]*metrics.Metric, len(funcs))
|
||||
|
||||
for _, f := range funcs {
|
||||
metrics = append(metrics, f(obj)...)
|
||||
for i, f := range funcs {
|
||||
metrics[i] = f(obj)
|
||||
}
|
||||
|
||||
return metrics
|
||||
|
|
|
|||
|
|
@ -16,12 +16,10 @@ limitations under the License.
|
|||
|
||||
package collectors
|
||||
|
||||
import (
|
||||
"k8s.io/kube-state-metrics/pkg/metrics"
|
||||
)
|
||||
import ()
|
||||
|
||||
type Store interface {
|
||||
GetAll() []*metrics.Metric
|
||||
GetAll() []string
|
||||
}
|
||||
|
||||
// Collector represents a kube-state-metrics metric collector. It is stripped
|
||||
|
|
@ -35,6 +33,6 @@ func NewCollector(s Store) *Collector {
|
|||
}
|
||||
|
||||
// Collect returns all metrics of the underlying store of the collector.
|
||||
func (c *Collector) Collect() []*metrics.Metric {
|
||||
func (c *Collector) Collect() []string {
|
||||
return c.Store.GetAll()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,11 +31,16 @@ type generateMetricsTestCase struct {
|
|||
Obj interface{}
|
||||
MetricNames []string
|
||||
Want string
|
||||
Func func(interface{}) []*metrics.Metric
|
||||
Func func(interface{}) [][]*metrics.Metric
|
||||
}
|
||||
|
||||
func (testCase *generateMetricsTestCase) run() error {
|
||||
metrics := testCase.Func(testCase.Obj)
|
||||
metricsByFamily := testCase.Func(testCase.Obj)
|
||||
|
||||
metrics := []*metrics.Metric{}
|
||||
for _, m := range metricsByFamily {
|
||||
metrics = append(metrics, m...)
|
||||
}
|
||||
|
||||
metrics = filterMetrics(metrics, testCase.MetricNames)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,21 +9,34 @@ import (
|
|||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
var (
|
||||
helpPrefix = "# HELP "
|
||||
)
|
||||
|
||||
// MetricsStore implements the k8s.io/kubernetes/client-go/tools/cache.Store
|
||||
// interface. Instead of storing entire Kubernetes objects, it stores metrics
|
||||
// generated based on them.
|
||||
type MetricsStore struct {
|
||||
mutex sync.RWMutex
|
||||
metrics map[types.UID][]*metrics.Metric
|
||||
// Protects metrics
|
||||
mutex sync.RWMutex
|
||||
// metrics is a map indexed by Kubernetes object id, containing a slice of
|
||||
// metric families, containing a slice of metrics. We need to keep metrics
|
||||
// grouped by metric families in order to zip families with their help text in
|
||||
// MetricsStore.WriteAll().
|
||||
metrics map[types.UID][][]*metrics.Metric
|
||||
// helpTexts is later on zipped with with their corresponding metric
|
||||
// families in MetricStore.WriteAll().
|
||||
helpTexts []string
|
||||
|
||||
generateMetricsFunc func(interface{}) []*metrics.Metric
|
||||
generateMetricsFunc func(interface{}) [][]*metrics.Metric
|
||||
}
|
||||
|
||||
// NewMetricsStore returns a new MetricsStore
|
||||
func NewMetricsStore(generateFunc func(interface{}) []*metrics.Metric) *MetricsStore {
|
||||
func NewMetricsStore(helpTexts []string, generateFunc func(interface{}) [][]*metrics.Metric) *MetricsStore {
|
||||
return &MetricsStore{
|
||||
generateMetricsFunc: generateFunc,
|
||||
metrics: map[types.UID][]*metrics.Metric{},
|
||||
helpTexts: helpTexts,
|
||||
metrics: map[types.UID][][]*metrics.Metric{},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -87,7 +100,7 @@ func (s *MetricsStore) GetByKey(key string) (item interface{}, exists bool, err
|
|||
// TODO: What is 'name' for?
|
||||
func (s *MetricsStore) Replace(list []interface{}, name string) error {
|
||||
s.mutex.Lock()
|
||||
s.metrics = map[types.UID][]*metrics.Metric{}
|
||||
s.metrics = map[types.UID][][]*metrics.Metric{}
|
||||
s.mutex.Unlock()
|
||||
|
||||
for _, o := range list {
|
||||
|
|
@ -104,15 +117,22 @@ func (s *MetricsStore) Resync() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *MetricsStore) GetAll() []*metrics.Metric {
|
||||
// GetAll returns all metrics of the store, zipped with the help text of each
|
||||
// metric family.
|
||||
func (s *MetricsStore) GetAll() []string {
|
||||
metrics := []string{}
|
||||
|
||||
s.mutex.RLock()
|
||||
defer s.mutex.RUnlock()
|
||||
|
||||
m := make([]*metrics.Metric, 0, len(s.metrics))
|
||||
|
||||
for _, metrics := range s.metrics {
|
||||
m = append(m, metrics...)
|
||||
for i, help := range s.helpTexts {
|
||||
metrics = append(metrics, helpPrefix+help+"\n")
|
||||
for _, metricsPerObject := range s.metrics {
|
||||
for _, metric := range metricsPerObject[i] {
|
||||
metrics = append(metrics, string(*metric))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m
|
||||
return metrics
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,18 +15,19 @@ import (
|
|||
func TestObjectsSameNameDifferentNamespaces(t *testing.T) {
|
||||
serviceIDS := []string{"a", "b"}
|
||||
|
||||
genFunc := func(obj interface{}) []*metrics.Metric {
|
||||
genFunc := func(obj interface{}) [][]*metrics.Metric {
|
||||
o, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
metric := metrics.Metric(fmt.Sprintf("kube_service_info{uid=\"%v\"} 1\n", o.GetUID()))
|
||||
metricFamily := []*metrics.Metric{&metric}
|
||||
|
||||
return []*metrics.Metric{&metric}
|
||||
return [][]*metrics.Metric{metricFamily}
|
||||
}
|
||||
|
||||
ms := NewMetricsStore(genFunc)
|
||||
ms := NewMetricsStore([]string{"Information about service."}, genFunc)
|
||||
|
||||
for _, id := range serviceIDS {
|
||||
s := v1.Service{
|
||||
|
|
@ -45,14 +46,15 @@ func TestObjectsSameNameDifferentNamespaces(t *testing.T) {
|
|||
|
||||
metrics := ms.GetAll()
|
||||
|
||||
if len(metrics) != 2 {
|
||||
// Expect 3 lines, HELP + 2 metrics
|
||||
if len(metrics) != 3 {
|
||||
t.Fatalf("expected 2 metrics but got %v", len(metrics))
|
||||
}
|
||||
|
||||
for _, id := range serviceIDS {
|
||||
found := false
|
||||
for _, m := range metrics {
|
||||
if strings.Contains(string(*m), fmt.Sprintf("uid=\"%v\"", id)) {
|
||||
if strings.Contains(m, fmt.Sprintf("uid=\"%v\"", id)) {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,17 +40,17 @@ func TestAsLibrary(t *testing.T) {
|
|||
|
||||
m := c.Collect()
|
||||
|
||||
if len(m) != 1 {
|
||||
t.Fatalf("expected one metric to be returned but got %v", len(m))
|
||||
if len(m) != 2 {
|
||||
t.Fatalf("expected HELP line and one metric to be returned but got %v", len(m))
|
||||
}
|
||||
|
||||
if !strings.Contains(string(*m[0]), service.ObjectMeta.Name) {
|
||||
if !strings.Contains(string(m[1]), service.ObjectMeta.Name) {
|
||||
t.Fatal("expected string to contain service name")
|
||||
}
|
||||
}
|
||||
|
||||
func serviceCollector(kubeClient clientset.Interface) *collectors.Collector {
|
||||
store := metricsstore.NewMetricsStore(generateServiceMetrics)
|
||||
store := metricsstore.NewMetricsStore([]string{"test_metric describes a test metric"}, generateServiceMetrics)
|
||||
|
||||
lw := cache.ListWatch{
|
||||
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
|
||||
|
|
@ -68,7 +68,7 @@ func serviceCollector(kubeClient clientset.Interface) *collectors.Collector {
|
|||
return collectors.NewCollector(store)
|
||||
}
|
||||
|
||||
func generateServiceMetrics(obj interface{}) []*metrics.Metric {
|
||||
func generateServiceMetrics(obj interface{}) [][]*metrics.Metric {
|
||||
sPointer := obj.(*v1.Service)
|
||||
s := *sPointer
|
||||
|
||||
|
|
@ -77,5 +77,7 @@ func generateServiceMetrics(obj interface{}) []*metrics.Metric {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
return []*metrics.Metric{m}
|
||||
ms := []*metrics.Metric{m}
|
||||
|
||||
return [][]*metrics.Metric{ms}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue