Skip to content

Commit

Permalink
Make CRS metrics type dynamic
Browse files Browse the repository at this point in the history
All CRS metrics are hardcoded to "gauge" type, this patch addresses
that.
  • Loading branch information
rexagod committed Dec 15, 2022
1 parent f01ce58 commit 02fd1a9
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 5 deletions.
76 changes: 76 additions & 0 deletions pkg/customresourcestate/custom_resource_metrics_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
Copyright 2022 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package customresourcestate

import (
"testing"
)

func TestNewCustomResourceMetrics(t *testing.T) {
tests := []struct {
r Resource
wantErr bool
name string
}{
{
// https://github.com/kubernetes/kube-state-metrics/issues/1886
name: "dynamic metric type (not just hardcoded to gauge)",
r: Resource{
GroupVersionKind: GroupVersionKind{
Group: "apps",
Version: "v1",
Kind: "Deployment",
},
Labels: Labels{
LabelsFromPath: map[string][]string{
"name": {"metadata", "name"},
},
},
Metrics: []Generator{
{
Name: "test_metrics",
Help: "metrics for testing",
Each: Metric{
Type: MetricTypeInfo,
Info: &MetricInfo{
MetricMeta: MetricMeta{
Path: []string{
"metadata",
"annotations",
},
},
LabelFromKey: "test",
},
},
},
},
},
wantErr: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v, err := NewCustomResourceMetrics(tt.r)
expectedError := v.(*customResourceMetrics).Families[0].Each.Type() != "info"
if (err != nil) != tt.wantErr || expectedError {
t.Errorf("NewCustomResourceMetrics() error = %v, wantErr %v", err, tt.wantErr)
return
}
})
}
}
11 changes: 9 additions & 2 deletions pkg/customresourcestate/registry_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ type compiledEach compiledMetric
type compiledCommon struct {
labelFromPath map[string]valuePath
path valuePath
t metric.Type
}

func (c compiledCommon) Path() valuePath {
Expand All @@ -126,6 +127,9 @@ func (c compiledCommon) Path() valuePath {
func (c compiledCommon) LabelFromPath() map[string]valuePath {
return c.labelFromPath
}
func (c compiledCommon) Type() metric.Type {
return c.t
}

type eachValue struct {
Labels map[string]string
Expand All @@ -136,6 +140,7 @@ type compiledMetric interface {
Values(v interface{}) (result []eachValue, err []error)
Path() valuePath
LabelFromPath() map[string]valuePath
Type() metric.Type
}

// newCompiledMetric returns a compiledMetric depending given the metric type.
Expand All @@ -146,6 +151,7 @@ func newCompiledMetric(m Metric) (compiledMetric, error) {
return nil, errors.New("expected each.gauge to not be nil")
}
cc, err := compileCommon(m.Gauge.MetricMeta)
cc.t = metric.Gauge
if err != nil {
return nil, fmt.Errorf("each.gauge: %w", err)
}
Expand All @@ -164,6 +170,7 @@ func newCompiledMetric(m Metric) (compiledMetric, error) {
return nil, errors.New("expected each.info to not be nil")
}
cc, err := compileCommon(m.Info.MetricMeta)
cc.t = metric.Info
if err != nil {
return nil, fmt.Errorf("each.info: %w", err)
}
Expand All @@ -176,6 +183,7 @@ func newCompiledMetric(m Metric) (compiledMetric, error) {
return nil, errors.New("expected each.stateSet to not be nil")
}
cc, err := compileCommon(m.StateSet.MetricMeta)
cc.t = metric.StateSet
if err != nil {
return nil, fmt.Errorf("each.stateSet: %w", err)
}
Expand Down Expand Up @@ -569,8 +577,7 @@ func famGen(f compiledFamily) generator.FamilyGenerator {
errLog := klog.V(f.ErrorLogV)
return generator.FamilyGenerator{
Name: f.Name,
// TODO(@rexagod): This should be dynamic.
Type: metric.Gauge,
Type: f.Each.Type(),
Help: f.Help,
GenerateFunc: func(obj interface{}) *metric.Family {
return generate(obj.(*unstructured.Unstructured), f, errLog)
Expand Down
12 changes: 9 additions & 3 deletions pkg/metric/metric.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,19 @@ var (
)

// Type represents the type of a metric e.g. a counter. See
// https://prometheus.io/docs/concepts/metric_types/.
// https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#metric-types.
type Type string

// Gauge defines a Prometheus gauge.
// Gauge defines a OpenMetrics gauge.
var Gauge Type = "gauge"

// Counter defines a Prometheus counter.
// Info defines an OpenMetrics info.
var Info Type = "info"

// StateSet defines an OpenMetrics stateset.
var StateSet Type = "stateset"

// Counter defines a OpenMetrics counter.
var Counter Type = "counter"

// Metric represents a single time series.
Expand Down

0 comments on commit 02fd1a9

Please sign in to comment.