mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 19:31:44 +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"
|
apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
"k8s.io/apiextensions-apiserver/pkg/apiserver/schema"
|
"k8s.io/apiextensions-apiserver/pkg/apiserver/schema"
|
||||||
"k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/library"
|
"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"
|
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
|
// - 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.
|
// 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) {
|
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 {
|
if len(s.Extensions.XValidations) == 0 {
|
||||||
return nil, nil
|
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"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/google/cel-go/common/types"
|
"github.com/google/cel-go/common/types"
|
||||||
"github.com/google/cel-go/common/types/ref"
|
"github.com/google/cel-go/common/types/ref"
|
||||||
@ -29,6 +30,7 @@ import (
|
|||||||
|
|
||||||
apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
"k8s.io/apiextensions-apiserver/pkg/apiserver/schema"
|
"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/apiextensions-apiserver/third_party/forked/celopenapi/model"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"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
|
// 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
|
// 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) {
|
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
|
remainingBudget = costBudget
|
||||||
if s == nil || obj == nil {
|
if s == nil || obj == nil {
|
||||||
return nil, remainingBudget
|
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
|
||||||
k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel
|
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/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/defaulting
|
||||||
k8s.io/apiextensions-apiserver/pkg/apiserver/schema/listtype
|
k8s.io/apiextensions-apiserver/pkg/apiserver/schema/listtype
|
||||||
k8s.io/apiextensions-apiserver/pkg/apiserver/schema/objectmeta
|
k8s.io/apiextensions-apiserver/pkg/apiserver/schema/objectmeta
|
||||||
|
Loading…
Reference in New Issue
Block a user