rebase: update kubernetes to v1.25.0

update kubernetes to latest v1.25.0
release.

Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
This commit is contained in:
Madhu Rajanna
2022-08-24 07:54:25 +05:30
committed by mergify[bot]
parent f47839d73d
commit e3bf375035
645 changed files with 42507 additions and 9219 deletions

View File

@ -17,14 +17,6 @@ limitations under the License.
package config
import (
"fmt"
"strconv"
"strings"
"time"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@ -86,127 +78,3 @@ type DebuggingConfiguration struct {
// enableProfiling is true.
EnableContentionProfiling bool
}
// LoggingConfiguration contains logging options
// Refer [Logs Options](https://github.com/kubernetes/component-base/blob/master/logs/options.go) for more information.
type LoggingConfiguration struct {
// Format Flag specifies the structure of log messages.
// default value of format is `text`
Format string
// Maximum number of nanoseconds (i.e. 1s = 1000000000) between log
// flushes. Ignored if the selected logging backend writes log
// messages without buffering.
FlushFrequency time.Duration
// Verbosity is the threshold that determines which log messages are
// logged. Default is zero which logs only the most important
// messages. Higher values enable additional messages. Error messages
// are always logged.
Verbosity VerbosityLevel
// VModule overrides the verbosity threshold for individual files.
// Only supported for "text" log format.
VModule VModuleConfiguration
// [Experimental] Options holds additional parameters that are specific
// to the different logging formats. Only the options for the selected
// format get used, but all of them get validated.
Options FormatOptions
}
// FormatOptions contains options for the different logging formats.
type FormatOptions struct {
// [Experimental] JSON contains options for logging format "json".
JSON JSONOptions
}
// JSONOptions contains options for logging format "json".
type JSONOptions struct {
// [Experimental] SplitStream redirects error messages to stderr while
// info messages go to stdout, with buffering. The default is to write
// both to stdout, without buffering.
SplitStream bool
// [Experimental] InfoBufferSize sets the size of the info stream when
// using split streams. The default is zero, which disables buffering.
InfoBufferSize resource.QuantityValue
}
// VModuleConfiguration is a collection of individual file names or patterns
// and the corresponding verbosity threshold.
type VModuleConfiguration []VModuleItem
var _ pflag.Value = &VModuleConfiguration{}
// VModuleItem defines verbosity for one or more files which match a certain
// glob pattern.
type VModuleItem struct {
// FilePattern is a base file name (i.e. minus the ".go" suffix and
// directory) or a "glob" pattern for such a name. It must not contain
// comma and equal signs because those are separators for the
// corresponding klog command line argument.
FilePattern string
// Verbosity is the threshold for log messages emitted inside files
// that match the pattern.
Verbosity VerbosityLevel
}
// String returns the -vmodule parameter (comma-separated list of pattern=N).
func (vmodule *VModuleConfiguration) String() string {
var patterns []string
for _, item := range *vmodule {
patterns = append(patterns, fmt.Sprintf("%s=%d", item.FilePattern, item.Verbosity))
}
return strings.Join(patterns, ",")
}
// Set parses the -vmodule parameter (comma-separated list of pattern=N).
func (vmodule *VModuleConfiguration) Set(value string) error {
// This code mirrors https://github.com/kubernetes/klog/blob/9ad246211af1ed84621ee94a26fcce0038b69cd1/klog.go#L287-L313
for _, pat := range strings.Split(value, ",") {
if len(pat) == 0 {
// Empty strings such as from a trailing comma can be ignored.
continue
}
patLev := strings.Split(pat, "=")
if len(patLev) != 2 || len(patLev[0]) == 0 || len(patLev[1]) == 0 {
return fmt.Errorf("%q does not have the pattern=N format", pat)
}
pattern := patLev[0]
// 31 instead of 32 to ensure that it also fits into int32.
v, err := strconv.ParseUint(patLev[1], 10, 31)
if err != nil {
return fmt.Errorf("parsing verbosity in %q: %v", pat, err)
}
*vmodule = append(*vmodule, VModuleItem{FilePattern: pattern, Verbosity: VerbosityLevel(v)})
}
return nil
}
func (vmodule *VModuleConfiguration) Type() string {
return "pattern=N,..."
}
// VerbosityLevel represents a klog or logr verbosity threshold.
type VerbosityLevel uint32
var _ pflag.Value = new(VerbosityLevel)
func (l *VerbosityLevel) String() string {
return strconv.FormatInt(int64(*l), 10)
}
func (l *VerbosityLevel) Get() interface{} {
return *l
}
func (l *VerbosityLevel) Set(value string) error {
// Limited to int32 for compatibility with klog.
v, err := strconv.ParseUint(value, 10, 31)
if err != nil {
return err
}
*l = VerbosityLevel(v)
return nil
}
func (l *VerbosityLevel) Type() string {
return "Level"
}

View File

@ -51,11 +51,3 @@ func Convert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfig
func Convert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(in *config.LeaderElectionConfiguration, out *LeaderElectionConfiguration, s conversion.Scope) error {
return autoConvert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(in, out, s)
}
func Convert_v1alpha1_LoggingConfiguration_To_config_LoggingConfiguration(in *LoggingConfiguration, out *config.LoggingConfiguration, s conversion.Scope) error {
return autoConvert_v1alpha1_LoggingConfiguration_To_config_LoggingConfiguration(in, out, s)
}
func Convert_config_LoggingConfiguration_To_v1alpha1_LoggingConfiguration(in *config.LoggingConfiguration, out *LoggingConfiguration, s conversion.Scope) error {
return autoConvert_config_LoggingConfiguration_To_v1alpha1_LoggingConfiguration(in, out, s)
}

View File

@ -19,7 +19,6 @@ package v1alpha1
import (
"time"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilpointer "k8s.io/utils/pointer"
)
@ -97,32 +96,3 @@ func NewRecommendedDebuggingConfiguration() *DebuggingConfiguration {
RecommendedDebuggingConfiguration(ret)
return ret
}
// RecommendedLoggingConfiguration defaults logging configuration.
// This will set the recommended default
// values, but they may be subject to change between API versions. This function
// is intentionally not registered in the scheme as a "normal" `SetDefaults_Foo`
// function to allow consumers of this type to set whatever defaults for their
// embedded configs. Forcing consumers to use these defaults would be problematic
// as defaulting in the scheme is done as part of the conversion, and there would
// be no easy way to opt-out. Instead, if you want to use this defaulting method
// run it in your wrapper struct of this type in its `SetDefaults_` method.
func RecommendedLoggingConfiguration(obj *LoggingConfiguration) {
if obj.Format == "" {
obj.Format = "text"
}
var empty resource.QuantityValue
if obj.Options.JSON.InfoBufferSize == empty {
obj.Options.JSON.InfoBufferSize = resource.QuantityValue{
// This is similar, but not quite the same as a default
// constructed instance.
Quantity: *resource.NewQuantity(0, resource.DecimalSI),
}
// This sets the unexported Quantity.s which will be compared
// by reflect.DeepEqual in some tests.
_ = obj.Options.JSON.InfoBufferSize.String()
}
if obj.FlushFrequency == 0 {
obj.FlushFrequency = 5 * time.Second
}
}

View File

@ -17,9 +17,6 @@ limitations under the License.
package v1alpha1
import (
"time"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@ -83,61 +80,3 @@ type ClientConnectionConfiguration struct {
// burst allows extra queries to accumulate when a client is exceeding its rate.
Burst int32 `json:"burst"`
}
// LoggingConfiguration contains logging options
// Refer [Logs Options](https://github.com/kubernetes/component-base/blob/master/logs/options.go) for more information.
type LoggingConfiguration struct {
// Format Flag specifies the structure of log messages.
// default value of format is `text`
Format string `json:"format,omitempty"`
// Maximum number of nanoseconds (i.e. 1s = 1000000000) between log
// flushes. Ignored if the selected logging backend writes log
// messages without buffering.
FlushFrequency time.Duration `json:"flushFrequency"`
// Verbosity is the threshold that determines which log messages are
// logged. Default is zero which logs only the most important
// messages. Higher values enable additional messages. Error messages
// are always logged.
Verbosity uint32 `json:"verbosity"`
// VModule overrides the verbosity threshold for individual files.
// Only supported for "text" log format.
VModule VModuleConfiguration `json:"vmodule,omitempty"`
// [Experimental] Options holds additional parameters that are specific
// to the different logging formats. Only the options for the selected
// format get used, but all of them get validated.
Options FormatOptions `json:"options,omitempty"`
}
// FormatOptions contains options for the different logging formats.
type FormatOptions struct {
// [Experimental] JSON contains options for logging format "json".
JSON JSONOptions `json:"json,omitempty"`
}
// JSONOptions contains options for logging format "json".
type JSONOptions struct {
// [Experimental] SplitStream redirects error messages to stderr while
// info messages go to stdout, with buffering. The default is to write
// both to stdout, without buffering.
SplitStream bool `json:"splitStream,omitempty"`
// [Experimental] InfoBufferSize sets the size of the info stream when
// using split streams. The default is zero, which disables buffering.
InfoBufferSize resource.QuantityValue `json:"infoBufferSize,omitempty"`
}
// VModuleConfiguration is a collection of individual file names or patterns
// and the corresponding verbosity threshold.
type VModuleConfiguration []VModuleItem
// VModuleItem defines verbosity for one or more files which match a certain
// glob pattern.
type VModuleItem struct {
// FilePattern is a base file name (i.e. minus the ".go" suffix and
// directory) or a "glob" pattern for such a name. It must not contain
// comma and equal signs because those are separators for the
// corresponding klog command line argument.
FilePattern string `json:"filePattern"`
// Verbosity is the threshold for log messages emitted inside files
// that match the pattern.
Verbosity uint32 `json:"verbosity"`
}

View File

@ -22,9 +22,6 @@ limitations under the License.
package v1alpha1
import (
time "time"
unsafe "unsafe"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
@ -38,36 +35,6 @@ func init() {
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(s *runtime.Scheme) error {
if err := s.AddGeneratedConversionFunc((*FormatOptions)(nil), (*config.FormatOptions)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_FormatOptions_To_config_FormatOptions(a.(*FormatOptions), b.(*config.FormatOptions), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*config.FormatOptions)(nil), (*FormatOptions)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_FormatOptions_To_v1alpha1_FormatOptions(a.(*config.FormatOptions), b.(*FormatOptions), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*JSONOptions)(nil), (*config.JSONOptions)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_JSONOptions_To_config_JSONOptions(a.(*JSONOptions), b.(*config.JSONOptions), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*config.JSONOptions)(nil), (*JSONOptions)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_JSONOptions_To_v1alpha1_JSONOptions(a.(*config.JSONOptions), b.(*JSONOptions), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*VModuleItem)(nil), (*config.VModuleItem)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_VModuleItem_To_config_VModuleItem(a.(*VModuleItem), b.(*config.VModuleItem), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*config.VModuleItem)(nil), (*VModuleItem)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_VModuleItem_To_v1alpha1_VModuleItem(a.(*config.VModuleItem), b.(*VModuleItem), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*config.ClientConnectionConfiguration)(nil), (*ClientConnectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(a.(*config.ClientConnectionConfiguration), b.(*ClientConnectionConfiguration), scope)
}); err != nil {
@ -83,11 +50,6 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddConversionFunc((*config.LoggingConfiguration)(nil), (*LoggingConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_LoggingConfiguration_To_v1alpha1_LoggingConfiguration(a.(*config.LoggingConfiguration), b.(*LoggingConfiguration), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*ClientConnectionConfiguration)(nil), (*config.ClientConnectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(a.(*ClientConnectionConfiguration), b.(*config.ClientConnectionConfiguration), scope)
}); err != nil {
@ -103,11 +65,6 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddConversionFunc((*LoggingConfiguration)(nil), (*config.LoggingConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_LoggingConfiguration_To_config_LoggingConfiguration(a.(*LoggingConfiguration), b.(*config.LoggingConfiguration), scope)
}); err != nil {
return err
}
return nil
}
@ -149,52 +106,6 @@ func autoConvert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguratio
return nil
}
func autoConvert_v1alpha1_FormatOptions_To_config_FormatOptions(in *FormatOptions, out *config.FormatOptions, s conversion.Scope) error {
if err := Convert_v1alpha1_JSONOptions_To_config_JSONOptions(&in.JSON, &out.JSON, s); err != nil {
return err
}
return nil
}
// Convert_v1alpha1_FormatOptions_To_config_FormatOptions is an autogenerated conversion function.
func Convert_v1alpha1_FormatOptions_To_config_FormatOptions(in *FormatOptions, out *config.FormatOptions, s conversion.Scope) error {
return autoConvert_v1alpha1_FormatOptions_To_config_FormatOptions(in, out, s)
}
func autoConvert_config_FormatOptions_To_v1alpha1_FormatOptions(in *config.FormatOptions, out *FormatOptions, s conversion.Scope) error {
if err := Convert_config_JSONOptions_To_v1alpha1_JSONOptions(&in.JSON, &out.JSON, s); err != nil {
return err
}
return nil
}
// Convert_config_FormatOptions_To_v1alpha1_FormatOptions is an autogenerated conversion function.
func Convert_config_FormatOptions_To_v1alpha1_FormatOptions(in *config.FormatOptions, out *FormatOptions, s conversion.Scope) error {
return autoConvert_config_FormatOptions_To_v1alpha1_FormatOptions(in, out, s)
}
func autoConvert_v1alpha1_JSONOptions_To_config_JSONOptions(in *JSONOptions, out *config.JSONOptions, s conversion.Scope) error {
out.SplitStream = in.SplitStream
out.InfoBufferSize = in.InfoBufferSize
return nil
}
// Convert_v1alpha1_JSONOptions_To_config_JSONOptions is an autogenerated conversion function.
func Convert_v1alpha1_JSONOptions_To_config_JSONOptions(in *JSONOptions, out *config.JSONOptions, s conversion.Scope) error {
return autoConvert_v1alpha1_JSONOptions_To_config_JSONOptions(in, out, s)
}
func autoConvert_config_JSONOptions_To_v1alpha1_JSONOptions(in *config.JSONOptions, out *JSONOptions, s conversion.Scope) error {
out.SplitStream = in.SplitStream
out.InfoBufferSize = in.InfoBufferSize
return nil
}
// Convert_config_JSONOptions_To_v1alpha1_JSONOptions is an autogenerated conversion function.
func Convert_config_JSONOptions_To_v1alpha1_JSONOptions(in *config.JSONOptions, out *JSONOptions, s conversion.Scope) error {
return autoConvert_config_JSONOptions_To_v1alpha1_JSONOptions(in, out, s)
}
func autoConvert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(in *LeaderElectionConfiguration, out *config.LeaderElectionConfiguration, s conversion.Scope) error {
if err := v1.Convert_Pointer_bool_To_bool(&in.LeaderElect, &out.LeaderElect, s); err != nil {
return err
@ -220,47 +131,3 @@ func autoConvert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionCo
out.ResourceNamespace = in.ResourceNamespace
return nil
}
func autoConvert_v1alpha1_LoggingConfiguration_To_config_LoggingConfiguration(in *LoggingConfiguration, out *config.LoggingConfiguration, s conversion.Scope) error {
out.Format = in.Format
out.FlushFrequency = time.Duration(in.FlushFrequency)
out.Verbosity = config.VerbosityLevel(in.Verbosity)
out.VModule = *(*config.VModuleConfiguration)(unsafe.Pointer(&in.VModule))
if err := Convert_v1alpha1_FormatOptions_To_config_FormatOptions(&in.Options, &out.Options, s); err != nil {
return err
}
return nil
}
func autoConvert_config_LoggingConfiguration_To_v1alpha1_LoggingConfiguration(in *config.LoggingConfiguration, out *LoggingConfiguration, s conversion.Scope) error {
out.Format = in.Format
out.FlushFrequency = time.Duration(in.FlushFrequency)
out.Verbosity = uint32(in.Verbosity)
out.VModule = *(*VModuleConfiguration)(unsafe.Pointer(&in.VModule))
if err := Convert_config_FormatOptions_To_v1alpha1_FormatOptions(&in.Options, &out.Options, s); err != nil {
return err
}
return nil
}
func autoConvert_v1alpha1_VModuleItem_To_config_VModuleItem(in *VModuleItem, out *config.VModuleItem, s conversion.Scope) error {
out.FilePattern = in.FilePattern
out.Verbosity = config.VerbosityLevel(in.Verbosity)
return nil
}
// Convert_v1alpha1_VModuleItem_To_config_VModuleItem is an autogenerated conversion function.
func Convert_v1alpha1_VModuleItem_To_config_VModuleItem(in *VModuleItem, out *config.VModuleItem, s conversion.Scope) error {
return autoConvert_v1alpha1_VModuleItem_To_config_VModuleItem(in, out, s)
}
func autoConvert_config_VModuleItem_To_v1alpha1_VModuleItem(in *config.VModuleItem, out *VModuleItem, s conversion.Scope) error {
out.FilePattern = in.FilePattern
out.Verbosity = uint32(in.Verbosity)
return nil
}
// Convert_config_VModuleItem_To_v1alpha1_VModuleItem is an autogenerated conversion function.
func Convert_config_VModuleItem_To_v1alpha1_VModuleItem(in *config.VModuleItem, out *VModuleItem, s conversion.Scope) error {
return autoConvert_config_VModuleItem_To_v1alpha1_VModuleItem(in, out, s)
}

View File

@ -63,40 +63,6 @@ func (in *DebuggingConfiguration) DeepCopy() *DebuggingConfiguration {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FormatOptions) DeepCopyInto(out *FormatOptions) {
*out = *in
in.JSON.DeepCopyInto(&out.JSON)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FormatOptions.
func (in *FormatOptions) DeepCopy() *FormatOptions {
if in == nil {
return nil
}
out := new(FormatOptions)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *JSONOptions) DeepCopyInto(out *JSONOptions) {
*out = *in
in.InfoBufferSize.DeepCopyInto(&out.InfoBufferSize)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONOptions.
func (in *JSONOptions) DeepCopy() *JSONOptions {
if in == nil {
return nil
}
out := new(JSONOptions)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LeaderElectionConfiguration) DeepCopyInto(out *LeaderElectionConfiguration) {
*out = *in
@ -120,61 +86,3 @@ func (in *LeaderElectionConfiguration) DeepCopy() *LeaderElectionConfiguration {
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LoggingConfiguration) DeepCopyInto(out *LoggingConfiguration) {
*out = *in
if in.VModule != nil {
in, out := &in.VModule, &out.VModule
*out = make(VModuleConfiguration, len(*in))
copy(*out, *in)
}
in.Options.DeepCopyInto(&out.Options)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoggingConfiguration.
func (in *LoggingConfiguration) DeepCopy() *LoggingConfiguration {
if in == nil {
return nil
}
out := new(LoggingConfiguration)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in VModuleConfiguration) DeepCopyInto(out *VModuleConfiguration) {
{
in := &in
*out = make(VModuleConfiguration, len(*in))
copy(*out, *in)
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VModuleConfiguration.
func (in VModuleConfiguration) DeepCopy() VModuleConfiguration {
if in == nil {
return nil
}
out := new(VModuleConfiguration)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *VModuleItem) DeepCopyInto(out *VModuleItem) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VModuleItem.
func (in *VModuleItem) DeepCopy() *VModuleItem {
if in == nil {
return nil
}
out := new(VModuleItem)
in.DeepCopyInto(out)
return out
}

View File

@ -53,40 +53,6 @@ func (in *DebuggingConfiguration) DeepCopy() *DebuggingConfiguration {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FormatOptions) DeepCopyInto(out *FormatOptions) {
*out = *in
in.JSON.DeepCopyInto(&out.JSON)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FormatOptions.
func (in *FormatOptions) DeepCopy() *FormatOptions {
if in == nil {
return nil
}
out := new(FormatOptions)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *JSONOptions) DeepCopyInto(out *JSONOptions) {
*out = *in
in.InfoBufferSize.DeepCopyInto(&out.InfoBufferSize)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONOptions.
func (in *JSONOptions) DeepCopy() *JSONOptions {
if in == nil {
return nil
}
out := new(JSONOptions)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LeaderElectionConfiguration) DeepCopyInto(out *LeaderElectionConfiguration) {
*out = *in
@ -105,61 +71,3 @@ func (in *LeaderElectionConfiguration) DeepCopy() *LeaderElectionConfiguration {
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LoggingConfiguration) DeepCopyInto(out *LoggingConfiguration) {
*out = *in
if in.VModule != nil {
in, out := &in.VModule, &out.VModule
*out = make(VModuleConfiguration, len(*in))
copy(*out, *in)
}
in.Options.DeepCopyInto(&out.Options)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoggingConfiguration.
func (in *LoggingConfiguration) DeepCopy() *LoggingConfiguration {
if in == nil {
return nil
}
out := new(LoggingConfiguration)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in VModuleConfiguration) DeepCopyInto(out *VModuleConfiguration) {
{
in := &in
*out = make(VModuleConfiguration, len(*in))
copy(*out, *in)
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VModuleConfiguration.
func (in VModuleConfiguration) DeepCopy() VModuleConfiguration {
if in == nil {
return nil
}
out := new(VModuleConfiguration)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *VModuleItem) DeepCopyInto(out *VModuleItem) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VModuleItem.
func (in *VModuleItem) DeepCopy() *VModuleItem {
if in == nil {
return nil
}
out := new(VModuleItem)
in.DeepCopyInto(out)
return out
}

32
vendor/k8s.io/component-base/logs/api/v1/doc.go generated vendored Normal file
View File

@ -0,0 +1,32 @@
/*
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.
*/
// +k8s:deepcopy-gen=package
// Package v1 contains the configuration API for logging.
//
// The intention is to only have a single version of this API, potentially with
// new fields added over time in a backwards-compatible manner. Fields for
// alpha or beta features are allowed as long as they are defined so that not
// changing the defaults leaves those features disabled.
//
// The "v1" package name is just a reminder that API compatibility rules apply,
// not an indication of the stability of all features covered by it.
// The LoggingAlphaOptions and LoggingBetaOptions feature gates control whether
// these unstable features can get enabled. This can be used to ensure that
// command invocations do not accidentally rely on unstable features.
package v1 // import "k8s.io/component-base/logs/api/v1"

View File

@ -0,0 +1,70 @@
/*
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 v1
import (
"k8s.io/component-base/featuregate"
)
const (
// owner: @pohly
// kep: http://kep.k8s.io/3077
// alpha: v1.24
//
// Enables looking up a logger from a context.Context instead of using
// the global fallback logger and manipulating the logger that is
// used by a call chain.
ContextualLogging featuregate.Feature = "ContextualLogging"
// contextualLoggingDefault must remain false while in alpha. It can
// become true in beta.
contextualLoggingDefault = false
// Allow fine-tuning of experimental, alpha-quality logging options.
//
// Per https://groups.google.com/g/kubernetes-sig-architecture/c/Nxsc7pfe5rw/m/vF2djJh0BAAJ
// we want to avoid a proliferation of feature gates. This feature gate:
// - will guard *a group* of logging options whose quality level is alpha.
// - will never graduate to beta or stable.
LoggingAlphaOptions featuregate.Feature = "LoggingAlphaOptions"
// Allow fine-tuning of experimental, beta-quality logging options.
//
// Per https://groups.google.com/g/kubernetes-sig-architecture/c/Nxsc7pfe5rw/m/vF2djJh0BAAJ
// we want to avoid a proliferation of feature gates. This feature gate:
// - will guard *a group* of logging options whose quality level is beta.
// - is thus *introduced* as beta
// - will never graduate to stable.
LoggingBetaOptions featuregate.Feature = "LoggingBetaOptions"
// Stable logging options. Always enabled.
LoggingStableOptions featuregate.Feature = "LoggingStableOptions"
)
func featureGates() map[featuregate.Feature]featuregate.FeatureSpec {
return map[featuregate.Feature]featuregate.FeatureSpec{
ContextualLogging: {Default: contextualLoggingDefault, PreRelease: featuregate.Alpha},
LoggingAlphaOptions: {Default: false, PreRelease: featuregate.Alpha},
LoggingBetaOptions: {Default: true, PreRelease: featuregate.Beta},
}
}
// AddFeatureGates adds all feature gates used by this package.
func AddFeatureGates(mutableFeatureGate featuregate.MutableFeatureGate) error {
return mutableFeatureGate.Add(featureGates())
}

282
vendor/k8s.io/component-base/logs/api/v1/options.go generated vendored Normal file
View File

@ -0,0 +1,282 @@
/*
Copyright 2021 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 v1
import (
"flag"
"fmt"
"math"
"sort"
"strings"
"time"
"github.com/spf13/pflag"
"k8s.io/klog/v2"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/util/validation/field"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/featuregate"
)
const (
// LogFlushFreqDefault is the default for the corresponding command line
// parameter.
LogFlushFreqDefault = 5 * time.Second
)
const (
// LogFlushFreqFlagName is the name of the command line parameter.
// Depending on how flags get added, it is either a stand-alone
// value (logs.AddFlags) or part of LoggingConfiguration.
LogFlushFreqFlagName = "log-flush-frequency"
)
// NewLoggingConfiguration returns a struct holding the default logging configuration.
func NewLoggingConfiguration() *LoggingConfiguration {
c := LoggingConfiguration{}
SetRecommendedLoggingConfiguration(&c)
return &c
}
// ValidateAndApply combines validation and application of the logging configuration.
// This should be invoked as early as possible because then the rest of the program
// startup (including validation of other options) will already run with the final
// logging configuration.
//
// The optional FeatureGate controls logging features. If nil, the default for
// these features is used.
func ValidateAndApply(c *LoggingConfiguration, featureGate featuregate.FeatureGate) error {
return ValidateAndApplyAsField(c, featureGate, nil)
}
// ValidateAndApplyAsField is a variant of ValidateAndApply that should be used
// when the LoggingConfiguration is embedded in some larger configuration
// structure.
func ValidateAndApplyAsField(c *LoggingConfiguration, featureGate featuregate.FeatureGate, fldPath *field.Path) error {
errs := Validate(c, featureGate, fldPath)
if len(errs) > 0 {
return errs.ToAggregate()
}
return apply(c, featureGate)
}
// Validate can be used to check for invalid settings without applying them.
// Most binaries should validate and apply the logging configuration as soon
// as possible via ValidateAndApply. The field path is optional: nil
// can be passed when the struct is not embedded in some larger struct.
func Validate(c *LoggingConfiguration, featureGate featuregate.FeatureGate, fldPath *field.Path) field.ErrorList {
errs := field.ErrorList{}
if c.Format != DefaultLogFormat {
// WordSepNormalizeFunc is just a guess. Commands should use it,
// but we cannot know for sure.
allFlags := unsupportedLoggingFlags(cliflag.WordSepNormalizeFunc)
for _, f := range allFlags {
if f.DefValue != f.Value.String() {
errs = append(errs, field.Invalid(fldPath.Child("format"), c.Format, fmt.Sprintf("Non-default format doesn't honor flag: %s", f.Name)))
}
}
}
format, err := logRegistry.get(c.Format)
if err != nil {
errs = append(errs, field.Invalid(fldPath.Child("format"), c.Format, "Unsupported log format"))
} else if format != nil {
if format.feature != LoggingStableOptions {
enabled := featureGates()[format.feature].Default
if featureGate != nil {
enabled = featureGate.Enabled(format.feature)
}
if !enabled {
errs = append(errs, field.Forbidden(fldPath.Child("format"), fmt.Sprintf("Log format %s is disabled, see %s feature", c.Format, format.feature)))
}
}
}
// The type in our struct is uint32, but klog only accepts positive int32.
if c.Verbosity > math.MaxInt32 {
errs = append(errs, field.Invalid(fldPath.Child("verbosity"), c.Verbosity, fmt.Sprintf("Must be <= %d", math.MaxInt32)))
}
vmoduleFldPath := fldPath.Child("vmodule")
if len(c.VModule) > 0 && c.Format != "" && c.Format != "text" {
errs = append(errs, field.Forbidden(vmoduleFldPath, "Only supported for text log format"))
}
for i, item := range c.VModule {
if item.FilePattern == "" {
errs = append(errs, field.Required(vmoduleFldPath.Index(i), "File pattern must not be empty"))
}
if strings.ContainsAny(item.FilePattern, "=,") {
errs = append(errs, field.Invalid(vmoduleFldPath.Index(i), item.FilePattern, "File pattern must not contain equal sign or comma"))
}
if item.Verbosity > math.MaxInt32 {
errs = append(errs, field.Invalid(vmoduleFldPath.Index(i), item.Verbosity, fmt.Sprintf("Must be <= %d", math.MaxInt32)))
}
}
errs = append(errs, validateFormatOptions(c, featureGate, fldPath.Child("options"))...)
return errs
}
func validateFormatOptions(c *LoggingConfiguration, featureGate featuregate.FeatureGate, fldPath *field.Path) field.ErrorList {
errs := field.ErrorList{}
errs = append(errs, validateJSONOptions(c, featureGate, fldPath.Child("json"))...)
return errs
}
func validateJSONOptions(c *LoggingConfiguration, featureGate featuregate.FeatureGate, fldPath *field.Path) field.ErrorList {
errs := field.ErrorList{}
if gate := LoggingAlphaOptions; c.Options.JSON.SplitStream && !featureEnabled(featureGate, gate) {
errs = append(errs, field.Forbidden(fldPath.Child("splitStream"), fmt.Sprintf("Feature %s is disabled", gate)))
}
if gate := LoggingAlphaOptions; c.Options.JSON.InfoBufferSize.Value() != 0 && !featureEnabled(featureGate, gate) {
errs = append(errs, field.Forbidden(fldPath.Child("infoBufferSize"), fmt.Sprintf("Feature %s is disabled", gate)))
}
return errs
}
func featureEnabled(featureGate featuregate.FeatureGate, feature featuregate.Feature) bool {
enabled := false
if featureGate != nil {
enabled = featureGate.Enabled(feature)
}
return enabled
}
func apply(c *LoggingConfiguration, featureGate featuregate.FeatureGate) error {
contextualLoggingEnabled := contextualLoggingDefault
if featureGate != nil {
contextualLoggingEnabled = featureGate.Enabled(ContextualLogging)
}
// if log format not exists, use nil loggr
format, _ := logRegistry.get(c.Format)
if format.factory == nil {
klog.ClearLogger()
} else {
log, flush := format.factory.Create(*c)
klog.SetLoggerWithOptions(log, klog.ContextualLogger(contextualLoggingEnabled), klog.FlushLogger(flush))
}
if err := loggingFlags.Lookup("v").Value.Set(VerbosityLevelPflag(&c.Verbosity).String()); err != nil {
return fmt.Errorf("internal error while setting klog verbosity: %v", err)
}
if err := loggingFlags.Lookup("vmodule").Value.Set(VModuleConfigurationPflag(&c.VModule).String()); err != nil {
return fmt.Errorf("internal error while setting klog vmodule: %v", err)
}
klog.StartFlushDaemon(c.FlushFrequency)
klog.EnableContextualLogging(contextualLoggingEnabled)
return nil
}
// AddFlags adds command line flags for the configuration.
func AddFlags(c *LoggingConfiguration, fs *pflag.FlagSet) {
// The help text is generated assuming that flags will eventually use
// hyphens, even if currently no normalization function is set for the
// flag set yet.
unsupportedFlags := strings.Join(unsupportedLoggingFlagNames(cliflag.WordSepNormalizeFunc), ", ")
formats := logRegistry.list()
fs.StringVar(&c.Format, "logging-format", c.Format, fmt.Sprintf("Sets the log format. Permitted formats: %s.\nNon-default formats don't honor these flags: %s.\nNon-default choices are currently alpha and subject to change without warning.", formats, unsupportedFlags))
// No new log formats should be added after generation is of flag options
logRegistry.freeze()
fs.DurationVar(&c.FlushFrequency, LogFlushFreqFlagName, c.FlushFrequency, "Maximum number of seconds between log flushes")
fs.VarP(VerbosityLevelPflag(&c.Verbosity), "v", "v", "number for the log level verbosity")
fs.Var(VModuleConfigurationPflag(&c.VModule), "vmodule", "comma-separated list of pattern=N settings for file-filtered logging (only works for text log format)")
// JSON options. We only register them if "json" is a valid format. The
// config file API however always has them.
if _, err := logRegistry.get("json"); err == nil {
fs.BoolVar(&c.Options.JSON.SplitStream, "log-json-split-stream", false, "[Alpha] In JSON format, write error messages to stderr and info messages to stdout. The default is to write a single stream to stdout. Enable the LoggingAlphaOptions feature gate to use this.")
fs.Var(&c.Options.JSON.InfoBufferSize, "log-json-info-buffer-size", "[Alpha] In JSON format with split output streams, the info messages can be buffered for a while to increase performance. The default value of zero bytes disables buffering. The size can be specified as number of bytes (512), multiples of 1000 (1K), multiples of 1024 (2Ki), or powers of those (3M, 4G, 5Mi, 6Gi). Enable the LoggingAlphaOptions feature gate to use this.")
}
}
// SetRecommendedLoggingConfiguration sets the default logging configuration
// for fields that are unset.
//
// Consumers who embed LoggingConfiguration in their own configuration structs
// may set custom defaults and then should call this function to add the
// global defaults.
func SetRecommendedLoggingConfiguration(c *LoggingConfiguration) {
if c.Format == "" {
c.Format = "text"
}
if c.FlushFrequency == 0 {
c.FlushFrequency = LogFlushFreqDefault
}
var empty resource.QuantityValue
if c.Options.JSON.InfoBufferSize == empty {
c.Options.JSON.InfoBufferSize = resource.QuantityValue{
// This is similar, but not quite the same as a default
// constructed instance.
Quantity: *resource.NewQuantity(0, resource.DecimalSI),
}
// This sets the unexported Quantity.s which will be compared
// by reflect.DeepEqual in some tests.
_ = c.Options.JSON.InfoBufferSize.String()
}
}
// loggingFlags captures the state of the logging flags, in particular their default value
// before flag parsing. It is used by unsupportedLoggingFlags.
var loggingFlags pflag.FlagSet
func init() {
var fs flag.FlagSet
klog.InitFlags(&fs)
loggingFlags.AddGoFlagSet(&fs)
}
// List of logs (k8s.io/klog + k8s.io/component-base/logs) flags supported by all logging formats
var supportedLogsFlags = map[string]struct{}{
"v": {},
// TODO: support vmodule after 1.19 Alpha
}
// unsupportedLoggingFlags lists unsupported logging flags. The normalize
// function is optional.
func unsupportedLoggingFlags(normalizeFunc func(f *pflag.FlagSet, name string) pflag.NormalizedName) []*pflag.Flag {
// k8s.io/component-base/logs and klog flags
pfs := &pflag.FlagSet{}
loggingFlags.VisitAll(func(flag *pflag.Flag) {
if _, found := supportedLogsFlags[flag.Name]; !found {
// Normalization changes flag.Name, so make a copy.
clone := *flag
pfs.AddFlag(&clone)
}
})
// Apply normalization.
pfs.SetNormalizeFunc(normalizeFunc)
var allFlags []*pflag.Flag
pfs.VisitAll(func(flag *pflag.Flag) {
allFlags = append(allFlags, flag)
})
return allFlags
}
// unsupportedLoggingFlagNames lists unsupported logging flags by name, with
// optional normalization and sorted.
func unsupportedLoggingFlagNames(normalizeFunc func(f *pflag.FlagSet, name string) pflag.NormalizedName) []string {
unsupportedFlags := unsupportedLoggingFlags(normalizeFunc)
names := make([]string, 0, len(unsupportedFlags))
for _, f := range unsupportedFlags {
names = append(names, "--"+f.Name)
}
sort.Strings(names)
return names
}

104
vendor/k8s.io/component-base/logs/api/v1/pflags.go generated vendored Normal file
View File

@ -0,0 +1,104 @@
/*
Copyright 2021 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 v1
import (
"fmt"
"strconv"
"strings"
"github.com/spf13/pflag"
)
// VModuleConfigurationPflag implements the pflag.Value interface for a
// VModuleConfiguration. The value pointer must not be nil.
func VModuleConfigurationPflag(value *VModuleConfiguration) pflag.Value {
return vmoduleConfigurationPFlag{value}
}
type vmoduleConfigurationPFlag struct {
value *VModuleConfiguration
}
// String returns the -vmodule parameter (comma-separated list of pattern=N).
func (wrapper vmoduleConfigurationPFlag) String() string {
var patterns []string
for _, item := range *wrapper.value {
patterns = append(patterns, fmt.Sprintf("%s=%d", item.FilePattern, item.Verbosity))
}
return strings.Join(patterns, ",")
}
// Set parses the -vmodule parameter (comma-separated list of pattern=N).
func (wrapper vmoduleConfigurationPFlag) Set(value string) error {
// This code mirrors https://github.com/kubernetes/klog/blob/9ad246211af1ed84621ee94a26fcce0038b69cd1/klog.go#L287-L313
for _, pat := range strings.Split(value, ",") {
if len(pat) == 0 {
// Empty strings such as from a trailing comma can be ignored.
continue
}
patLev := strings.Split(pat, "=")
if len(patLev) != 2 || len(patLev[0]) == 0 || len(patLev[1]) == 0 {
return fmt.Errorf("%q does not have the pattern=N format", pat)
}
pattern := patLev[0]
// 31 instead of 32 to ensure that it also fits into int32.
v, err := strconv.ParseUint(patLev[1], 10, 31)
if err != nil {
return fmt.Errorf("parsing verbosity in %q: %v", pat, err)
}
*wrapper.value = append(*wrapper.value, VModuleItem{FilePattern: pattern, Verbosity: VerbosityLevel(v)})
}
return nil
}
func (wrapper vmoduleConfigurationPFlag) Type() string {
return "pattern=N,..."
}
// VerbosityLevelPflag implements the pflag.Value interface for a verbosity
// level value.
func VerbosityLevelPflag(value *VerbosityLevel) pflag.Value {
return verbosityLevelPflag{value}
}
type verbosityLevelPflag struct {
value *VerbosityLevel
}
func (wrapper verbosityLevelPflag) String() string {
return strconv.FormatInt(int64(*wrapper.value), 10)
}
func (wrapper verbosityLevelPflag) Get() interface{} {
return *wrapper.value
}
func (wrapper verbosityLevelPflag) Set(value string) error {
// Limited to int32 for compatibility with klog.
v, err := strconv.ParseUint(value, 10, 31)
if err != nil {
return err
}
*wrapper.value = VerbosityLevel(v)
return nil
}
func (wrapper verbosityLevelPflag) Type() string {
return "Level"
}

110
vendor/k8s.io/component-base/logs/api/v1/registry.go generated vendored Normal file
View File

@ -0,0 +1,110 @@
/*
Copyright 2020 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 v1
import (
"fmt"
"sort"
"strings"
"github.com/go-logr/logr"
"k8s.io/component-base/featuregate"
)
var logRegistry = newLogFormatRegistry()
// logFormatRegistry stores factories for all supported logging formats.
type logFormatRegistry struct {
registry map[string]logFormat
frozen bool
}
type logFormat struct {
factory LogFormatFactory
feature featuregate.Feature
}
// LogFormatFactory provides support for a certain additional,
// non-default log format.
type LogFormatFactory interface {
// Create returns a logger with the requested configuration.
// Returning a flush function for the logger is optional.
// If provided, the caller must ensure that it is called
// periodically (if desired) and at program exit.
Create(c LoggingConfiguration) (log logr.Logger, flush func())
}
// RegisterLogFormat registers support for a new logging format. This must be called
// before using any of the methods in LoggingConfiguration. The feature must
// be one of those defined in this package (typically LoggingAlphaOptions,
// LoggingBetaOptions or LoggingStableOptions).
func RegisterLogFormat(name string, factory LogFormatFactory, feature featuregate.Feature) error {
return logRegistry.register(name, logFormat{factory, feature})
}
func newLogFormatRegistry() *logFormatRegistry {
registry := &logFormatRegistry{
registry: make(map[string]logFormat),
frozen: false,
}
registry.register("text", logFormat{feature: LoggingStableOptions})
return registry
}
// register adds a new log format. It's an error to modify an existing one.
func (lfr *logFormatRegistry) register(name string, format logFormat) error {
if lfr.frozen {
return fmt.Errorf("log format registry is frozen, unable to register log format %s", name)
}
if _, ok := lfr.registry[name]; ok {
return fmt.Errorf("log format: %s already exists", name)
}
if _, ok := featureGates()[format.feature]; !ok && format.feature != LoggingStableOptions {
return fmt.Errorf("log format %s: unsupported feature gate %s", name, format.feature)
}
lfr.registry[name] = format
return nil
}
// get specified log format factory
func (lfr *logFormatRegistry) get(name string) (*logFormat, error) {
format, ok := lfr.registry[name]
if !ok {
return nil, fmt.Errorf("log format: %s does not exists", name)
}
return &format, nil
}
// list names of registered log formats, including feature gates (sorted)
func (lfr *logFormatRegistry) list() string {
formats := make([]string, 0, len(lfr.registry))
for name, format := range lfr.registry {
item := fmt.Sprintf(`"%s"`, name)
if format.feature != LoggingStableOptions {
item += fmt.Sprintf(" (gated by %s)", format.feature)
}
formats = append(formats, item)
}
sort.Strings(formats)
return strings.Join(formats, ", ")
}
// freeze prevents further modifications of the registered log formats.
func (lfr *logFormatRegistry) freeze() {
lfr.frozen = true
}

99
vendor/k8s.io/component-base/logs/api/v1/types.go generated vendored Normal file
View File

@ -0,0 +1,99 @@
/*
Copyright 2021 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 v1
import (
"time"
"k8s.io/apimachinery/pkg/api/resource"
)
// Supported output formats.
const (
// DefaultLogFormat is the traditional klog output format.
DefaultLogFormat = "text"
// JSONLogFormat emits each log message as a JSON struct.
JSONLogFormat = "json"
)
// The alpha or beta level of structs is the highest stability level of any field
// inside it. Feature gates will get checked during LoggingConfiguration.ValidateAndApply.
// LoggingConfiguration contains logging options.
type LoggingConfiguration struct {
// Format Flag specifies the structure of log messages.
// default value of format is `text`
Format string `json:"format,omitempty"`
// Maximum number of nanoseconds (i.e. 1s = 1000000000) between log
// flushes. Ignored if the selected logging backend writes log
// messages without buffering.
FlushFrequency time.Duration `json:"flushFrequency"`
// Verbosity is the threshold that determines which log messages are
// logged. Default is zero which logs only the most important
// messages. Higher values enable additional messages. Error messages
// are always logged.
Verbosity VerbosityLevel `json:"verbosity"`
// VModule overrides the verbosity threshold for individual files.
// Only supported for "text" log format.
VModule VModuleConfiguration `json:"vmodule,omitempty"`
// [Alpha] Options holds additional parameters that are specific
// to the different logging formats. Only the options for the selected
// format get used, but all of them get validated.
// Only available when the LoggingAlphaOptions feature gate is enabled.
Options FormatOptions `json:"options,omitempty"`
}
// FormatOptions contains options for the different logging formats.
type FormatOptions struct {
// [Alpha] JSON contains options for logging format "json".
// Only available when the LoggingAlphaOptions feature gate is enabled.
JSON JSONOptions `json:"json,omitempty"`
}
// JSONOptions contains options for logging format "json".
type JSONOptions struct {
// [Alpha] SplitStream redirects error messages to stderr while
// info messages go to stdout, with buffering. The default is to write
// both to stdout, without buffering. Only available when
// the LoggingAlphaOptions feature gate is enabled.
SplitStream bool `json:"splitStream,omitempty"`
// [Alpha] InfoBufferSize sets the size of the info stream when
// using split streams. The default is zero, which disables buffering.
// Only available when the LoggingAlphaOptions feature gate is enabled.
InfoBufferSize resource.QuantityValue `json:"infoBufferSize,omitempty"`
}
// VModuleConfiguration is a collection of individual file names or patterns
// and the corresponding verbosity threshold.
type VModuleConfiguration []VModuleItem
// VModuleItem defines verbosity for one or more files which match a certain
// glob pattern.
type VModuleItem struct {
// FilePattern is a base file name (i.e. minus the ".go" suffix and
// directory) or a "glob" pattern for such a name. It must not contain
// comma and equal signs because those are separators for the
// corresponding klog command line argument.
FilePattern string `json:"filePattern"`
// Verbosity is the threshold for log messages emitted inside files
// that match the pattern.
Verbosity VerbosityLevel `json:"verbosity"`
}
// VerbosityLevel represents a klog or logr verbosity threshold.
type VerbosityLevel uint32

View File

@ -0,0 +1,114 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright 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.
*/
// Code generated by deepcopy-gen. DO NOT EDIT.
package v1
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FormatOptions) DeepCopyInto(out *FormatOptions) {
*out = *in
in.JSON.DeepCopyInto(&out.JSON)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FormatOptions.
func (in *FormatOptions) DeepCopy() *FormatOptions {
if in == nil {
return nil
}
out := new(FormatOptions)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *JSONOptions) DeepCopyInto(out *JSONOptions) {
*out = *in
in.InfoBufferSize.DeepCopyInto(&out.InfoBufferSize)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONOptions.
func (in *JSONOptions) DeepCopy() *JSONOptions {
if in == nil {
return nil
}
out := new(JSONOptions)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LoggingConfiguration) DeepCopyInto(out *LoggingConfiguration) {
*out = *in
if in.VModule != nil {
in, out := &in.VModule, &out.VModule
*out = make(VModuleConfiguration, len(*in))
copy(*out, *in)
}
in.Options.DeepCopyInto(&out.Options)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoggingConfiguration.
func (in *LoggingConfiguration) DeepCopy() *LoggingConfiguration {
if in == nil {
return nil
}
out := new(LoggingConfiguration)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in VModuleConfiguration) DeepCopyInto(out *VModuleConfiguration) {
{
in := &in
*out = make(VModuleConfiguration, len(*in))
copy(*out, *in)
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VModuleConfiguration.
func (in VModuleConfiguration) DeepCopy() VModuleConfiguration {
if in == nil {
return nil
}
out := new(VModuleConfiguration)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *VModuleItem) DeepCopyInto(out *VModuleItem) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VModuleItem.
func (in *VModuleItem) DeepCopy() *VModuleItem {
if in == nil {
return nil
}
out := new(VModuleItem)
in.DeepCopyInto(out)
return out
}

View File

@ -18,6 +18,7 @@ package metrics
import (
"context"
"github.com/blang/semver/v4"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
@ -106,9 +107,14 @@ type CounterVec struct {
originalLabels []string
}
// NewCounterVec returns an object which satisfies the kubeCollector and CounterVecMetric interfaces.
var _ kubeCollector = &CounterVec{}
// TODO: make this true: var _ CounterVecMetric = &CounterVec{}
// NewCounterVec returns an object which satisfies the kubeCollector and (almost) CounterVecMetric interfaces.
// However, the object returned will not measure anything unless the collector is first
// registered, since the metric is lazily instantiated.
// registered, since the metric is lazily instantiated, and only members extracted after
// registration will actually measure anything.
func NewCounterVec(opts *CounterOpts, labels []string) *CounterVec {
opts.StabilityLevel.setDefaults()
@ -149,13 +155,16 @@ func (v *CounterVec) initializeDeprecatedMetric() {
v.initializeMetric()
}
// Default Prometheus behavior actually results in the creation of a new metric
// if a metric with the unique label values is not found in the underlying stored metricMap.
// Default Prometheus Vec behavior is that member extraction results in creation of a new element
// if one with the unique label values is not found in the underlying stored metricMap.
// This means that if this function is called but the underlying metric is not registered
// (which means it will never be exposed externally nor consumed), the metric will exist in memory
// for perpetuity (i.e. throughout application lifecycle).
//
// For reference: https://github.com/prometheus/client_golang/blob/v0.9.2/prometheus/counter.go#L179-L197
//
// In contrast, the Vec behavior in this package is that member extraction before registration
// returns a permanent noop object.
// WithLabelValues returns the Counter for the given slice of label
// values (same order as the VariableLabels in Desc). If that combination of

View File

@ -218,8 +218,8 @@ func (d *Desc) initializeDeprecatedDesc() {
// GetRawDesc will returns a new *Desc with original parameters provided to NewDesc().
//
// It will be useful in testing scenario that the same Desc be registered to different registry.
// 1. Desc `D` is registered to registry 'A' in TestA (Note: `D` maybe created)
// 2. Desc `D` is registered to registry 'B' in TestB (Note: since 'D' has been created once, thus will be ignored by registry 'B')
// 1. Desc `D` is registered to registry 'A' in TestA (Note: `D` maybe created)
// 2. Desc `D` is registered to registry 'B' in TestB (Note: since 'D' has been created once, thus will be ignored by registry 'B')
func (d *Desc) GetRawDesc() *Desc {
return NewDesc(d.fqName, d.help, d.variableLabels, d.constLabels, d.stabilityLevel, d.deprecatedVersion)
}

View File

@ -18,6 +18,7 @@ package metrics
import (
"context"
"github.com/blang/semver/v4"
"github.com/prometheus/client_golang/prometheus"
@ -33,7 +34,11 @@ type Gauge struct {
selfCollector
}
// NewGauge returns an object which satisfies the kubeCollector and KubeGauge interfaces.
var _ GaugeMetric = &Gauge{}
var _ Registerable = &Gauge{}
var _ kubeCollector = &Gauge{}
// NewGauge returns an object which satisfies the kubeCollector, Registerable, and Gauge interfaces.
// However, the object returned will not measure anything unless the collector is first
// registered, since the metric is lazily instantiated.
func NewGauge(opts *GaugeOpts) *Gauge {
@ -88,9 +93,14 @@ type GaugeVec struct {
originalLabels []string
}
// NewGaugeVec returns an object which satisfies the kubeCollector and KubeGaugeVec interfaces.
var _ GaugeVecMetric = &GaugeVec{}
var _ Registerable = &GaugeVec{}
var _ kubeCollector = &GaugeVec{}
// NewGaugeVec returns an object which satisfies the kubeCollector, Registerable, and GaugeVecMetric interfaces.
// However, the object returned will not measure anything unless the collector is first
// registered, since the metric is lazily instantiated.
// registered, since the metric is lazily instantiated, and only members extracted after
// registration will actually measure anything.
func NewGaugeVec(opts *GaugeOpts, labels []string) *GaugeVec {
opts.StabilityLevel.setDefaults()
@ -130,26 +140,55 @@ func (v *GaugeVec) initializeDeprecatedMetric() {
v.initializeMetric()
}
// Default Prometheus behavior actually results in the creation of a new metric
// if a metric with the unique label values is not found in the underlying stored metricMap.
func (v *GaugeVec) WithLabelValuesChecked(lvs ...string) (GaugeMetric, error) {
if !v.IsCreated() {
if v.IsHidden() {
return noop, nil
}
return noop, errNotRegistered // return no-op gauge
}
if v.LabelValueAllowLists != nil {
v.LabelValueAllowLists.ConstrainToAllowedList(v.originalLabels, lvs)
}
elt, err := v.GaugeVec.GetMetricWithLabelValues(lvs...)
return elt, err
}
// Default Prometheus Vec behavior is that member extraction results in creation of a new element
// if one with the unique label values is not found in the underlying stored metricMap.
// This means that if this function is called but the underlying metric is not registered
// (which means it will never be exposed externally nor consumed), the metric will exist in memory
// for perpetuity (i.e. throughout application lifecycle).
//
// For reference: https://github.com/prometheus/client_golang/blob/v0.9.2/prometheus/gauge.go#L190-L208
//
// In contrast, the Vec behavior in this package is that member extraction before registration
// returns a permanent noop object.
// WithLabelValues returns the GaugeMetric for the given slice of label
// values (same order as the VariableLabels in Desc). If that combination of
// label values is accessed for the first time, a new GaugeMetric is created IFF the gaugeVec
// has been registered to a metrics registry.
func (v *GaugeVec) WithLabelValues(lvs ...string) GaugeMetric {
ans, err := v.WithLabelValuesChecked(lvs...)
if err == nil || ErrIsNotRegistered(err) {
return ans
}
panic(err)
}
func (v *GaugeVec) WithChecked(labels map[string]string) (GaugeMetric, error) {
if !v.IsCreated() {
return noop // return no-op gauge
if v.IsHidden() {
return noop, nil
}
return noop, errNotRegistered // return no-op gauge
}
if v.LabelValueAllowLists != nil {
v.LabelValueAllowLists.ConstrainToAllowedList(v.originalLabels, lvs)
v.LabelValueAllowLists.ConstrainLabelMap(labels)
}
return v.GaugeVec.WithLabelValues(lvs...)
elt, err := v.GaugeVec.GetMetricWith(labels)
return elt, err
}
// With returns the GaugeMetric for the given Labels map (the label names
@ -157,13 +196,11 @@ func (v *GaugeVec) WithLabelValues(lvs ...string) GaugeMetric {
// accessed for the first time, a new GaugeMetric is created IFF the gaugeVec has
// been registered to a metrics registry.
func (v *GaugeVec) With(labels map[string]string) GaugeMetric {
if !v.IsCreated() {
return noop // return no-op gauge
ans, err := v.WithChecked(labels)
if err == nil || ErrIsNotRegistered(err) {
return ans
}
if v.LabelValueAllowLists != nil {
v.LabelValueAllowLists.ConstrainLabelMap(labels)
}
return v.GaugeVec.With(labels)
panic(err)
}
// Delete deletes the metric where the variable labels are the same as those
@ -219,6 +256,10 @@ func (v *GaugeVec) WithContext(ctx context.Context) *GaugeVecWithContext {
}
}
func (v *GaugeVec) InterfaceWithContext(ctx context.Context) GaugeVecMetric {
return v.WithContext(ctx)
}
// GaugeVecWithContext is the wrapper of GaugeVec with context.
type GaugeVecWithContext struct {
*GaugeVec

View File

@ -18,6 +18,7 @@ package metrics
import (
"context"
"github.com/blang/semver/v4"
"github.com/prometheus/client_golang/prometheus"
)
@ -100,7 +101,10 @@ type HistogramVec struct {
// NewHistogramVec returns an object which satisfies kubeCollector and wraps the
// prometheus.HistogramVec object. However, the object returned will not measure
// anything unless the collector is first registered, since the metric is lazily instantiated.
// anything unless the collector is first registered, since the metric is lazily instantiated,
// and only members extracted after
// registration will actually measure anything.
func NewHistogramVec(opts *HistogramOpts, labels []string) *HistogramVec {
opts.StabilityLevel.setDefaults()
@ -136,13 +140,16 @@ func (v *HistogramVec) initializeDeprecatedMetric() {
v.initializeMetric()
}
// Default Prometheus behavior actually results in the creation of a new metric
// if a metric with the unique label values is not found in the underlying stored metricMap.
// Default Prometheus Vec behavior is that member extraction results in creation of a new element
// if one with the unique label values is not found in the underlying stored metricMap.
// This means that if this function is called but the underlying metric is not registered
// (which means it will never be exposed externally nor consumed), the metric will exist in memory
// for perpetuity (i.e. throughout application lifecycle).
//
// For reference: https://github.com/prometheus/client_golang/blob/v0.9.2/prometheus/histogram.go#L460-L470
//
// In contrast, the Vec behavior in this package is that member extraction before registration
// returns a permanent noop object.
// WithLabelValues returns the ObserverMetric for the given slice of label
// values (same order as the VariableLabels in Desc). If that combination of

View File

@ -22,6 +22,7 @@ import (
"github.com/blang/semver/v4"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
promext "k8s.io/component-base/metrics/prometheusextension"
"k8s.io/klog/v2"
)
@ -90,13 +91,14 @@ func (r *lazyMetric) lazyInit(self kubeCollector, fqName string) {
// preprocessMetric figures out whether the lazy metric should be hidden or not.
// This method takes a Version argument which should be the version of the binary in which
// this code is currently being executed. A metric can be hidden under two conditions:
// 1. if the metric is deprecated and is outside the grace period (i.e. has been
// deprecated for more than one release
// 2. if the metric is manually disabled via a CLI flag.
// 1. if the metric is deprecated and is outside the grace period (i.e. has been
// deprecated for more than one release
// 2. if the metric is manually disabled via a CLI flag.
//
// Disclaimer: disabling a metric via a CLI flag has higher precedence than
// deprecation and will override show-hidden-metrics for the explicitly
// disabled metric.
//
// deprecation and will override show-hidden-metrics for the explicitly
// disabled metric.
func (r *lazyMetric) preprocessMetric(version semver.Version) {
disabledMetricsLock.RLock()
defer disabledMetricsLock.RUnlock()
@ -203,6 +205,7 @@ func (c *selfCollector) Collect(ch chan<- prometheus.Metric) {
// no-op vecs for convenience
var noopCounterVec = &prometheus.CounterVec{}
var noopHistogramVec = &prometheus.HistogramVec{}
var noopTimingHistogramVec = &promext.TimingHistogramVec{}
var noopGaugeVec = &prometheus.GaugeVec{}
var noopObserverVec = &noopObserverVector{}
@ -211,17 +214,18 @@ var noop = &noopMetric{}
type noopMetric struct{}
func (noopMetric) Inc() {}
func (noopMetric) Add(float64) {}
func (noopMetric) Dec() {}
func (noopMetric) Set(float64) {}
func (noopMetric) Sub(float64) {}
func (noopMetric) Observe(float64) {}
func (noopMetric) SetToCurrentTime() {}
func (noopMetric) Desc() *prometheus.Desc { return nil }
func (noopMetric) Write(*dto.Metric) error { return nil }
func (noopMetric) Describe(chan<- *prometheus.Desc) {}
func (noopMetric) Collect(chan<- prometheus.Metric) {}
func (noopMetric) Inc() {}
func (noopMetric) Add(float64) {}
func (noopMetric) Dec() {}
func (noopMetric) Set(float64) {}
func (noopMetric) Sub(float64) {}
func (noopMetric) Observe(float64) {}
func (noopMetric) ObserveWithWeight(float64, uint64) {}
func (noopMetric) SetToCurrentTime() {}
func (noopMetric) Desc() *prometheus.Desc { return nil }
func (noopMetric) Write(*dto.Metric) error { return nil }
func (noopMetric) Describe(chan<- *prometheus.Desc) {}
func (noopMetric) Collect(chan<- prometheus.Metric) {}
type noopObserverVector struct{}

View File

@ -24,6 +24,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
"k8s.io/apimachinery/pkg/util/sets"
promext "k8s.io/component-base/metrics/prometheusextension"
)
var (
@ -189,6 +190,54 @@ func (o *HistogramOpts) toPromHistogramOpts() prometheus.HistogramOpts {
}
}
// TimingHistogramOpts bundles the options for creating a TimingHistogram metric. It is
// mandatory to set Name to a non-empty string. All other fields are optional
// and can safely be left at their zero value, although it is strongly
// encouraged to set a Help string.
type TimingHistogramOpts struct {
Namespace string
Subsystem string
Name string
Help string
ConstLabels map[string]string
Buckets []float64
InitialValue float64
DeprecatedVersion string
deprecateOnce sync.Once
annotateOnce sync.Once
StabilityLevel StabilityLevel
LabelValueAllowLists *MetricLabelAllowList
}
// Modify help description on the metric description.
func (o *TimingHistogramOpts) markDeprecated() {
o.deprecateOnce.Do(func() {
o.Help = fmt.Sprintf("(Deprecated since %v) %v", o.DeprecatedVersion, o.Help)
})
}
// annotateStabilityLevel annotates help description on the metric description with the stability level
// of the metric
func (o *TimingHistogramOpts) annotateStabilityLevel() {
o.annotateOnce.Do(func() {
o.Help = fmt.Sprintf("[%v] %v", o.StabilityLevel, o.Help)
})
}
// convenience function to allow easy transformation to the prometheus
// counterpart. This will do more once we have a proper label abstraction
func (o *TimingHistogramOpts) toPromHistogramOpts() promext.TimingHistogramOpts {
return promext.TimingHistogramOpts{
Namespace: o.Namespace,
Subsystem: o.Subsystem,
Name: o.Name,
Help: o.Help,
ConstLabels: o.ConstLabels,
Buckets: o.Buckets,
InitialValue: o.InitialValue,
}
}
// SummaryOpts bundles the options for creating a Summary metric. It is
// mandatory to set Name to a non-empty string. While all other fields are
// optional and can safely be left at their zero value, it is recommended to set

View File

@ -0,0 +1,189 @@
/*
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 prometheusextension
import (
"errors"
"time"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
)
// GaugeOps is the part of `prometheus.Gauge` that is relevant to
// instrumented code.
// This factoring should be in prometheus, analogous to the way
// it already factors out the Observer interface for histograms and summaries.
type GaugeOps interface {
// Set is the same as Gauge.Set
Set(float64)
// Inc is the same as Gauge.inc
Inc()
// Dec is the same as Gauge.Dec
Dec()
// Add is the same as Gauge.Add
Add(float64)
// Sub is the same as Gauge.Sub
Sub(float64)
// SetToCurrentTime the same as Gauge.SetToCurrentTime
SetToCurrentTime()
}
// A TimingHistogram tracks how long a `float64` variable spends in
// ranges defined by buckets. Time is counted in nanoseconds. The
// histogram's sum is the integral over time (in nanoseconds, from
// creation of the histogram) of the variable's value.
type TimingHistogram interface {
prometheus.Metric
prometheus.Collector
GaugeOps
}
// TimingHistogramOpts is the parameters of the TimingHistogram constructor
type TimingHistogramOpts struct {
Namespace string
Subsystem string
Name string
Help string
ConstLabels prometheus.Labels
// Buckets defines the buckets into which observations are
// accumulated. Each element in the slice is the upper
// inclusive bound of a bucket. The values must be sorted in
// strictly increasing order. There is no need to add a
// highest bucket with +Inf bound. The default value is
// prometheus.DefBuckets.
Buckets []float64
// The initial value of the variable.
InitialValue float64
}
// NewTimingHistogram creates a new TimingHistogram
func NewTimingHistogram(opts TimingHistogramOpts) (TimingHistogram, error) {
return NewTestableTimingHistogram(time.Now, opts)
}
// NewTestableTimingHistogram creates a TimingHistogram that uses a mockable clock
func NewTestableTimingHistogram(nowFunc func() time.Time, opts TimingHistogramOpts) (TimingHistogram, error) {
desc := prometheus.NewDesc(
prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
wrapTimingHelp(opts.Help),
nil,
opts.ConstLabels,
)
return newTimingHistogram(nowFunc, desc, opts)
}
func wrapTimingHelp(given string) string {
return "EXPERIMENTAL: " + given
}
func newTimingHistogram(nowFunc func() time.Time, desc *prometheus.Desc, opts TimingHistogramOpts, variableLabelValues ...string) (TimingHistogram, error) {
allLabelsM := prometheus.Labels{}
allLabelsS := prometheus.MakeLabelPairs(desc, variableLabelValues)
for _, pair := range allLabelsS {
if pair == nil || pair.Name == nil || pair.Value == nil {
return nil, errors.New("prometheus.MakeLabelPairs returned a nil")
}
allLabelsM[*pair.Name] = *pair.Value
}
weighted, err := newWeightedHistogram(desc, WeightedHistogramOpts{
Namespace: opts.Namespace,
Subsystem: opts.Subsystem,
Name: opts.Name,
Help: opts.Help,
ConstLabels: allLabelsM,
Buckets: opts.Buckets,
}, variableLabelValues...)
if err != nil {
return nil, err
}
return &timingHistogram{
nowFunc: nowFunc,
weighted: weighted,
lastSetTime: nowFunc(),
value: opts.InitialValue,
}, nil
}
type timingHistogram struct {
nowFunc func() time.Time
weighted *weightedHistogram
// The following fields must only be accessed with weighted's lock held
lastSetTime time.Time // identifies when value was last set
value float64
}
var _ TimingHistogram = &timingHistogram{}
func (th *timingHistogram) Set(newValue float64) {
th.update(func(float64) float64 { return newValue })
}
func (th *timingHistogram) Inc() {
th.update(func(oldValue float64) float64 { return oldValue + 1 })
}
func (th *timingHistogram) Dec() {
th.update(func(oldValue float64) float64 { return oldValue - 1 })
}
func (th *timingHistogram) Add(delta float64) {
th.update(func(oldValue float64) float64 { return oldValue + delta })
}
func (th *timingHistogram) Sub(delta float64) {
th.update(func(oldValue float64) float64 { return oldValue - delta })
}
func (th *timingHistogram) SetToCurrentTime() {
th.update(func(oldValue float64) float64 { return th.nowFunc().Sub(time.Unix(0, 0)).Seconds() })
}
func (th *timingHistogram) update(updateFn func(float64) float64) {
th.weighted.lock.Lock()
defer th.weighted.lock.Unlock()
now := th.nowFunc()
delta := now.Sub(th.lastSetTime)
value := th.value
if delta > 0 {
th.weighted.observeWithWeightLocked(value, uint64(delta))
th.lastSetTime = now
}
th.value = updateFn(value)
}
func (th *timingHistogram) Desc() *prometheus.Desc {
return th.weighted.Desc()
}
func (th *timingHistogram) Write(dest *dto.Metric) error {
th.Add(0) // account for time since last update
return th.weighted.Write(dest)
}
func (th *timingHistogram) Describe(ch chan<- *prometheus.Desc) {
ch <- th.weighted.Desc()
}
func (th *timingHistogram) Collect(ch chan<- prometheus.Metric) {
ch <- th
}

View File

@ -0,0 +1,111 @@
/*
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 prometheusextension
import (
"time"
"github.com/prometheus/client_golang/prometheus"
)
// GaugeVecOps is a bunch of Gauge that have the same
// Desc and are distinguished by the values for their variable labels.
type GaugeVecOps interface {
GetMetricWith(prometheus.Labels) (GaugeOps, error)
GetMetricWithLabelValues(lvs ...string) (GaugeOps, error)
With(prometheus.Labels) GaugeOps
WithLabelValues(...string) GaugeOps
CurryWith(prometheus.Labels) (GaugeVecOps, error)
MustCurryWith(prometheus.Labels) GaugeVecOps
}
type TimingHistogramVec struct {
*prometheus.MetricVec
}
var _ GaugeVecOps = &TimingHistogramVec{}
var _ prometheus.Collector = &TimingHistogramVec{}
func NewTimingHistogramVec(opts TimingHistogramOpts, labelNames ...string) *TimingHistogramVec {
return NewTestableTimingHistogramVec(time.Now, opts, labelNames...)
}
func NewTestableTimingHistogramVec(nowFunc func() time.Time, opts TimingHistogramOpts, labelNames ...string) *TimingHistogramVec {
desc := prometheus.NewDesc(
prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
wrapTimingHelp(opts.Help),
labelNames,
opts.ConstLabels,
)
return &TimingHistogramVec{
MetricVec: prometheus.NewMetricVec(desc, func(lvs ...string) prometheus.Metric {
metric, err := newTimingHistogram(nowFunc, desc, opts, lvs...)
if err != nil {
panic(err) // like in prometheus.newHistogram
}
return metric
}),
}
}
func (hv *TimingHistogramVec) GetMetricWith(labels prometheus.Labels) (GaugeOps, error) {
metric, err := hv.MetricVec.GetMetricWith(labels)
if metric != nil {
return metric.(GaugeOps), err
}
return nil, err
}
func (hv *TimingHistogramVec) GetMetricWithLabelValues(lvs ...string) (GaugeOps, error) {
metric, err := hv.MetricVec.GetMetricWithLabelValues(lvs...)
if metric != nil {
return metric.(GaugeOps), err
}
return nil, err
}
func (hv *TimingHistogramVec) With(labels prometheus.Labels) GaugeOps {
h, err := hv.GetMetricWith(labels)
if err != nil {
panic(err)
}
return h
}
func (hv *TimingHistogramVec) WithLabelValues(lvs ...string) GaugeOps {
h, err := hv.GetMetricWithLabelValues(lvs...)
if err != nil {
panic(err)
}
return h
}
func (hv *TimingHistogramVec) CurryWith(labels prometheus.Labels) (GaugeVecOps, error) {
vec, err := hv.MetricVec.CurryWith(labels)
if vec != nil {
return &TimingHistogramVec{MetricVec: vec}, err
}
return nil, err
}
func (hv *TimingHistogramVec) MustCurryWith(labels prometheus.Labels) GaugeVecOps {
vec, err := hv.CurryWith(labels)
if err != nil {
panic(err)
}
return vec
}

View File

@ -0,0 +1,203 @@
/*
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 prometheusextension
import (
"fmt"
"math"
"sort"
"sync"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
)
// WeightedHistogram generalizes Histogram: each observation has
// an associated _weight_. For a given `x` and `N`,
// `1` call on `ObserveWithWeight(x, N)` has the same meaning as
// `N` calls on `ObserveWithWeight(x, 1)`.
// The weighted sum might differ slightly due to the use of
// floating point, although the implementation takes some steps
// to mitigate that.
// If every weight were 1,
// this would be the same as the existing Histogram abstraction.
type WeightedHistogram interface {
prometheus.Metric
prometheus.Collector
WeightedObserver
}
// WeightedObserver generalizes the Observer interface.
type WeightedObserver interface {
// Set the variable to the given value with the given weight.
ObserveWithWeight(value float64, weight uint64)
}
// WeightedHistogramOpts is the same as for an ordinary Histogram
type WeightedHistogramOpts = prometheus.HistogramOpts
// NewWeightedHistogram creates a new WeightedHistogram
func NewWeightedHistogram(opts WeightedHistogramOpts) (WeightedHistogram, error) {
desc := prometheus.NewDesc(
prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
wrapWeightedHelp(opts.Help),
nil,
opts.ConstLabels,
)
return newWeightedHistogram(desc, opts)
}
func wrapWeightedHelp(given string) string {
return "EXPERIMENTAL: " + given
}
func newWeightedHistogram(desc *prometheus.Desc, opts WeightedHistogramOpts, variableLabelValues ...string) (*weightedHistogram, error) {
if len(opts.Buckets) == 0 {
opts.Buckets = prometheus.DefBuckets
}
for i, upperBound := range opts.Buckets {
if i < len(opts.Buckets)-1 {
if upperBound >= opts.Buckets[i+1] {
return nil, fmt.Errorf(
"histogram buckets must be in increasing order: %f >= %f",
upperBound, opts.Buckets[i+1],
)
}
} else {
if math.IsInf(upperBound, +1) {
// The +Inf bucket is implicit. Remove it here.
opts.Buckets = opts.Buckets[:i]
}
}
}
upperBounds := make([]float64, len(opts.Buckets))
copy(upperBounds, opts.Buckets)
return &weightedHistogram{
desc: desc,
variableLabelValues: variableLabelValues,
upperBounds: upperBounds,
buckets: make([]uint64, len(upperBounds)+1),
hotCount: initialHotCount,
}, nil
}
type weightedHistogram struct {
desc *prometheus.Desc
variableLabelValues []string
upperBounds []float64 // exclusive of +Inf
lock sync.Mutex // applies to all the following
// buckets is longer by one than upperBounds.
// For 0 <= idx < len(upperBounds), buckets[idx] holds the
// accumulated time.Duration that value has been <=
// upperBounds[idx] but not <= upperBounds[idx-1].
// buckets[len(upperBounds)] holds the accumulated
// time.Duration when value fit in no other bucket.
buckets []uint64
// sumHot + sumCold is the weighted sum of value.
// Rather than risk loss of precision in one
// float64, we do this sum hierarchically. Many successive
// increments are added into sumHot; once in a while
// the magnitude of sumHot is compared to the magnitude
// of sumCold and, if the ratio is high enough,
// sumHot is transferred into sumCold.
sumHot float64
sumCold float64
transferThreshold float64 // = math.Abs(sumCold) / 2^26 (that's about half of the bits of precision in a float64)
// hotCount is used to decide when to consider dumping sumHot into sumCold.
// hotCount counts upward from initialHotCount to zero.
hotCount int
}
// initialHotCount is the negative of the number of terms
// that are summed into sumHot before considering whether
// to transfer to sumCold. This only has to be big enough
// to make the extra floating point operations occur in a
// distinct minority of cases.
const initialHotCount = -15
var _ WeightedHistogram = &weightedHistogram{}
var _ prometheus.Metric = &weightedHistogram{}
var _ prometheus.Collector = &weightedHistogram{}
func (sh *weightedHistogram) ObserveWithWeight(value float64, weight uint64) {
idx := sort.SearchFloat64s(sh.upperBounds, value)
sh.lock.Lock()
defer sh.lock.Unlock()
sh.updateLocked(idx, value, weight)
}
func (sh *weightedHistogram) observeWithWeightLocked(value float64, weight uint64) {
idx := sort.SearchFloat64s(sh.upperBounds, value)
sh.updateLocked(idx, value, weight)
}
func (sh *weightedHistogram) updateLocked(idx int, value float64, weight uint64) {
sh.buckets[idx] += weight
newSumHot := sh.sumHot + float64(weight)*value
sh.hotCount++
if sh.hotCount >= 0 {
sh.hotCount = initialHotCount
if math.Abs(newSumHot) > sh.transferThreshold {
newSumCold := sh.sumCold + newSumHot
sh.sumCold = newSumCold
sh.transferThreshold = math.Abs(newSumCold / 67108864)
sh.sumHot = 0
return
}
}
sh.sumHot = newSumHot
}
func (sh *weightedHistogram) Desc() *prometheus.Desc {
return sh.desc
}
func (sh *weightedHistogram) Write(dest *dto.Metric) error {
count, sum, buckets := func() (uint64, float64, map[float64]uint64) {
sh.lock.Lock()
defer sh.lock.Unlock()
nBounds := len(sh.upperBounds)
buckets := make(map[float64]uint64, nBounds)
var count uint64
for idx, upperBound := range sh.upperBounds {
count += sh.buckets[idx]
buckets[upperBound] = count
}
count += sh.buckets[nBounds]
return count, sh.sumHot + sh.sumCold, buckets
}()
metric, err := prometheus.NewConstHistogram(sh.desc, count, sum, buckets, sh.variableLabelValues...)
if err != nil {
return err
}
return metric.Write(dest)
}
func (sh *weightedHistogram) Describe(ch chan<- *prometheus.Desc) {
ch <- sh.desc
}
func (sh *weightedHistogram) Collect(ch chan<- prometheus.Metric) {
ch <- sh
}

View File

@ -0,0 +1,106 @@
/*
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 prometheusextension
import (
"github.com/prometheus/client_golang/prometheus"
)
// WeightedObserverVec is a bunch of WeightedObservers that have the same
// Desc and are distinguished by the values for their variable labels.
type WeightedObserverVec interface {
GetMetricWith(prometheus.Labels) (WeightedObserver, error)
GetMetricWithLabelValues(lvs ...string) (WeightedObserver, error)
With(prometheus.Labels) WeightedObserver
WithLabelValues(...string) WeightedObserver
CurryWith(prometheus.Labels) (WeightedObserverVec, error)
MustCurryWith(prometheus.Labels) WeightedObserverVec
}
// WeightedHistogramVec implements WeightedObserverVec
type WeightedHistogramVec struct {
*prometheus.MetricVec
}
var _ WeightedObserverVec = &WeightedHistogramVec{}
var _ prometheus.Collector = &WeightedHistogramVec{}
func NewWeightedHistogramVec(opts WeightedHistogramOpts, labelNames ...string) *WeightedHistogramVec {
desc := prometheus.NewDesc(
prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
wrapWeightedHelp(opts.Help),
labelNames,
opts.ConstLabels,
)
return &WeightedHistogramVec{
MetricVec: prometheus.NewMetricVec(desc, func(lvs ...string) prometheus.Metric {
metric, err := newWeightedHistogram(desc, opts, lvs...)
if err != nil {
panic(err) // like in prometheus.newHistogram
}
return metric
}),
}
}
func (hv *WeightedHistogramVec) GetMetricWith(labels prometheus.Labels) (WeightedObserver, error) {
metric, err := hv.MetricVec.GetMetricWith(labels)
if metric != nil {
return metric.(WeightedObserver), err
}
return nil, err
}
func (hv *WeightedHistogramVec) GetMetricWithLabelValues(lvs ...string) (WeightedObserver, error) {
metric, err := hv.MetricVec.GetMetricWithLabelValues(lvs...)
if metric != nil {
return metric.(WeightedObserver), err
}
return nil, err
}
func (hv *WeightedHistogramVec) With(labels prometheus.Labels) WeightedObserver {
h, err := hv.GetMetricWith(labels)
if err != nil {
panic(err)
}
return h
}
func (hv *WeightedHistogramVec) WithLabelValues(lvs ...string) WeightedObserver {
h, err := hv.GetMetricWithLabelValues(lvs...)
if err != nil {
panic(err)
}
return h
}
func (hv *WeightedHistogramVec) CurryWith(labels prometheus.Labels) (WeightedObserverVec, error) {
vec, err := hv.MetricVec.CurryWith(labels)
if vec != nil {
return &WeightedHistogramVec{MetricVec: vec}, err
}
return nil, err
}
func (hv *WeightedHistogramVec) MustCurryWith(labels prometheus.Labels) WeightedObserverVec {
vec, err := hv.CurryWith(labels)
if err != nil {
panic(err)
}
return vec
}

View File

@ -18,10 +18,17 @@ package metrics
import (
"context"
"github.com/blang/semver/v4"
"github.com/prometheus/client_golang/prometheus"
)
const (
DefAgeBuckets = prometheus.DefAgeBuckets
DefBufCap = prometheus.DefBufCap
DefMaxAge = prometheus.DefMaxAge
)
// Summary is our internal representation for our wrapping struct around prometheus
// summaries. Summary implements both kubeCollector and ObserverMetric
//
@ -93,7 +100,9 @@ type SummaryVec struct {
// NewSummaryVec returns an object which satisfies kubeCollector and wraps the
// prometheus.SummaryVec object. However, the object returned will not measure
// anything unless the collector is first registered, since the metric is lazily instantiated.
// anything unless the collector is first registered, since the metric is lazily instantiated,
// and only members extracted after
// registration will actually measure anything.
//
// DEPRECATED: as per the metrics overhaul KEP
func NewSummaryVec(opts *SummaryOpts, labels []string) *SummaryVec {
@ -130,13 +139,16 @@ func (v *SummaryVec) initializeDeprecatedMetric() {
v.initializeMetric()
}
// Default Prometheus behavior actually results in the creation of a new metric
// if a metric with the unique label values is not found in the underlying stored metricMap.
// Default Prometheus Vec behavior is that member extraction results in creation of a new element
// if one with the unique label values is not found in the underlying stored metricMap.
// This means that if this function is called but the underlying metric is not registered
// (which means it will never be exposed externally nor consumed), the metric will exist in memory
// for perpetuity (i.e. throughout application lifecycle).
//
// For reference: https://github.com/prometheus/client_golang/blob/v0.9.2/prometheus/summary.go#L485-L495
// For reference: https://github.com/prometheus/client_golang/blob/v0.9.2/prometheus/histogram.go#L460-L470
//
// In contrast, the Vec behavior in this package is that member extraction before registration
// returns a permanent noop object.
// WithLabelValues returns the ObserverMetric for the given slice of label
// values (same order as the VariableLabels in Desc). If that combination of

View File

@ -0,0 +1,267 @@
/*
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 metrics
import (
"context"
"time"
"github.com/blang/semver/v4"
promext "k8s.io/component-base/metrics/prometheusextension"
)
// PrometheusTimingHistogram is the abstraction of the underlying histogram
// that we want to promote from the wrapper.
type PrometheusTimingHistogram interface {
GaugeMetric
}
// TimingHistogram is our internal representation for our wrapping struct around
// timing histograms. It implements both kubeCollector and GaugeMetric
type TimingHistogram struct {
PrometheusTimingHistogram
*TimingHistogramOpts
nowFunc func() time.Time
lazyMetric
selfCollector
}
var _ GaugeMetric = &TimingHistogram{}
var _ Registerable = &TimingHistogram{}
var _ kubeCollector = &TimingHistogram{}
// NewTimingHistogram returns an object which is TimingHistogram-like. However, nothing
// will be measured until the histogram is registered somewhere.
func NewTimingHistogram(opts *TimingHistogramOpts) *TimingHistogram {
return NewTestableTimingHistogram(time.Now, opts)
}
// NewTestableTimingHistogram adds injection of the clock
func NewTestableTimingHistogram(nowFunc func() time.Time, opts *TimingHistogramOpts) *TimingHistogram {
opts.StabilityLevel.setDefaults()
h := &TimingHistogram{
TimingHistogramOpts: opts,
nowFunc: nowFunc,
lazyMetric: lazyMetric{},
}
h.setPrometheusHistogram(noopMetric{})
h.lazyInit(h, BuildFQName(opts.Namespace, opts.Subsystem, opts.Name))
return h
}
// setPrometheusHistogram sets the underlying KubeGauge object, i.e. the thing that does the measurement.
func (h *TimingHistogram) setPrometheusHistogram(histogram promext.TimingHistogram) {
h.PrometheusTimingHistogram = histogram
h.initSelfCollection(histogram)
}
// DeprecatedVersion returns a pointer to the Version or nil
func (h *TimingHistogram) DeprecatedVersion() *semver.Version {
return parseSemver(h.TimingHistogramOpts.DeprecatedVersion)
}
// initializeMetric invokes the actual prometheus.Histogram object instantiation
// and stores a reference to it
func (h *TimingHistogram) initializeMetric() {
h.TimingHistogramOpts.annotateStabilityLevel()
// this actually creates the underlying prometheus gauge.
histogram, err := promext.NewTestableTimingHistogram(h.nowFunc, h.TimingHistogramOpts.toPromHistogramOpts())
if err != nil {
panic(err) // handle as for regular histograms
}
h.setPrometheusHistogram(histogram)
}
// initializeDeprecatedMetric invokes the actual prometheus.Histogram object instantiation
// but modifies the Help description prior to object instantiation.
func (h *TimingHistogram) initializeDeprecatedMetric() {
h.TimingHistogramOpts.markDeprecated()
h.initializeMetric()
}
// WithContext allows the normal TimingHistogram metric to pass in context. The context is no-op now.
func (h *TimingHistogram) WithContext(ctx context.Context) GaugeMetric {
return h.PrometheusTimingHistogram
}
// TimingHistogramVec is the internal representation of our wrapping struct around prometheus
// TimingHistogramVecs.
type TimingHistogramVec struct {
*promext.TimingHistogramVec
*TimingHistogramOpts
nowFunc func() time.Time
lazyMetric
originalLabels []string
}
var _ GaugeVecMetric = &TimingHistogramVec{}
var _ Registerable = &TimingHistogramVec{}
var _ kubeCollector = &TimingHistogramVec{}
// NewTimingHistogramVec returns an object which satisfies the kubeCollector, Registerable, and GaugeVecMetric interfaces
// and wraps an underlying promext.TimingHistogramVec object. Note well the way that
// behavior depends on registration and whether this is hidden.
func NewTimingHistogramVec(opts *TimingHistogramOpts, labels []string) *TimingHistogramVec {
return NewTestableTimingHistogramVec(time.Now, opts, labels)
}
// NewTestableTimingHistogramVec adds injection of the clock.
func NewTestableTimingHistogramVec(nowFunc func() time.Time, opts *TimingHistogramOpts, labels []string) *TimingHistogramVec {
opts.StabilityLevel.setDefaults()
fqName := BuildFQName(opts.Namespace, opts.Subsystem, opts.Name)
allowListLock.RLock()
if allowList, ok := labelValueAllowLists[fqName]; ok {
opts.LabelValueAllowLists = allowList
}
allowListLock.RUnlock()
v := &TimingHistogramVec{
TimingHistogramVec: noopTimingHistogramVec,
TimingHistogramOpts: opts,
nowFunc: nowFunc,
originalLabels: labels,
lazyMetric: lazyMetric{},
}
v.lazyInit(v, fqName)
return v
}
// DeprecatedVersion returns a pointer to the Version or nil
func (v *TimingHistogramVec) DeprecatedVersion() *semver.Version {
return parseSemver(v.TimingHistogramOpts.DeprecatedVersion)
}
func (v *TimingHistogramVec) initializeMetric() {
v.TimingHistogramOpts.annotateStabilityLevel()
v.TimingHistogramVec = promext.NewTestableTimingHistogramVec(v.nowFunc, v.TimingHistogramOpts.toPromHistogramOpts(), v.originalLabels...)
}
func (v *TimingHistogramVec) initializeDeprecatedMetric() {
v.TimingHistogramOpts.markDeprecated()
v.initializeMetric()
}
// WithLabelValuesChecked, if called before this vector has been registered in
// at least one registry, will return a noop gauge and
// an error that passes ErrIsNotRegistered.
// If called on a hidden vector,
// will return a noop gauge and a nil error.
// If called with a syntactic problem in the labels, will
// return a noop gauge and an error about the labels.
// If none of the above apply, this method will return
// the appropriate vector member and a nil error.
func (v *TimingHistogramVec) WithLabelValuesChecked(lvs ...string) (GaugeMetric, error) {
if !v.IsCreated() {
if v.IsHidden() {
return noop, nil
}
return noop, errNotRegistered
}
if v.LabelValueAllowLists != nil {
v.LabelValueAllowLists.ConstrainToAllowedList(v.originalLabels, lvs)
}
ops, err := v.TimingHistogramVec.GetMetricWithLabelValues(lvs...)
return ops.(GaugeMetric), err
}
// WithLabelValues calls WithLabelValuesChecked
// and handles errors as follows.
// An error that passes ErrIsNotRegistered is ignored
// and the noop gauge is returned;
// all other errors cause a panic.
func (v *TimingHistogramVec) WithLabelValues(lvs ...string) GaugeMetric {
ans, err := v.WithLabelValuesChecked(lvs...)
if err == nil || ErrIsNotRegistered(err) {
return ans
}
panic(err)
}
// WithChecked, if called before this vector has been registered in
// at least one registry, will return a noop gauge and
// an error that passes ErrIsNotRegistered.
// If called on a hidden vector,
// will return a noop gauge and a nil error.
// If called with a syntactic problem in the labels, will
// return a noop gauge and an error about the labels.
// If none of the above apply, this method will return
// the appropriate vector member and a nil error.
func (v *TimingHistogramVec) WithChecked(labels map[string]string) (GaugeMetric, error) {
if !v.IsCreated() {
if v.IsHidden() {
return noop, nil
}
return noop, errNotRegistered
}
if v.LabelValueAllowLists != nil {
v.LabelValueAllowLists.ConstrainLabelMap(labels)
}
ops, err := v.TimingHistogramVec.GetMetricWith(labels)
return ops.(GaugeMetric), err
}
// With calls WithChecked and handles errors as follows.
// An error that passes ErrIsNotRegistered is ignored
// and the noop gauge is returned;
// all other errors cause a panic.
func (v *TimingHistogramVec) With(labels map[string]string) GaugeMetric {
ans, err := v.WithChecked(labels)
if err == nil || ErrIsNotRegistered(err) {
return ans
}
panic(err)
}
// Delete deletes the metric where the variable labels are the same as those
// passed in as labels. It returns true if a metric was deleted.
//
// It is not an error if the number and names of the Labels are inconsistent
// with those of the VariableLabels in Desc. However, such inconsistent Labels
// can never match an actual metric, so the method will always return false in
// that case.
func (v *TimingHistogramVec) Delete(labels map[string]string) bool {
if !v.IsCreated() {
return false // since we haven't created the metric, we haven't deleted a metric with the passed in values
}
return v.TimingHistogramVec.Delete(labels)
}
// Reset deletes all metrics in this vector.
func (v *TimingHistogramVec) Reset() {
if !v.IsCreated() {
return
}
v.TimingHistogramVec.Reset()
}
// WithContext returns wrapped TimingHistogramVec with context
func (v *TimingHistogramVec) InterfaceWithContext(ctx context.Context) GaugeVecMetric {
return &TimingHistogramVecWithContext{
ctx: ctx,
TimingHistogramVec: v,
}
}
// TimingHistogramVecWithContext is the wrapper of TimingHistogramVec with context.
// Currently the context is ignored.
type TimingHistogramVecWithContext struct {
*TimingHistogramVec
ctx context.Context
}

View File

@ -50,7 +50,8 @@ func NewLazyConstMetric(desc *Desc, valueType ValueType, value float64, labelVal
// NewLazyMetricWithTimestamp is a helper of NewMetricWithTimestamp.
//
// Warning: the Metric 'm' must be the one created by NewLazyConstMetric(),
// otherwise, no stability guarantees would be offered.
//
// otherwise, no stability guarantees would be offered.
func NewLazyMetricWithTimestamp(t time.Time, m Metric) Metric {
if m == nil {
return nil

View File

@ -17,6 +17,8 @@ limitations under the License.
package metrics
import (
"errors"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
)
@ -65,6 +67,64 @@ type GaugeMetric interface {
SetToCurrentTime()
}
// GaugeVecMetric is a collection of Gauges that differ only in label values.
type GaugeVecMetric interface {
// Default Prometheus Vec behavior is that member extraction results in creation of a new element
// if one with the unique label values is not found in the underlying stored metricMap.
// This means that if this function is called but the underlying metric is not registered
// (which means it will never be exposed externally nor consumed), the metric would exist in memory
// for perpetuity (i.e. throughout application lifecycle).
//
// For reference: https://github.com/prometheus/client_golang/blob/v0.9.2/prometheus/gauge.go#L190-L208
//
// In contrast, the Vec behavior in this package is that member extraction before registration
// returns a permanent noop object.
// WithLabelValuesChecked, if called before this vector has been registered in
// at least one registry, will return a noop gauge and
// an error that passes ErrIsNotRegistered.
// If called on a hidden vector,
// will return a noop gauge and a nil error.
// If called with a syntactic problem in the labels, will
// return a noop gauge and an error about the labels.
// If none of the above apply, this method will return
// the appropriate vector member and a nil error.
WithLabelValuesChecked(labelValues ...string) (GaugeMetric, error)
// WithLabelValues calls WithLabelValuesChecked
// and handles errors as follows.
// An error that passes ErrIsNotRegistered is ignored
// and the noop gauge is returned;
// all other errors cause a panic.
WithLabelValues(labelValues ...string) GaugeMetric
// WithChecked, if called before this vector has been registered in
// at least one registry, will return a noop gauge and
// an error that passes ErrIsNotRegistered.
// If called on a hidden vector,
// will return a noop gauge and a nil error.
// If called with a syntactic problem in the labels, will
// return a noop gauge and an error about the labels.
// If none of the above apply, this method will return
// the appropriate vector member and a nil error.
WithChecked(labels map[string]string) (GaugeMetric, error)
// With calls WithChecked and handles errors as follows.
// An error that passes ErrIsNotRegistered is ignored
// and the noop gauge is returned;
// all other errors cause a panic.
With(labels map[string]string) GaugeMetric
// Delete asserts that the vec should have no member for the given label set.
// The returned bool indicates whether there was a change.
// The return will certainly be `false` if the given label set has the wrong
// set of label names.
Delete(map[string]string) bool
// Reset removes all the members
Reset()
}
// ObserverMetric captures individual observations.
type ObserverMetric interface {
Observe(float64)
@ -93,3 +153,9 @@ type GaugeFunc interface {
Metric
Collector
}
func ErrIsNotRegistered(err error) bool {
return err == errNotRegistered
}
var errNotRegistered = errors.New("metric vec is not registered yet")

View File

@ -1,80 +0,0 @@
/*
Copyright 2021 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 traces
import (
"context"
"net/http"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel/exporters/otlp"
"go.opentelemetry.io/otel/exporters/otlp/otlpgrpc"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace"
"k8s.io/client-go/transport"
"k8s.io/klog/v2"
)
// NewProvider initializes tracing in the component, and enforces recommended tracing behavior.
func NewProvider(ctx context.Context, baseSampler sdktrace.Sampler, resourceOpts []resource.Option, opts ...otlpgrpc.Option) trace.TracerProvider {
opts = append(opts, otlpgrpc.WithInsecure())
driver := otlpgrpc.NewDriver(opts...)
exporter, err := otlp.NewExporter(ctx, driver)
if err != nil {
klog.Fatalf("Failed to create OTLP exporter: %v", err)
}
res, err := resource.New(ctx, resourceOpts...)
if err != nil {
klog.Fatalf("Failed to create resource: %v", err)
}
bsp := sdktrace.NewBatchSpanProcessor(exporter)
return sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.ParentBased(baseSampler)),
sdktrace.WithSpanProcessor(bsp),
sdktrace.WithResource(res),
)
}
// WrapperFor can be used to add tracing to a *rest.Config. Example usage:
// tp := traces.NewProvider(...)
// config, _ := rest.InClusterConfig()
// config.Wrap(traces.WrapperFor(&tp))
// kubeclient, _ := clientset.NewForConfig(config)
func WrapperFor(tp *trace.TracerProvider) transport.WrapperFunc {
return func(rt http.RoundTripper) http.RoundTripper {
opts := []otelhttp.Option{
otelhttp.WithPropagators(Propagators()),
}
if tp != nil {
opts = append(opts, otelhttp.WithTracerProvider(*tp))
}
// Even if there is no TracerProvider, the otelhttp still handles context propagation.
// See https://github.com/open-telemetry/opentelemetry-go/tree/main/example/passthrough
return otelhttp.NewTransport(rt, opts...)
}
}
// Propagators returns the recommended set of propagators.
func Propagators() propagation.TextMapPropagator {
return propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})
}

88
vendor/k8s.io/component-base/tracing/api/v1/config.go generated vendored Normal file
View File

@ -0,0 +1,88 @@
/*
Copyright 2021 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 v1
import (
"fmt"
"net/url"
"strings"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/component-base/featuregate"
)
var (
maxSamplingRatePerMillion = int32(1000000)
)
// ValidateTracingConfiguration validates the tracing configuration
func ValidateTracingConfiguration(traceConfig *TracingConfiguration, featureGate featuregate.FeatureGate, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if traceConfig == nil {
return allErrs
}
if traceConfig.SamplingRatePerMillion != nil {
allErrs = append(allErrs, validateSamplingRate(*traceConfig.SamplingRatePerMillion, fldPath.Child("samplingRatePerMillion"))...)
}
if traceConfig.Endpoint != nil {
allErrs = append(allErrs, validateEndpoint(*traceConfig.Endpoint, fldPath.Child("endpoint"))...)
}
return allErrs
}
func validateSamplingRate(rate int32, fldPath *field.Path) field.ErrorList {
errs := field.ErrorList{}
if rate < 0 {
errs = append(errs, field.Invalid(
fldPath, rate,
"sampling rate must be positive",
))
}
if rate > maxSamplingRatePerMillion {
errs = append(errs, field.Invalid(
fldPath, rate,
"sampling rate per million must be less than or equal to one million",
))
}
return errs
}
func validateEndpoint(endpoint string, fldPath *field.Path) field.ErrorList {
errs := field.ErrorList{}
if !strings.Contains(endpoint, "//") {
endpoint = "dns://" + endpoint
}
url, err := url.Parse(endpoint)
if err != nil {
errs = append(errs, field.Invalid(
fldPath, endpoint,
err.Error(),
))
return errs
}
switch url.Scheme {
case "dns":
case "unix":
case "unix-abstract":
default:
errs = append(errs, field.Invalid(
fldPath, endpoint,
fmt.Sprintf("unsupported scheme: %v. Options are none, dns, unix, or unix-abstract. See https://github.com/grpc/grpc/blob/master/doc/naming.md", url.Scheme),
))
}
return errs
}

29
vendor/k8s.io/component-base/tracing/api/v1/doc.go generated vendored Normal file
View File

@ -0,0 +1,29 @@
/*
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.
*/
// +k8s:deepcopy-gen=package
// Package v1 contains the configuration API for tracing.
//
// The intention is to only have a single version of this API, potentially with
// new fields added over time in a backwards-compatible manner. Fields for
// alpha or beta features are allowed as long as they are defined so that not
// changing the defaults leaves those features disabled.
//
// The "v1" package name is just a reminder that API compatibility rules apply,
// not an indication of the stability of all features covered by it.
package v1 // import "k8s.io/component-base/tracing/api/v1"

32
vendor/k8s.io/component-base/tracing/api/v1/types.go generated vendored Normal file
View File

@ -0,0 +1,32 @@
/*
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 v1
// TracingConfiguration provides versioned configuration for OpenTelemetry tracing clients.
type TracingConfiguration struct {
// Endpoint of the collector this component will report traces to.
// The connection is insecure, and does not currently support TLS.
// Recommended is unset, and endpoint is the otlp grpc default, localhost:4317.
// +optional
Endpoint *string `json:"endpoint,omitempty"`
// SamplingRatePerMillion is the number of samples to collect per million spans.
// Recommended is unset. If unset, sampler respects its parent span's sampling
// rate, but otherwise never samples.
// +optional
SamplingRatePerMillion *int32 `json:"samplingRatePerMillion,omitempty"`
}

View File

@ -0,0 +1,48 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright 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.
*/
// Code generated by deepcopy-gen. DO NOT EDIT.
package v1
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TracingConfiguration) DeepCopyInto(out *TracingConfiguration) {
*out = *in
if in.Endpoint != nil {
in, out := &in.Endpoint, &out.Endpoint
*out = new(string)
**out = **in
}
if in.SamplingRatePerMillion != nil {
in, out := &in.SamplingRatePerMillion, &out.SamplingRatePerMillion
*out = new(int32)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TracingConfiguration.
func (in *TracingConfiguration) DeepCopy() *TracingConfiguration {
if in == nil {
return nil
}
out := new(TracingConfiguration)
in.DeepCopyInto(out)
return out
}

108
vendor/k8s.io/component-base/tracing/utils.go generated vendored Normal file
View File

@ -0,0 +1,108 @@
/*
Copyright 2021 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 tracing
import (
"context"
"net/http"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel/exporters/otlp"
"go.opentelemetry.io/otel/exporters/otlp/otlpgrpc"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
oteltrace "go.opentelemetry.io/otel/trace"
"k8s.io/client-go/transport"
"k8s.io/component-base/tracing/api/v1"
)
// NewProvider creates a TracerProvider in a component, and enforces recommended tracing behavior
func NewProvider(ctx context.Context,
tracingConfig *v1.TracingConfiguration,
addedOpts []otlpgrpc.Option,
resourceOpts []resource.Option,
) (oteltrace.TracerProvider, error) {
if tracingConfig == nil {
return oteltrace.NewNoopTracerProvider(), nil
}
opts := append([]otlpgrpc.Option{}, addedOpts...)
if tracingConfig.Endpoint != nil {
opts = append(opts, otlpgrpc.WithEndpoint(*tracingConfig.Endpoint))
}
opts = append(opts, otlpgrpc.WithInsecure())
driver := otlpgrpc.NewDriver(opts...)
exporter, err := otlp.NewExporter(ctx, driver)
if err != nil {
return nil, err
}
res, err := resource.New(ctx, resourceOpts...)
if err != nil {
return nil, err
}
// sampler respects parent span's sampling rate or
// otherwise never samples.
sampler := sdktrace.NeverSample()
// Or, emit spans for a fraction of transactions
if tracingConfig.SamplingRatePerMillion != nil && *tracingConfig.SamplingRatePerMillion > 0 {
sampler = sdktrace.TraceIDRatioBased(float64(*tracingConfig.SamplingRatePerMillion) / float64(1000000))
}
// batch span processor to aggregate spans before export.
bsp := sdktrace.NewBatchSpanProcessor(exporter)
tp := sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.ParentBased(sampler)),
sdktrace.WithSpanProcessor(bsp),
sdktrace.WithResource(res),
)
return tp, nil
}
// WithTracing adds tracing to requests if the incoming request is sampled
func WithTracing(handler http.Handler, tp oteltrace.TracerProvider, serviceName string) http.Handler {
opts := []otelhttp.Option{
otelhttp.WithPropagators(Propagators()),
otelhttp.WithTracerProvider(tp),
}
// With Noop TracerProvider, the otelhttp still handles context propagation.
// See https://github.com/open-telemetry/opentelemetry-go/tree/main/example/passthrough
return otelhttp.NewHandler(handler, serviceName, opts...)
}
// WrapperFor can be used to add tracing to a *rest.Config.
// Example usage:
// tp := NewProvider(...)
// config, _ := rest.InClusterConfig()
// config.Wrap(WrapperFor(&tp))
// kubeclient, _ := clientset.NewForConfig(config)
func WrapperFor(tp oteltrace.TracerProvider) transport.WrapperFunc {
return func(rt http.RoundTripper) http.RoundTripper {
opts := []otelhttp.Option{
otelhttp.WithPropagators(Propagators()),
otelhttp.WithTracerProvider(tp),
}
// With Noop TracerProvider, the otelhttp still handles context propagation.
// See https://github.com/open-telemetry/opentelemetry-go/tree/main/example/passthrough
return otelhttp.NewTransport(rt, opts...)
}
}
// Propagators returns the recommended set of propagators.
func Propagators() propagation.TextMapPropagator {
return propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})
}