mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 10:51:29 +00:00
Merge pull request #111035 from jiahuif-forks/feature/matrics/cel
metrics for CEL compilation and evaluation
This commit is contained in:
commit
408850e9f7
@ -31,6 +31,7 @@ import (
|
||||
apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apiserver/schema"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/library"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/metrics"
|
||||
celmodel "k8s.io/apiextensions-apiserver/third_party/forked/celopenapi/model"
|
||||
)
|
||||
|
||||
@ -99,6 +100,9 @@ func getBaseEnv() (*cel.Env, error) {
|
||||
// - nil Program, nil Error: The provided rule was empty so compilation was not attempted
|
||||
// perCallLimit was added for testing purpose only. Callers should always use const PerCallLimit as input.
|
||||
func Compile(s *schema.Structural, isResourceRoot bool, perCallLimit uint64) ([]CompilationResult, error) {
|
||||
t := time.Now()
|
||||
defer metrics.Metrics.ObserveCompilation(time.Since(t))
|
||||
|
||||
if len(s.Extensions.XValidations) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
Copyright 2022 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 metrics
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"k8s.io/component-base/metrics"
|
||||
"k8s.io/component-base/metrics/legacyregistry"
|
||||
)
|
||||
|
||||
// TODO(jiahuif) CEL is to be used in multiple components, revise naming when that happens.
|
||||
const (
|
||||
namespace = "apiserver"
|
||||
subsystem = "cel"
|
||||
)
|
||||
|
||||
// Metrics provides access to CEL metrics.
|
||||
var Metrics = newCelMetrics()
|
||||
|
||||
type CelMetrics struct {
|
||||
compilationTime *metrics.Histogram
|
||||
evaluationTime *metrics.Histogram
|
||||
}
|
||||
|
||||
func newCelMetrics() *CelMetrics {
|
||||
m := &CelMetrics{
|
||||
compilationTime: metrics.NewHistogram(&metrics.HistogramOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "compilation_duration_seconds",
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
}),
|
||||
evaluationTime: metrics.NewHistogram(&metrics.HistogramOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "evaluation_duration_seconds",
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
}),
|
||||
}
|
||||
|
||||
legacyregistry.MustRegister(m.compilationTime)
|
||||
legacyregistry.MustRegister(m.evaluationTime)
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// ObserveCompilation records a CEL compilation with the time the compilation took.
|
||||
func (m *CelMetrics) ObserveCompilation(elapsed time.Duration) {
|
||||
seconds := elapsed.Seconds()
|
||||
m.compilationTime.Observe(seconds)
|
||||
}
|
||||
|
||||
// ObserveEvaluation records a CEL evaluation with the time the evaluation took.
|
||||
func (m *CelMetrics) ObserveEvaluation(elapsed time.Duration) {
|
||||
seconds := elapsed.Seconds()
|
||||
m.evaluationTime.Observe(seconds)
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright 2022 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 metrics
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/component-base/metrics/legacyregistry"
|
||||
)
|
||||
|
||||
func TestObserveCompilation(t *testing.T) {
|
||||
defer legacyregistry.Reset()
|
||||
Metrics.ObserveCompilation(2 * time.Second)
|
||||
c, s := gatherHistogram(t, "apiserver_cel_compilation_duration_seconds")
|
||||
if c != 1 {
|
||||
t.Errorf("unexpected count: %v", c)
|
||||
}
|
||||
if math.Abs(s-2.0) > 1e-7 {
|
||||
t.Fatalf("incorrect sum: %v", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestObserveEvaluation(t *testing.T) {
|
||||
defer legacyregistry.Reset()
|
||||
Metrics.ObserveEvaluation(2 * time.Second)
|
||||
c, s := gatherHistogram(t, "apiserver_cel_evaluation_duration_seconds")
|
||||
if c != 1 {
|
||||
t.Errorf("unexpected count: %v", c)
|
||||
}
|
||||
if math.Abs(s-2.0) > 1e-7 {
|
||||
t.Fatalf("incorrect sum: %v", s)
|
||||
}
|
||||
}
|
||||
|
||||
func gatherHistogram(t *testing.T, name string) (count uint64, sum float64) {
|
||||
metrics, err := legacyregistry.DefaultGatherer.Gather()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to gather metrics: %s", err)
|
||||
}
|
||||
for _, mf := range metrics {
|
||||
if mf.GetName() == name {
|
||||
for _, m := range mf.GetMetric() {
|
||||
h := m.GetHistogram()
|
||||
count += h.GetSampleCount()
|
||||
sum += h.GetSampleSum()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Fatalf("metric not found: %v", name)
|
||||
return 0, 0
|
||||
}
|
@ -22,6 +22,7 @@ import (
|
||||
"math"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
@ -29,6 +30,7 @@ import (
|
||||
|
||||
apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apiserver/schema"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/metrics"
|
||||
"k8s.io/apiextensions-apiserver/third_party/forked/celopenapi/model"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
@ -113,6 +115,8 @@ func validator(s *schema.Structural, isResourceRoot bool, perCallLimit uint64) *
|
||||
// Most callers can ignore the returned remainingBudget value unless another validate call is going to be made
|
||||
// context is passed for supporting context cancellation during cel validation
|
||||
func (s *Validator) Validate(ctx context.Context, fldPath *field.Path, sts *schema.Structural, obj, oldObj interface{}, costBudget int64) (errs field.ErrorList, remainingBudget int64) {
|
||||
t := time.Now()
|
||||
defer metrics.Metrics.ObserveEvaluation(time.Since(t))
|
||||
remainingBudget = costBudget
|
||||
if s == nil || obj == nil {
|
||||
return nil, remainingBudget
|
||||
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
@ -1428,6 +1428,7 @@ k8s.io/apiextensions-apiserver/pkg/apiserver/conversion
|
||||
k8s.io/apiextensions-apiserver/pkg/apiserver/schema
|
||||
k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel
|
||||
k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/library
|
||||
k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/metrics
|
||||
k8s.io/apiextensions-apiserver/pkg/apiserver/schema/defaulting
|
||||
k8s.io/apiextensions-apiserver/pkg/apiserver/schema/listtype
|
||||
k8s.io/apiextensions-apiserver/pkg/apiserver/schema/objectmeta
|
||||
|
Loading…
Reference in New Issue
Block a user