Browse Source

Add reconcile duration metric for ClusterExternalSecret controller (#2334)

* Add reconcile duration metric for ClusterExternalSecret controller

Signed-off-by: shuheiktgw <s-kitagawa@mercari.com>

* chore: fmt imports

Signed-off-by: Moritz Johner <beller.moritz@googlemail.com>

---------

Signed-off-by: shuheiktgw <s-kitagawa@mercari.com>
Signed-off-by: Moritz Johner <beller.moritz@googlemail.com>
Co-authored-by: Moritz Johner <beller.moritz@googlemail.com>
Shuhei Kitagawa 2 years ago
parent
commit
d879f37d9e

+ 6 - 1
cmd/root.go

@@ -36,8 +36,10 @@ import (
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	genv1alpha1 "github.com/external-secrets/external-secrets/apis/generators/v1alpha1"
 	"github.com/external-secrets/external-secrets/pkg/controllers/clusterexternalsecret"
+	"github.com/external-secrets/external-secrets/pkg/controllers/clusterexternalsecret/cesmetrics"
 	"github.com/external-secrets/external-secrets/pkg/controllers/externalsecret"
 	"github.com/external-secrets/external-secrets/pkg/controllers/externalsecret/esmetrics"
+	ctrlmetrics "github.com/external-secrets/external-secrets/pkg/controllers/metrics"
 	"github.com/external-secrets/external-secrets/pkg/controllers/pushsecret"
 	"github.com/external-secrets/external-secrets/pkg/controllers/secretstore"
 	"github.com/external-secrets/external-secrets/pkg/feature"
@@ -125,7 +127,8 @@ var rootCmd = &cobra.Command{
 		}
 		logger := zap.New(zap.UseFlagOptions(&opts))
 		ctrl.SetLogger(logger)
-		esmetrics.SetUpMetrics(enableExtendedMetricLabels)
+		ctrlmetrics.SetUpLabelNames(enableExtendedMetricLabels)
+		esmetrics.SetUpMetrics()
 		config := ctrl.GetConfigOrDie()
 		config.QPS = clientQPS
 		config.Burst = clientBurst
@@ -192,6 +195,8 @@ var rootCmd = &cobra.Command{
 			}
 		}
 		if enableClusterExternalSecretReconciler {
+			cesmetrics.SetUpMetrics()
+
 			if err = (&clusterexternalsecret.Reconciler{
 				Client:          mgr.GetClient(),
 				Log:             ctrl.Log.WithName("controllers").WithName("ClusterExternalSecret"),

+ 49 - 0
pkg/controllers/clusterexternalsecret/cesmetrics/cesmetrics.go

@@ -0,0 +1,49 @@
+/*
+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 cesmetrics
+
+import (
+	"github.com/prometheus/client_golang/prometheus"
+	"sigs.k8s.io/controller-runtime/pkg/metrics"
+
+	ctrlmetrics "github.com/external-secrets/external-secrets/pkg/controllers/metrics"
+)
+
+const (
+	ClusterExternalSecretSubsystem            = "clusterexternalsecret"
+	ClusterExternalSecretReconcileDurationKey = "reconcile_duration"
+)
+
+var gaugeVecMetrics = map[string]*prometheus.GaugeVec{}
+
+// SetUpMetrics is called at the root to set-up the metric logic using the
+// config flags provided.
+func SetUpMetrics() {
+	clusterExternalSecretReconcileDuration := prometheus.NewGaugeVec(prometheus.GaugeOpts{
+		Subsystem: ClusterExternalSecretSubsystem,
+		Name:      ClusterExternalSecretReconcileDurationKey,
+		Help:      "The duration time to reconcile the Cluster External Secret",
+	}, ctrlmetrics.NonConditionMetricLabelNames)
+
+	metrics.Registry.MustRegister(clusterExternalSecretReconcileDuration)
+
+	gaugeVecMetrics = map[string]*prometheus.GaugeVec{
+		ClusterExternalSecretReconcileDurationKey: clusterExternalSecretReconcileDuration,
+	}
+}
+
+func GetGaugeVec(key string) *prometheus.GaugeVec {
+	return gaugeVecMetrics[key]
+}

+ 8 - 0
pkg/controllers/clusterexternalsecret/clusterexternalsecret_controller.go

@@ -32,6 +32,8 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
+	"github.com/external-secrets/external-secrets/pkg/controllers/clusterexternalsecret/cesmetrics"
+	ctrlmetrics "github.com/external-secrets/external-secrets/pkg/controllers/metrics"
 )
 
 // ClusterExternalSecretReconciler reconciles a ClusterExternalSecret object.
@@ -58,6 +60,12 @@ const (
 func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
 	log := r.Log.WithValues("ClusterExternalSecret", req.NamespacedName)
 
+	resourceLabels := ctrlmetrics.RefineNonConditionMetricLabels(map[string]string{"name": req.Name, "namespace": req.Namespace})
+	start := time.Now()
+
+	externalSecretReconcileDuration := cesmetrics.GetGaugeVec(cesmetrics.ClusterExternalSecretReconcileDurationKey)
+	defer func() { externalSecretReconcileDuration.With(resourceLabels).Set(float64(time.Since(start))) }()
+
 	var clusterExternalSecret esv1beta1.ClusterExternalSecret
 
 	err := r.Get(ctx, req.NamespacedName, &clusterExternalSecret)

+ 7 - 0
pkg/controllers/clusterexternalsecret/clusterexternalsecret_controller_test.go

@@ -28,7 +28,9 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
+	"github.com/external-secrets/external-secrets/pkg/controllers/clusterexternalsecret/cesmetrics"
 	ctest "github.com/external-secrets/external-secrets/pkg/controllers/commontest"
+	ctrlmetrics "github.com/external-secrets/external-secrets/pkg/controllers/metrics"
 )
 
 var (
@@ -379,3 +381,8 @@ func sliceContainsString(toFind string, collection []string) bool {
 
 	return false
 }
+
+func init() {
+	ctrlmetrics.SetUpLabelNames(false)
+	cesmetrics.SetUpMetrics()
+}

+ 16 - 91
pkg/controllers/externalsecret/esmetrics/esmetrics.go

@@ -15,13 +15,12 @@ limitations under the License.
 package esmetrics
 
 import (
-	"regexp"
-
 	"github.com/prometheus/client_golang/prometheus"
 	v1 "k8s.io/api/core/v1"
 	"sigs.k8s.io/controller-runtime/pkg/metrics"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
+	ctrlmetrics "github.com/external-secrets/external-secrets/pkg/controllers/metrics"
 )
 
 const (
@@ -32,78 +31,37 @@ const (
 	ExternalSecretReconcileDurationKey = "reconcile_duration"
 )
 
-var (
-	NonConditionMetricLabelNames = make([]string, 0)
-
-	ConditionMetricLabelNames = make([]string, 0)
+var counterVecMetrics = map[string]*prometheus.CounterVec{}
 
-	NonConditionMetricLabels = make(map[string]string)
-
-	ConditionMetricLabels = make(map[string]string)
-)
-
-var counterVecMetrics map[string]*prometheus.CounterVec = map[string]*prometheus.CounterVec{}
-
-var gaugeVecMetrics map[string]*prometheus.GaugeVec = map[string]*prometheus.GaugeVec{}
+var gaugeVecMetrics = map[string]*prometheus.GaugeVec{}
 
 // Called at the root to set-up the metric logic using the
 // config flags provided.
-func SetUpMetrics(addKubeStandardLabels bool) {
-	// Figure out what the labels for the metrics are
-	if addKubeStandardLabels {
-		NonConditionMetricLabelNames = []string{
-			"name", "namespace",
-			"app_kubernetes_io_name", "app_kubernetes_io_instance",
-			"app_kubernetes_io_version", "app_kubernetes_io_component",
-			"app_kubernetes_io_part_of", "app_kubernetes_io_managed_by",
-		}
-
-		ConditionMetricLabelNames = []string{
-			"name", "namespace",
-			"condition", "status",
-			"app_kubernetes_io_name", "app_kubernetes_io_instance",
-			"app_kubernetes_io_version", "app_kubernetes_io_component",
-			"app_kubernetes_io_part_of", "app_kubernetes_io_managed_by",
-		}
-	} else {
-		NonConditionMetricLabelNames = []string{"name", "namespace"}
-
-		ConditionMetricLabelNames = []string{"name", "namespace", "condition", "status"}
-	}
-
-	// Set default values for each label
-	for _, k := range NonConditionMetricLabelNames {
-		NonConditionMetricLabels[k] = ""
-	}
-
-	for _, k := range ConditionMetricLabelNames {
-		ConditionMetricLabels[k] = ""
-	}
-
+func SetUpMetrics() {
 	// Obtain the prometheus metrics and register
 	syncCallsTotal := prometheus.NewCounterVec(prometheus.CounterOpts{
 		Subsystem: ExternalSecretSubsystem,
 		Name:      SyncCallsKey,
 		Help:      "Total number of the External Secret sync calls",
-	}, NonConditionMetricLabelNames)
+	}, ctrlmetrics.NonConditionMetricLabelNames)
 
 	syncCallsError := prometheus.NewCounterVec(prometheus.CounterOpts{
 		Subsystem: ExternalSecretSubsystem,
 		Name:      SyncCallsErrorKey,
 		Help:      "Total number of the External Secret sync errors",
-	}, NonConditionMetricLabelNames)
+	}, ctrlmetrics.NonConditionMetricLabelNames)
 
 	externalSecretCondition := prometheus.NewGaugeVec(prometheus.GaugeOpts{
 		Subsystem: ExternalSecretSubsystem,
 		Name:      ExternalSecretStatusConditionKey,
 		Help:      "The status condition of a specific External Secret",
-	}, ConditionMetricLabelNames)
+	}, ctrlmetrics.ConditionMetricLabelNames)
 
 	externalSecretReconcileDuration := prometheus.NewGaugeVec(prometheus.GaugeOpts{
 		Subsystem: ExternalSecretSubsystem,
 		Name:      ExternalSecretReconcileDurationKey,
 		Help:      "The duration time to reconcile the External Secret",
-	}, NonConditionMetricLabelNames)
+	}, ctrlmetrics.NonConditionMetricLabelNames)
 
 	metrics.Registry.MustRegister(syncCallsTotal, syncCallsError, externalSecretCondition, externalSecretReconcileDuration)
 
@@ -125,19 +83,19 @@ func UpdateExternalSecretCondition(es *esv1beta1.ExternalSecret, condition *esv1
 	for k, v := range es.Labels {
 		esInfo[k] = v
 	}
-	conditionLabels := RefineConditionMetricLabels(esInfo)
+	conditionLabels := ctrlmetrics.RefineConditionMetricLabels(esInfo)
 	externalSecretCondition := GetGaugeVec(ExternalSecretStatusConditionKey)
 
 	switch condition.Type {
 	case esv1beta1.ExternalSecretDeleted:
 		// Remove condition=Ready metrics when the object gets deleted.
-		externalSecretCondition.Delete(RefineLabels(conditionLabels,
+		externalSecretCondition.Delete(ctrlmetrics.RefineLabels(conditionLabels,
 			map[string]string{
 				"condition": string(esv1beta1.ExternalSecretReady),
 				"status":    string(v1.ConditionFalse),
 			}))
 
-		externalSecretCondition.Delete(RefineLabels(conditionLabels,
+		externalSecretCondition.Delete(ctrlmetrics.RefineLabels(conditionLabels,
 			map[string]string{
 				"condition": string(esv1beta1.ExternalSecretReady),
 				"status":    string(v1.ConditionTrue),
@@ -145,13 +103,13 @@ func UpdateExternalSecretCondition(es *esv1beta1.ExternalSecret, condition *esv1
 
 	case esv1beta1.ExternalSecretReady:
 		// Remove condition=Deleted metrics when the object gets ready.
-		externalSecretCondition.Delete(RefineLabels(conditionLabels,
+		externalSecretCondition.Delete(ctrlmetrics.RefineLabels(conditionLabels,
 			map[string]string{
 				"condition": string(esv1beta1.ExternalSecretDeleted),
 				"status":    string(v1.ConditionFalse),
 			}))
 
-		externalSecretCondition.Delete(RefineLabels(conditionLabels,
+		externalSecretCondition.Delete(ctrlmetrics.RefineLabels(conditionLabels,
 			map[string]string{
 				"condition": string(esv1beta1.ExternalSecretDeleted),
 				"status":    string(v1.ConditionTrue),
@@ -160,13 +118,13 @@ func UpdateExternalSecretCondition(es *esv1beta1.ExternalSecret, condition *esv1
 		// Toggle opposite Status to 0
 		switch condition.Status {
 		case v1.ConditionFalse:
-			externalSecretCondition.With(RefineLabels(conditionLabels,
+			externalSecretCondition.With(ctrlmetrics.RefineLabels(conditionLabels,
 				map[string]string{
 					"condition": string(esv1beta1.ExternalSecretReady),
 					"status":    string(v1.ConditionTrue),
 				})).Set(0)
 		case v1.ConditionTrue:
-			externalSecretCondition.With(RefineLabels(conditionLabels,
+			externalSecretCondition.With(ctrlmetrics.RefineLabels(conditionLabels,
 				map[string]string{
 					"condition": string(esv1beta1.ExternalSecretReady),
 					"status":    string(v1.ConditionFalse),
@@ -181,7 +139,7 @@ func UpdateExternalSecretCondition(es *esv1beta1.ExternalSecret, condition *esv1
 		break
 	}
 
-	externalSecretCondition.With(RefineLabels(conditionLabels,
+	externalSecretCondition.With(ctrlmetrics.RefineLabels(conditionLabels,
 		map[string]string{
 			"condition": string(condition.Type),
 			"status":    string(condition.Status),
@@ -195,36 +153,3 @@ func GetCounterVec(key string) *prometheus.CounterVec {
 func GetGaugeVec(key string) *prometheus.GaugeVec {
 	return gaugeVecMetrics[key]
 }
-
-// Refine the given Prometheus Labels with values from a map `newLabels`
-// Only overwrite a value if the corresponding key is present in the
-// Prometheus' Labels already to avoid adding label names which are
-// not defined in a metric's description. Note that non-alphanumeric
-// characters from keys of `newLabels` are replaced by an underscore
-// because Prometheus does not accept non-alphanumeric, non-underscore
-// characters in label names.
-func RefineLabels(promLabels prometheus.Labels, newLabels map[string]string) prometheus.Labels {
-	nonAlphanumericRegex := regexp.MustCompile(`[^a-zA-Z0-9 ]+`)
-	var refinement = prometheus.Labels{}
-
-	for k, v := range promLabels {
-		refinement[k] = v
-	}
-
-	for k, v := range newLabels {
-		cleanKey := nonAlphanumericRegex.ReplaceAllString(k, "_")
-		if _, ok := refinement[cleanKey]; ok {
-			refinement[cleanKey] = v
-		}
-	}
-
-	return refinement
-}
-
-func RefineNonConditionMetricLabels(labels map[string]string) prometheus.Labels {
-	return RefineLabels(NonConditionMetricLabels, labels)
-}
-
-func RefineConditionMetricLabels(labels map[string]string) prometheus.Labels {
-	return RefineLabels(ConditionMetricLabels, labels)
-}

+ 3 - 2
pkg/controllers/externalsecret/externalsecret_controller.go

@@ -39,6 +39,7 @@ import (
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	// Metrics.
 	"github.com/external-secrets/external-secrets/pkg/controllers/externalsecret/esmetrics"
+	ctrlmetrics "github.com/external-secrets/external-secrets/pkg/controllers/metrics"
 	// Loading registered generators.
 	_ "github.com/external-secrets/external-secrets/pkg/generator/register"
 	// Loading registered providers.
@@ -96,7 +97,7 @@ type Reconciler struct {
 func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
 	log := r.Log.WithValues("ExternalSecret", req.NamespacedName)
 
-	resourceLabels := esmetrics.RefineNonConditionMetricLabels(map[string]string{"name": req.Name, "namespace": req.Namespace})
+	resourceLabels := ctrlmetrics.RefineNonConditionMetricLabels(map[string]string{"name": req.Name, "namespace": req.Namespace})
 	start := time.Now()
 
 	externalSecretReconcileDuration := esmetrics.GetGaugeVec(esmetrics.ExternalSecretReconcileDurationKey)
@@ -132,7 +133,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
 	}
 
 	// if extended metrics is enabled, refine the time series vector
-	resourceLabels = esmetrics.RefineLabels(resourceLabels, externalSecret.Labels)
+	resourceLabels = ctrlmetrics.RefineLabels(resourceLabels, externalSecret.Labels)
 
 	defer externalSecretReconcileDuration.With(resourceLabels).Set(float64(time.Since(start)))
 	defer syncCallsTotal.With(resourceLabels).Inc()

+ 3 - 1
pkg/controllers/externalsecret/externalsecret_controller_test.go

@@ -37,6 +37,7 @@ import (
 	genv1alpha1 "github.com/external-secrets/external-secrets/apis/generators/v1alpha1"
 	ctest "github.com/external-secrets/external-secrets/pkg/controllers/commontest"
 	"github.com/external-secrets/external-secrets/pkg/controllers/externalsecret/esmetrics"
+	ctrlmetrics "github.com/external-secrets/external-secrets/pkg/controllers/metrics"
 	"github.com/external-secrets/external-secrets/pkg/provider/testing/fake"
 )
 
@@ -2308,7 +2309,8 @@ func init() {
 		},
 	})
 
-	esmetrics.SetUpMetrics(false)
+	ctrlmetrics.SetUpLabelNames(false)
+	esmetrics.SetUpMetrics()
 	testSyncCallsTotal = esmetrics.GetCounterVec(esmetrics.SyncCallsKey)
 	testSyncCallsError = esmetrics.GetCounterVec(esmetrics.SyncCallsErrorKey)
 	testExternalSecretCondition = esmetrics.GetGaugeVec(esmetrics.ExternalSecretStatusConditionKey)

+ 101 - 0
pkg/controllers/metrics/labels.go

@@ -0,0 +1,101 @@
+/*
+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 metrics
+
+import (
+	"regexp"
+
+	"github.com/prometheus/client_golang/prometheus"
+)
+
+var (
+	NonConditionMetricLabelNames = make([]string, 0)
+
+	ConditionMetricLabelNames = make([]string, 0)
+
+	NonConditionMetricLabels = make(map[string]string)
+
+	ConditionMetricLabels = make(map[string]string)
+)
+
+var nonAlphanumericRegex *regexp.Regexp
+
+func init() {
+	nonAlphanumericRegex = regexp.MustCompile(`[^a-zA-Z0-9 ]+`)
+}
+
+// SetUpLabelNames initializes both non-conditional and conditional metric labels and label names.
+func SetUpLabelNames(addKubeStandardLabels bool) {
+	NonConditionMetricLabelNames = []string{"name", "namespace"}
+	ConditionMetricLabelNames = []string{"name", "namespace", "condition", "status"}
+
+	// Figure out what the labels for the metrics are
+	if addKubeStandardLabels {
+		NonConditionMetricLabelNames = append(
+			NonConditionMetricLabelNames,
+			"app_kubernetes_io_name", "app_kubernetes_io_instance",
+			"app_kubernetes_io_version", "app_kubernetes_io_component",
+			"app_kubernetes_io_part_of", "app_kubernetes_io_managed_by",
+		)
+
+		ConditionMetricLabelNames = append(
+			ConditionMetricLabelNames,
+			"app_kubernetes_io_name", "app_kubernetes_io_instance",
+			"app_kubernetes_io_version", "app_kubernetes_io_component",
+			"app_kubernetes_io_part_of", "app_kubernetes_io_managed_by",
+		)
+	}
+
+	// Set default values for each label
+	for _, k := range NonConditionMetricLabelNames {
+		NonConditionMetricLabels[k] = ""
+	}
+
+	for _, k := range ConditionMetricLabelNames {
+		ConditionMetricLabels[k] = ""
+	}
+}
+
+// RefineLabels refines the given Prometheus Labels with values from a map `newLabels`
+// Only overwrite a value if the corresponding key is present in the
+// Prometheus' Labels already to avoid adding label names which are
+// not defined in a metric's description. Note that non-alphanumeric
+// characters from keys of `newLabels` are replaced by an underscore
+// because Prometheus does not accept non-alphanumeric, non-underscore
+// characters in label names.
+func RefineLabels(promLabels prometheus.Labels, newLabels map[string]string) prometheus.Labels {
+	var refinement = prometheus.Labels{}
+
+	for k, v := range promLabels {
+		refinement[k] = v
+	}
+
+	for k, v := range newLabels {
+		cleanKey := nonAlphanumericRegex.ReplaceAllString(k, "_")
+		if _, ok := refinement[cleanKey]; ok {
+			refinement[cleanKey] = v
+		}
+	}
+
+	return refinement
+}
+
+func RefineNonConditionMetricLabels(labels map[string]string) prometheus.Labels {
+	return RefineLabels(NonConditionMetricLabels, labels)
+}
+
+func RefineConditionMetricLabels(labels map[string]string) prometheus.Labels {
+	return RefineLabels(ConditionMetricLabels, labels)
+}

+ 199 - 0
pkg/controllers/metrics/labels_test.go

@@ -0,0 +1,199 @@
+/*
+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 metrics
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/prometheus/client_golang/prometheus"
+)
+
+func TestSetUpLabelNames(t *testing.T) {
+	testCases := []struct {
+		description                          string
+		addKubeStandardLabels                bool
+		expectedNonConditionMetricLabelNames []string
+		expectedConditionMetricLabelNames    []string
+		expectedNonConditionMetricLabels     map[string]string
+		expectedConditionMetricLabels        map[string]string
+	}{
+		{
+			description:           "Add standard labels disabled",
+			addKubeStandardLabels: false,
+			expectedNonConditionMetricLabelNames: []string{
+				"name",
+				"namespace",
+			},
+			expectedConditionMetricLabelNames: []string{
+				"name",
+				"namespace",
+				"condition",
+				"status",
+			},
+			expectedNonConditionMetricLabels: map[string]string{
+				"name":      "",
+				"namespace": "",
+			},
+			expectedConditionMetricLabels: map[string]string{
+				"name":      "",
+				"namespace": "",
+				"condition": "",
+				"status":    "",
+			},
+		},
+		{
+			description:           "Add standard labels enabled",
+			addKubeStandardLabels: true,
+			expectedNonConditionMetricLabelNames: []string{
+				"name",
+				"namespace",
+				"app_kubernetes_io_name",
+				"app_kubernetes_io_instance",
+				"app_kubernetes_io_version",
+				"app_kubernetes_io_component",
+				"app_kubernetes_io_part_of",
+				"app_kubernetes_io_managed_by",
+			},
+			expectedConditionMetricLabelNames: []string{
+				"name",
+				"namespace",
+				"condition",
+				"status",
+				"app_kubernetes_io_name",
+				"app_kubernetes_io_instance",
+				"app_kubernetes_io_version",
+				"app_kubernetes_io_component",
+				"app_kubernetes_io_part_of",
+				"app_kubernetes_io_managed_by",
+			},
+			expectedNonConditionMetricLabels: map[string]string{
+				"name":                         "",
+				"namespace":                    "",
+				"app_kubernetes_io_name":       "",
+				"app_kubernetes_io_instance":   "",
+				"app_kubernetes_io_version":    "",
+				"app_kubernetes_io_component":  "",
+				"app_kubernetes_io_part_of":    "",
+				"app_kubernetes_io_managed_by": "",
+			},
+			expectedConditionMetricLabels: map[string]string{
+				"name":                         "",
+				"namespace":                    "",
+				"condition":                    "",
+				"status":                       "",
+				"app_kubernetes_io_name":       "",
+				"app_kubernetes_io_instance":   "",
+				"app_kubernetes_io_version":    "",
+				"app_kubernetes_io_component":  "",
+				"app_kubernetes_io_part_of":    "",
+				"app_kubernetes_io_managed_by": "",
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.description, func(t *testing.T) {
+			SetUpLabelNames(tc.addKubeStandardLabels)
+
+			if diff := cmp.Diff(NonConditionMetricLabelNames, tc.expectedNonConditionMetricLabelNames); diff != "" {
+				t.Errorf("NonConditionMetricLabelNames does not match the expected value. (-got +want)\n%s", diff)
+			}
+
+			if diff := cmp.Diff(ConditionMetricLabelNames, tc.expectedConditionMetricLabelNames); diff != "" {
+				t.Errorf("ConditionMetricLabelNames does not match the expected value. (-got +want)\n%s", diff)
+			}
+
+			if diff := cmp.Diff(NonConditionMetricLabels, tc.expectedNonConditionMetricLabels); diff != "" {
+				t.Errorf("NonConditionMetricLabels are not initialized with empty strings. (-got +want)\n%s", diff)
+			}
+
+			if diff := cmp.Diff(ConditionMetricLabels, tc.expectedConditionMetricLabels); diff != "" {
+				t.Errorf("ConditionMetricLabels are not initialized with empty strings. (-got +want)\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestRefineLabels(t *testing.T) {
+	testCases := []struct {
+		description        string
+		promLabels         prometheus.Labels
+		newLabels          map[string]string
+		expectedRefinement prometheus.Labels
+	}{
+		{
+			description: "No new labels",
+			promLabels: prometheus.Labels{
+				"label1": "value1",
+				"label2": "value2",
+			},
+			newLabels:          map[string]string{},
+			expectedRefinement: prometheus.Labels{"label1": "value1", "label2": "value2"},
+		},
+		{
+			description: "Add unregistered labels",
+			promLabels: prometheus.Labels{
+				"label1": "value1",
+				"label2": "value2",
+			},
+			newLabels: map[string]string{
+				"new_label1": "new_value1",
+				"new_label2": "new_value2",
+			},
+			expectedRefinement: prometheus.Labels{
+				"label1": "value1",
+				"label2": "value2",
+			},
+		},
+		{
+			description: "Overwrite existing labels",
+			promLabels: prometheus.Labels{
+				"label1": "value1",
+				"label2": "value2",
+			},
+			newLabels: map[string]string{
+				"label1": "new_value1",
+				"label2": "new_value2",
+			},
+			expectedRefinement: prometheus.Labels{
+				"label1": "new_value1",
+				"label2": "new_value2",
+			},
+		},
+		{
+			description: "Clean non-alphanumeric characters in new labels",
+			promLabels: prometheus.Labels{
+				"label_1": "value1",
+			},
+			newLabels: map[string]string{
+				"label@1": "new_value",
+			},
+			expectedRefinement: prometheus.Labels{
+				"label_1": "new_value",
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.description, func(t *testing.T) {
+			refinement := RefineLabels(tc.promLabels, tc.newLabels)
+
+			if diff := cmp.Diff(refinement, tc.expectedRefinement); diff != "" {
+				t.Errorf("Refinement does not match the expected value. (-got +want)\n%s", diff)
+			}
+		})
+	}
+}