mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-28 05:57:25 +00:00
Add latency metric for CR Webhook Conversion
This commit is contained in:
parent
094eb614fe
commit
b62c8bca7a
@ -33,11 +33,14 @@ type CRConverterFactory struct {
|
||||
// webhookConverterFactory is the factory for webhook converters.
|
||||
// This field should not be used if CustomResourceWebhookConversion feature is disabled.
|
||||
webhookConverterFactory *webhookConverterFactory
|
||||
converterMetricFactory *converterMetricFactory
|
||||
}
|
||||
|
||||
// NewCRConverterFactory creates a new CRConverterFactory
|
||||
func NewCRConverterFactory(serviceResolver webhook.ServiceResolver, authResolverWrapper webhook.AuthenticationInfoResolverWrapper) (*CRConverterFactory, error) {
|
||||
converterFactory := &CRConverterFactory{}
|
||||
converterFactory := &CRConverterFactory{
|
||||
converterMetricFactory: newConverterMertricFactory(),
|
||||
}
|
||||
if utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceWebhookConversion) {
|
||||
webhookConverterFactory, err := newWebhookConverterFactory(serviceResolver, authResolverWrapper)
|
||||
if err != nil {
|
||||
@ -67,6 +70,10 @@ func (m *CRConverterFactory) NewConverter(crd *apiextensions.CustomResourceDefin
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
converter, err = m.converterMetricFactory.addMetrics("webhook", crd.Name, converter)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("unknown conversion strategy %q for CRD %s", crd.Spec.Conversion.Strategy, crd.Name)
|
||||
}
|
||||
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
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 conversion
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
latencyBuckets = prometheus.ExponentialBuckets(0.001, 2, 15)
|
||||
)
|
||||
|
||||
// converterMetricFactory holds metrics for all CRD converters
|
||||
type converterMetricFactory struct {
|
||||
// A map from a converter name to it's metric. Allows the converterMetric to be created
|
||||
// again with the same metric for a specific converter (e.g. 'webhook').
|
||||
durations map[string]*prometheus.HistogramVec
|
||||
factoryLock sync.Mutex
|
||||
}
|
||||
|
||||
func newConverterMertricFactory() *converterMetricFactory {
|
||||
return &converterMetricFactory{durations: map[string]*prometheus.HistogramVec{}, factoryLock: sync.Mutex{}}
|
||||
}
|
||||
|
||||
var _ crConverterInterface = &converterMetric{}
|
||||
|
||||
type converterMetric struct {
|
||||
delegate crConverterInterface
|
||||
latencies *prometheus.HistogramVec
|
||||
crdName string
|
||||
}
|
||||
|
||||
func (c *converterMetricFactory) addMetrics(converterName string, crdName string, converter crConverterInterface) (crConverterInterface, error) {
|
||||
c.factoryLock.Lock()
|
||||
defer c.factoryLock.Unlock()
|
||||
metric, exists := c.durations[converterName]
|
||||
if !exists {
|
||||
metric = prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: fmt.Sprintf("apiserver_crd_%s_conversion_duration_seconds", converterName),
|
||||
Help: fmt.Sprintf("CRD %s conversion duration in seconds", converterName),
|
||||
Buckets: latencyBuckets,
|
||||
},
|
||||
[]string{"crd_name", "from_version", "to_version", "succeeded"})
|
||||
err := prometheus.Register(metric)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.durations[converterName] = metric
|
||||
}
|
||||
return &converterMetric{latencies: metric, delegate: converter, crdName: crdName}, nil
|
||||
}
|
||||
|
||||
func (m *converterMetric) Convert(in runtime.Object, targetGV schema.GroupVersion) (runtime.Object, error) {
|
||||
start := time.Now()
|
||||
obj, err := m.delegate.Convert(in, targetGV)
|
||||
fromVersion := in.GetObjectKind().GroupVersionKind().Version
|
||||
toVersion := targetGV.Version
|
||||
|
||||
// only record this observation if the version is different
|
||||
if fromVersion != toVersion {
|
||||
m.latencies.WithLabelValues(
|
||||
m.crdName, fromVersion, toVersion, strconv.FormatBool(err == nil)).Observe(time.Since(start).Seconds())
|
||||
}
|
||||
return obj, err
|
||||
}
|
Loading…
Reference in New Issue
Block a user