mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-22 18:16:52 +00:00
Merge pull request #106090 from pohly/log-v-flags
component-base: move v/vmodule/log-flush-frequency into LoggingConfiguration
This commit is contained in:
commit
dc93951ad0
@ -170,7 +170,6 @@ func (s *ServerRunOptions) Validate() []error {
|
|||||||
errs = append(errs, s.APIEnablement.Validate(legacyscheme.Scheme, apiextensionsapiserver.Scheme, aggregatorscheme.Scheme)...)
|
errs = append(errs, s.APIEnablement.Validate(legacyscheme.Scheme, apiextensionsapiserver.Scheme, aggregatorscheme.Scheme)...)
|
||||||
errs = append(errs, validateTokenRequest(s)...)
|
errs = append(errs, validateTokenRequest(s)...)
|
||||||
errs = append(errs, s.Metrics.Validate()...)
|
errs = append(errs, s.Metrics.Validate()...)
|
||||||
errs = append(errs, s.Logs.Validate()...)
|
|
||||||
errs = append(errs, validateAPIServerIdentity(s)...)
|
errs = append(errs, validateAPIServerIdentity(s)...)
|
||||||
|
|
||||||
return errs
|
return errs
|
||||||
|
@ -56,6 +56,7 @@ import (
|
|||||||
"k8s.io/client-go/util/keyutil"
|
"k8s.io/client-go/util/keyutil"
|
||||||
cliflag "k8s.io/component-base/cli/flag"
|
cliflag "k8s.io/component-base/cli/flag"
|
||||||
"k8s.io/component-base/cli/globalflag"
|
"k8s.io/component-base/cli/globalflag"
|
||||||
|
"k8s.io/component-base/logs"
|
||||||
_ "k8s.io/component-base/metrics/prometheus/workqueue" // for workqueue metric registration
|
_ "k8s.io/component-base/metrics/prometheus/workqueue" // for workqueue metric registration
|
||||||
"k8s.io/component-base/term"
|
"k8s.io/component-base/term"
|
||||||
"k8s.io/component-base/version"
|
"k8s.io/component-base/version"
|
||||||
@ -114,6 +115,12 @@ cluster's shared state through which all other components interact.`,
|
|||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
verflag.PrintAndExitIfRequested()
|
verflag.PrintAndExitIfRequested()
|
||||||
fs := cmd.Flags()
|
fs := cmd.Flags()
|
||||||
|
|
||||||
|
// Activate logging as soon as possible, after that
|
||||||
|
// show flags with the final logging configuration.
|
||||||
|
if err := s.Logs.ValidateAndApply(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
cliflag.PrintFlags(fs)
|
cliflag.PrintFlags(fs)
|
||||||
|
|
||||||
err := checkNonZeroInsecurePort(fs)
|
err := checkNonZeroInsecurePort(fs)
|
||||||
@ -146,7 +153,7 @@ cluster's shared state through which all other components interact.`,
|
|||||||
fs := cmd.Flags()
|
fs := cmd.Flags()
|
||||||
namedFlagSets := s.Flags()
|
namedFlagSets := s.Flags()
|
||||||
verflag.AddFlags(namedFlagSets.FlagSet("global"))
|
verflag.AddFlags(namedFlagSets.FlagSet("global"))
|
||||||
globalflag.AddGlobalFlags(namedFlagSets.FlagSet("global"), cmd.Name())
|
globalflag.AddGlobalFlags(namedFlagSets.FlagSet("global"), cmd.Name(), logs.SkipLoggingConfigurationFlags())
|
||||||
options.AddCustomGlobalFlags(namedFlagSets.FlagSet("generic"))
|
options.AddCustomGlobalFlags(namedFlagSets.FlagSet("generic"))
|
||||||
for _, f := range namedFlagSets.FlagSets {
|
for _, f := range namedFlagSets.FlagSets {
|
||||||
fs.AddFlagSet(f)
|
fs.AddFlagSet(f)
|
||||||
@ -265,8 +272,6 @@ func CreateKubeAPIServerConfig(s completedServerRunOptions) (
|
|||||||
s.Metrics.Apply()
|
s.Metrics.Apply()
|
||||||
serviceaccount.RegisterMetrics()
|
serviceaccount.RegisterMetrics()
|
||||||
|
|
||||||
s.Logs.Apply()
|
|
||||||
|
|
||||||
config := &controlplane.Config{
|
config := &controlplane.Config{
|
||||||
GenericConfig: genericConfig,
|
GenericConfig: genericConfig,
|
||||||
ExtraConfig: controlplane.ExtraConfig{
|
ExtraConfig: controlplane.ExtraConfig{
|
||||||
|
@ -55,6 +55,7 @@ import (
|
|||||||
cliflag "k8s.io/component-base/cli/flag"
|
cliflag "k8s.io/component-base/cli/flag"
|
||||||
"k8s.io/component-base/cli/globalflag"
|
"k8s.io/component-base/cli/globalflag"
|
||||||
"k8s.io/component-base/configz"
|
"k8s.io/component-base/configz"
|
||||||
|
"k8s.io/component-base/logs"
|
||||||
"k8s.io/component-base/term"
|
"k8s.io/component-base/term"
|
||||||
"k8s.io/component-base/version"
|
"k8s.io/component-base/version"
|
||||||
"k8s.io/component-base/version/verflag"
|
"k8s.io/component-base/version/verflag"
|
||||||
@ -128,6 +129,13 @@ controller, and serviceaccounts controller.`,
|
|||||||
},
|
},
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
verflag.PrintAndExitIfRequested()
|
verflag.PrintAndExitIfRequested()
|
||||||
|
|
||||||
|
// Activate logging as soon as possible, after that
|
||||||
|
// show flags with the final logging configuration.
|
||||||
|
if err := s.Logs.ValidateAndApply(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
cliflag.PrintFlags(cmd.Flags())
|
cliflag.PrintFlags(cmd.Flags())
|
||||||
|
|
||||||
err := checkNonZeroInsecurePort(cmd.Flags())
|
err := checkNonZeroInsecurePort(cmd.Flags())
|
||||||
@ -160,7 +168,7 @@ controller, and serviceaccounts controller.`,
|
|||||||
fs := cmd.Flags()
|
fs := cmd.Flags()
|
||||||
namedFlagSets := s.Flags(KnownControllers(), ControllersDisabledByDefault.List())
|
namedFlagSets := s.Flags(KnownControllers(), ControllersDisabledByDefault.List())
|
||||||
verflag.AddFlags(namedFlagSets.FlagSet("global"))
|
verflag.AddFlags(namedFlagSets.FlagSet("global"))
|
||||||
globalflag.AddGlobalFlags(namedFlagSets.FlagSet("global"), cmd.Name())
|
globalflag.AddGlobalFlags(namedFlagSets.FlagSet("global"), cmd.Name(), logs.SkipLoggingConfigurationFlags())
|
||||||
registerLegacyGlobalFlags(namedFlagSets)
|
registerLegacyGlobalFlags(namedFlagSets)
|
||||||
for _, f := range namedFlagSets.FlagSets {
|
for _, f := range namedFlagSets.FlagSets {
|
||||||
fs.AddFlagSet(f)
|
fs.AddFlagSet(f)
|
||||||
|
@ -415,7 +415,6 @@ func (s *KubeControllerManagerOptions) Validate(allControllers []string, disable
|
|||||||
errs = append(errs, s.Authentication.Validate()...)
|
errs = append(errs, s.Authentication.Validate()...)
|
||||||
errs = append(errs, s.Authorization.Validate()...)
|
errs = append(errs, s.Authorization.Validate()...)
|
||||||
errs = append(errs, s.Metrics.Validate()...)
|
errs = append(errs, s.Metrics.Validate()...)
|
||||||
errs = append(errs, s.Logs.Validate()...)
|
|
||||||
|
|
||||||
// TODO: validate component config, master and kubeconfig
|
// TODO: validate component config, master and kubeconfig
|
||||||
|
|
||||||
@ -459,8 +458,6 @@ func (s KubeControllerManagerOptions) Config(allControllers []string, disabledBy
|
|||||||
}
|
}
|
||||||
s.Metrics.Apply()
|
s.Metrics.Apply()
|
||||||
|
|
||||||
s.Logs.Apply()
|
|
||||||
|
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,7 +231,6 @@ func (o *Options) ApplyTo(c *schedulerappconfig.Config) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
o.Metrics.Apply()
|
o.Metrics.Apply()
|
||||||
o.Logs.Apply()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +246,6 @@ func (o *Options) Validate() []error {
|
|||||||
errs = append(errs, o.Authorization.Validate()...)
|
errs = append(errs, o.Authorization.Validate()...)
|
||||||
errs = append(errs, o.Deprecated.Validate()...)
|
errs = append(errs, o.Deprecated.Validate()...)
|
||||||
errs = append(errs, o.Metrics.Validate()...)
|
errs = append(errs, o.Metrics.Validate()...)
|
||||||
errs = append(errs, o.Logs.Validate()...)
|
|
||||||
|
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ for more information about scheduling and the kube-scheduler component.`,
|
|||||||
|
|
||||||
nfs := opts.Flags
|
nfs := opts.Flags
|
||||||
verflag.AddFlags(nfs.FlagSet("global"))
|
verflag.AddFlags(nfs.FlagSet("global"))
|
||||||
globalflag.AddGlobalFlags(nfs.FlagSet("global"), cmd.Name())
|
globalflag.AddGlobalFlags(nfs.FlagSet("global"), cmd.Name(), logs.SkipLoggingConfigurationFlags())
|
||||||
fs := cmd.Flags()
|
fs := cmd.Flags()
|
||||||
for _, f := range nfs.FlagSets {
|
for _, f := range nfs.FlagSets {
|
||||||
fs.AddFlagSet(f)
|
fs.AddFlagSet(f)
|
||||||
@ -108,6 +108,13 @@ for more information about scheduling and the kube-scheduler component.`,
|
|||||||
// runCommand runs the scheduler.
|
// runCommand runs the scheduler.
|
||||||
func runCommand(cmd *cobra.Command, opts *options.Options, registryOptions ...Option) error {
|
func runCommand(cmd *cobra.Command, opts *options.Options, registryOptions ...Option) error {
|
||||||
verflag.PrintAndExitIfRequested()
|
verflag.PrintAndExitIfRequested()
|
||||||
|
|
||||||
|
// Activate logging as soon as possible, after that
|
||||||
|
// show flags with the final logging configuration.
|
||||||
|
if err := opts.Logs.ValidateAndApply(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
cliflag.PrintFlags(cmd.Flags())
|
cliflag.PrintFlags(cmd.Flags())
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
@ -40,7 +40,7 @@ func AddGlobalFlags(fs *pflag.FlagSet) {
|
|||||||
addCadvisorFlags(fs)
|
addCadvisorFlags(fs)
|
||||||
addCredentialProviderFlags(fs)
|
addCredentialProviderFlags(fs)
|
||||||
verflag.AddFlags(fs)
|
verflag.AddFlags(fs)
|
||||||
logs.AddFlags(fs)
|
logs.AddFlags(fs, logs.SkipLoggingConfigurationFlags())
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalize replaces underscores with hyphens
|
// normalize replaces underscores with hyphens
|
||||||
|
@ -391,7 +391,20 @@ func AddKubeletConfigFlags(mainfs *pflag.FlagSet, c *kubeletconfig.KubeletConfig
|
|||||||
// e.g. if a flag was added after this deprecation function, it may not be at the end
|
// e.g. if a flag was added after this deprecation function, it may not be at the end
|
||||||
// of its lifetime yet, even if the rest are.
|
// of its lifetime yet, even if the rest are.
|
||||||
deprecated := "This parameter should be set via the config file specified by the Kubelet's --config flag. See https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/ for more information."
|
deprecated := "This parameter should be set via the config file specified by the Kubelet's --config flag. See https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/ for more information."
|
||||||
|
// Some flags are permanently (?) meant to be available. In
|
||||||
|
// Kubernetes 1.23, the following options were added to
|
||||||
|
// LoggingConfiguration (long-term goal, more complete
|
||||||
|
// configuration file) but deprecating the flags seemed
|
||||||
|
// premature.
|
||||||
|
notDeprecated := map[string]bool{
|
||||||
|
"v": true,
|
||||||
|
"vmodule": true,
|
||||||
|
"log-flush-frequency": true,
|
||||||
|
}
|
||||||
fs.VisitAll(func(f *pflag.Flag) {
|
fs.VisitAll(func(f *pflag.Flag) {
|
||||||
|
if notDeprecated[f.Name] {
|
||||||
|
return
|
||||||
|
}
|
||||||
f.Deprecated = deprecated
|
f.Deprecated = deprecated
|
||||||
})
|
})
|
||||||
mainfs.AddFlagSet(fs)
|
mainfs.AddFlagSet(fs)
|
||||||
|
@ -261,6 +261,11 @@ HTTP server: The kubelet can also listen for HTTP and respond to a simple API
|
|||||||
|
|
||||||
// Config and flags parsed, now we can initialize logging.
|
// Config and flags parsed, now we can initialize logging.
|
||||||
logs.InitLogs()
|
logs.InitLogs()
|
||||||
|
logOption := &logs.Options{Config: kubeletConfig.Logging}
|
||||||
|
if err := logOption.ValidateAndApply(); err != nil {
|
||||||
|
klog.ErrorS(err, "Failed to initialize logging")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
// construct a KubeletServer from kubeletFlags and kubeletConfig
|
// construct a KubeletServer from kubeletFlags and kubeletConfig
|
||||||
kubeletServer := &options.KubeletServer{
|
kubeletServer := &options.KubeletServer{
|
||||||
@ -437,8 +442,6 @@ func UnsecuredDependencies(s *options.KubeletServer, featureGate featuregate.Fea
|
|||||||
// Otherwise, the caller is assumed to have set up the Dependencies object and a default one will
|
// Otherwise, the caller is assumed to have set up the Dependencies object and a default one will
|
||||||
// not be generated.
|
// not be generated.
|
||||||
func Run(ctx context.Context, s *options.KubeletServer, kubeDeps *kubelet.Dependencies, featureGate featuregate.FeatureGate) error {
|
func Run(ctx context.Context, s *options.KubeletServer, kubeDeps *kubelet.Dependencies, featureGate featuregate.FeatureGate) error {
|
||||||
logOption := &logs.Options{Config: s.Logging}
|
|
||||||
logOption.Apply()
|
|
||||||
// To help debugging, immediately log version
|
// To help debugging, immediately log version
|
||||||
klog.InfoS("Kubelet version", "kubeletVersion", version.Get())
|
klog.InfoS("Kubelet version", "kubeletVersion", version.Get())
|
||||||
if err := initForOS(s.KubeletFlags.WindowsService, s.KubeletFlags.WindowsPriorityClass); err != nil {
|
if err := initForOS(s.KubeletFlags.WindowsService, s.KubeletFlags.WindowsPriorityClass); err != nil {
|
||||||
|
@ -187,6 +187,7 @@ var (
|
|||||||
"HairpinMode",
|
"HairpinMode",
|
||||||
"HealthzBindAddress",
|
"HealthzBindAddress",
|
||||||
"HealthzPort",
|
"HealthzPort",
|
||||||
|
"Logging.FlushFrequency",
|
||||||
"Logging.Format",
|
"Logging.Format",
|
||||||
"Logging.Options.JSON.InfoBufferSize.Quantity.Format",
|
"Logging.Options.JSON.InfoBufferSize.Quantity.Format",
|
||||||
"Logging.Options.JSON.InfoBufferSize.Quantity.d.Dec.scale",
|
"Logging.Options.JSON.InfoBufferSize.Quantity.d.Dec.scale",
|
||||||
@ -197,6 +198,9 @@ var (
|
|||||||
"Logging.Options.JSON.InfoBufferSize.Quantity.s",
|
"Logging.Options.JSON.InfoBufferSize.Quantity.s",
|
||||||
"Logging.Options.JSON.SplitStream",
|
"Logging.Options.JSON.SplitStream",
|
||||||
"Logging.Sanitization",
|
"Logging.Sanitization",
|
||||||
|
"Logging.VModule[*].FilePattern",
|
||||||
|
"Logging.VModule[*].Verbosity",
|
||||||
|
"Logging.Verbosity",
|
||||||
"TLSCipherSuites[*]",
|
"TLSCipherSuites[*]",
|
||||||
"TLSMinVersion",
|
"TLSMinVersion",
|
||||||
"IPTablesDropBit",
|
"IPTablesDropBit",
|
||||||
|
@ -53,10 +53,12 @@ kind: KubeletConfiguration
|
|||||||
kubeAPIBurst: 10
|
kubeAPIBurst: 10
|
||||||
kubeAPIQPS: 5
|
kubeAPIQPS: 5
|
||||||
logging:
|
logging:
|
||||||
|
flushFrequency: 5000000000
|
||||||
format: text
|
format: text
|
||||||
options:
|
options:
|
||||||
json:
|
json:
|
||||||
infoBufferSize: "0"
|
infoBufferSize: "0"
|
||||||
|
verbosity: 0
|
||||||
makeIPTablesUtilChains: true
|
makeIPTablesUtilChains: true
|
||||||
maxOpenFiles: 1000000
|
maxOpenFiles: 1000000
|
||||||
maxPods: 110
|
maxPods: 110
|
||||||
|
@ -53,10 +53,12 @@ kind: KubeletConfiguration
|
|||||||
kubeAPIBurst: 10
|
kubeAPIBurst: 10
|
||||||
kubeAPIQPS: 5
|
kubeAPIQPS: 5
|
||||||
logging:
|
logging:
|
||||||
|
flushFrequency: 5000000000
|
||||||
format: text
|
format: text
|
||||||
options:
|
options:
|
||||||
json:
|
json:
|
||||||
infoBufferSize: "0"
|
infoBufferSize: "0"
|
||||||
|
verbosity: 0
|
||||||
makeIPTablesUtilChains: true
|
makeIPTablesUtilChains: true
|
||||||
maxOpenFiles: 1000000
|
maxOpenFiles: 1000000
|
||||||
maxPods: 110
|
maxPods: 110
|
||||||
|
@ -112,7 +112,8 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
|
|||||||
EnforceNodeAllocatable: DefaultNodeAllocatableEnforcement,
|
EnforceNodeAllocatable: DefaultNodeAllocatableEnforcement,
|
||||||
VolumePluginDir: DefaultVolumePluginDir,
|
VolumePluginDir: DefaultVolumePluginDir,
|
||||||
Logging: componentbaseconfigv1alpha1.LoggingConfiguration{
|
Logging: componentbaseconfigv1alpha1.LoggingConfiguration{
|
||||||
Format: "text",
|
Format: "text",
|
||||||
|
FlushFrequency: 5 * time.Second,
|
||||||
},
|
},
|
||||||
EnableSystemLogHandler: utilpointer.BoolPtr(true),
|
EnableSystemLogHandler: utilpointer.BoolPtr(true),
|
||||||
EnableProfilingHandler: utilpointer.BoolPtr(true),
|
EnableProfilingHandler: utilpointer.BoolPtr(true),
|
||||||
@ -231,8 +232,9 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
|
|||||||
ProviderID: "",
|
ProviderID: "",
|
||||||
KernelMemcgNotification: false,
|
KernelMemcgNotification: false,
|
||||||
Logging: componentbaseconfigv1alpha1.LoggingConfiguration{
|
Logging: componentbaseconfigv1alpha1.LoggingConfiguration{
|
||||||
Format: "",
|
Format: "",
|
||||||
Sanitization: false,
|
FlushFrequency: 5 * time.Second,
|
||||||
|
Sanitization: false,
|
||||||
},
|
},
|
||||||
EnableSystemLogHandler: utilpointer.Bool(false),
|
EnableSystemLogHandler: utilpointer.Bool(false),
|
||||||
ShutdownGracePeriod: zeroDuration,
|
ShutdownGracePeriod: zeroDuration,
|
||||||
@ -327,8 +329,9 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
|
|||||||
AllowedUnsafeSysctls: []string{},
|
AllowedUnsafeSysctls: []string{},
|
||||||
VolumePluginDir: DefaultVolumePluginDir,
|
VolumePluginDir: DefaultVolumePluginDir,
|
||||||
Logging: componentbaseconfigv1alpha1.LoggingConfiguration{
|
Logging: componentbaseconfigv1alpha1.LoggingConfiguration{
|
||||||
Format: "text",
|
Format: "text",
|
||||||
Sanitization: false,
|
FlushFrequency: 5 * time.Second,
|
||||||
|
Sanitization: false,
|
||||||
},
|
},
|
||||||
EnableSystemLogHandler: utilpointer.Bool(false),
|
EnableSystemLogHandler: utilpointer.Bool(false),
|
||||||
ReservedMemory: []v1beta1.MemoryReservation{},
|
ReservedMemory: []v1beta1.MemoryReservation{},
|
||||||
@ -468,8 +471,9 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
|
|||||||
ProviderID: "provider-id",
|
ProviderID: "provider-id",
|
||||||
KernelMemcgNotification: true,
|
KernelMemcgNotification: true,
|
||||||
Logging: componentbaseconfigv1alpha1.LoggingConfiguration{
|
Logging: componentbaseconfigv1alpha1.LoggingConfiguration{
|
||||||
Format: "json",
|
Format: "json",
|
||||||
Sanitization: true,
|
FlushFrequency: 5 * time.Second,
|
||||||
|
Sanitization: true,
|
||||||
},
|
},
|
||||||
EnableSystemLogHandler: utilpointer.Bool(true),
|
EnableSystemLogHandler: utilpointer.Bool(true),
|
||||||
ShutdownGracePeriod: metav1.Duration{Duration: 60 * time.Second},
|
ShutdownGracePeriod: metav1.Duration{Duration: 60 * time.Second},
|
||||||
@ -613,8 +617,9 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
|
|||||||
ProviderID: "provider-id",
|
ProviderID: "provider-id",
|
||||||
KernelMemcgNotification: true,
|
KernelMemcgNotification: true,
|
||||||
Logging: componentbaseconfigv1alpha1.LoggingConfiguration{
|
Logging: componentbaseconfigv1alpha1.LoggingConfiguration{
|
||||||
Format: "json",
|
Format: "json",
|
||||||
Sanitization: true,
|
FlushFrequency: 5 * time.Second,
|
||||||
|
Sanitization: true,
|
||||||
},
|
},
|
||||||
EnableSystemLogHandler: utilpointer.Bool(true),
|
EnableSystemLogHandler: utilpointer.Bool(true),
|
||||||
ShutdownGracePeriod: metav1.Duration{Duration: 60 * time.Second},
|
ShutdownGracePeriod: metav1.Duration{Duration: 60 * time.Second},
|
||||||
@ -706,7 +711,8 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
|
|||||||
EnforceNodeAllocatable: DefaultNodeAllocatableEnforcement,
|
EnforceNodeAllocatable: DefaultNodeAllocatableEnforcement,
|
||||||
VolumePluginDir: DefaultVolumePluginDir,
|
VolumePluginDir: DefaultVolumePluginDir,
|
||||||
Logging: componentbaseconfigv1alpha1.LoggingConfiguration{
|
Logging: componentbaseconfigv1alpha1.LoggingConfiguration{
|
||||||
Format: "text",
|
Format: "text",
|
||||||
|
FlushFrequency: 5 * time.Second,
|
||||||
},
|
},
|
||||||
EnableSystemLogHandler: utilpointer.BoolPtr(true),
|
EnableSystemLogHandler: utilpointer.BoolPtr(true),
|
||||||
EnableProfilingHandler: utilpointer.BoolPtr(true),
|
EnableProfilingHandler: utilpointer.BoolPtr(true),
|
||||||
|
@ -27,8 +27,12 @@ import (
|
|||||||
// AddGlobalFlags explicitly registers flags that libraries (klog, verflag, etc.) register
|
// AddGlobalFlags explicitly registers flags that libraries (klog, verflag, etc.) register
|
||||||
// against the global flagsets from "flag" and "k8s.io/klog/v2".
|
// against the global flagsets from "flag" and "k8s.io/klog/v2".
|
||||||
// We do this in order to prevent unwanted flags from leaking into the component's flagset.
|
// We do this in order to prevent unwanted flags from leaking into the component's flagset.
|
||||||
func AddGlobalFlags(fs *pflag.FlagSet, name string) {
|
//
|
||||||
logs.AddFlags(fs)
|
// k8s.io/component-base/logs.SkipLoggingConfigurationFlags must be used as
|
||||||
|
// option when the program also uses a LoggingConfiguration struct for
|
||||||
|
// configuring logging. Then only flags not covered by that get added.
|
||||||
|
func AddGlobalFlags(fs *pflag.FlagSet, name string, opts ...logs.Option) {
|
||||||
|
logs.AddFlags(fs, opts...)
|
||||||
|
|
||||||
fs.BoolP("help", "h", false, fmt.Sprintf("help for %s", name))
|
fs.BoolP("help", "h", false, fmt.Sprintf("help for %s", name))
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,13 @@ limitations under the License.
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
@ -86,6 +93,17 @@ type LoggingConfiguration struct {
|
|||||||
// Format Flag specifies the structure of log messages.
|
// Format Flag specifies the structure of log messages.
|
||||||
// default value of format is `text`
|
// default value of format is `text`
|
||||||
Format string
|
Format string
|
||||||
|
// Maximum number of seconds 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] When enabled prevents logging of fields tagged as sensitive (passwords, keys, tokens).
|
// [Experimental] When enabled prevents logging of fields tagged as sensitive (passwords, keys, tokens).
|
||||||
// Runtime log sanitization may introduce significant computation overhead and therefore should not be enabled in production.`)
|
// Runtime log sanitization may introduce significant computation overhead and therefore should not be enabled in production.`)
|
||||||
Sanitization bool
|
Sanitization bool
|
||||||
@ -111,3 +129,86 @@ type JSONOptions struct {
|
|||||||
// using split streams. The default is zero, which disables buffering.
|
// using split streams. The default is zero, which disables buffering.
|
||||||
InfoBufferSize resource.QuantityValue
|
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"
|
||||||
|
}
|
||||||
|
119
staging/src/k8s.io/component-base/config/types_test.go
Normal file
119
staging/src/k8s.io/component-base/config/types_test.go
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
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 config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVModule(t *testing.T) {
|
||||||
|
testcases := []struct {
|
||||||
|
arg string
|
||||||
|
expectError string
|
||||||
|
expectValue VModuleConfiguration
|
||||||
|
expectParam string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
arg: "gopher*=1",
|
||||||
|
expectValue: VModuleConfiguration{
|
||||||
|
{
|
||||||
|
FilePattern: "gopher*",
|
||||||
|
Verbosity: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: "foo=1,bar=2",
|
||||||
|
expectValue: VModuleConfiguration{
|
||||||
|
{
|
||||||
|
FilePattern: "foo",
|
||||||
|
Verbosity: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
FilePattern: "bar",
|
||||||
|
Verbosity: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: "foo=1,bar=2,",
|
||||||
|
expectValue: VModuleConfiguration{
|
||||||
|
{
|
||||||
|
FilePattern: "foo",
|
||||||
|
Verbosity: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
FilePattern: "bar",
|
||||||
|
Verbosity: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectParam: "foo=1,bar=2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: "gopher*",
|
||||||
|
expectError: `"gopher*" does not have the pattern=N format`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: "=1",
|
||||||
|
expectError: `"=1" does not have the pattern=N format`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: "foo=-1",
|
||||||
|
expectError: `parsing verbosity in "foo=-1": strconv.ParseUint: parsing "-1": invalid syntax`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: fmt.Sprintf("validint32=%d", math.MaxInt32),
|
||||||
|
expectValue: VModuleConfiguration{
|
||||||
|
{
|
||||||
|
FilePattern: "validint32",
|
||||||
|
Verbosity: math.MaxInt32,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: fmt.Sprintf("invalidint32=%d", math.MaxInt32+1),
|
||||||
|
expectError: `parsing verbosity in "invalidint32=2147483648": strconv.ParseUint: parsing "2147483648": value out of range`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testcases {
|
||||||
|
t.Run(test.arg, func(t *testing.T) {
|
||||||
|
var actual VModuleConfiguration
|
||||||
|
err := actual.Set(test.arg)
|
||||||
|
if test.expectError != "" {
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("parsing should have failed")
|
||||||
|
}
|
||||||
|
assert.Equal(t, test.expectError, err.Error(), "parse error")
|
||||||
|
} else {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
param := actual.String()
|
||||||
|
expectParam := test.expectParam
|
||||||
|
if expectParam == "" {
|
||||||
|
expectParam = test.arg
|
||||||
|
}
|
||||||
|
assert.Equal(t, expectParam, param, "encoded parameter value not identical")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -122,4 +122,7 @@ func RecommendedLoggingConfiguration(obj *LoggingConfiguration) {
|
|||||||
// by reflect.DeepEqual in some tests.
|
// by reflect.DeepEqual in some tests.
|
||||||
_ = obj.Options.JSON.InfoBufferSize.String()
|
_ = obj.Options.JSON.InfoBufferSize.String()
|
||||||
}
|
}
|
||||||
|
if obj.FlushFrequency == 0 {
|
||||||
|
obj.FlushFrequency = 5 * time.Second
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,8 @@ limitations under the License.
|
|||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
@ -88,6 +90,17 @@ type LoggingConfiguration struct {
|
|||||||
// Format Flag specifies the structure of log messages.
|
// Format Flag specifies the structure of log messages.
|
||||||
// default value of format is `text`
|
// default value of format is `text`
|
||||||
Format string `json:"format,omitempty"`
|
Format string `json:"format,omitempty"`
|
||||||
|
// Maximum number of seconds 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] When enabled prevents logging of fields tagged as sensitive (passwords, keys, tokens).
|
// [Experimental] When enabled prevents logging of fields tagged as sensitive (passwords, keys, tokens).
|
||||||
// Runtime log sanitization may introduce significant computation overhead and therefore should not be enabled in production.`)
|
// Runtime log sanitization may introduce significant computation overhead and therefore should not be enabled in production.`)
|
||||||
Sanitization bool `json:"sanitization,omitempty"`
|
Sanitization bool `json:"sanitization,omitempty"`
|
||||||
@ -113,3 +126,20 @@ type JSONOptions struct {
|
|||||||
// using split streams. The default is zero, which disables buffering.
|
// using split streams. The default is zero, which disables buffering.
|
||||||
InfoBufferSize resource.QuantityValue `json:"infoBufferSize,omitempty"`
|
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"`
|
||||||
|
}
|
||||||
|
@ -22,6 +22,9 @@ limitations under the License.
|
|||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
time "time"
|
||||||
|
unsafe "unsafe"
|
||||||
|
|
||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
@ -55,6 +58,16 @@ func RegisterConversions(s *runtime.Scheme) error {
|
|||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
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 {
|
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)
|
return Convert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(a.(*config.ClientConnectionConfiguration), b.(*ClientConnectionConfiguration), scope)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@ -210,6 +223,9 @@ func autoConvert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionCo
|
|||||||
|
|
||||||
func autoConvert_v1alpha1_LoggingConfiguration_To_config_LoggingConfiguration(in *LoggingConfiguration, out *config.LoggingConfiguration, s conversion.Scope) error {
|
func autoConvert_v1alpha1_LoggingConfiguration_To_config_LoggingConfiguration(in *LoggingConfiguration, out *config.LoggingConfiguration, s conversion.Scope) error {
|
||||||
out.Format = in.Format
|
out.Format = in.Format
|
||||||
|
out.FlushFrequency = time.Duration(in.FlushFrequency)
|
||||||
|
out.Verbosity = config.VerbosityLevel(in.Verbosity)
|
||||||
|
out.VModule = *(*config.VModuleConfiguration)(unsafe.Pointer(&in.VModule))
|
||||||
out.Sanitization = in.Sanitization
|
out.Sanitization = in.Sanitization
|
||||||
if err := Convert_v1alpha1_FormatOptions_To_config_FormatOptions(&in.Options, &out.Options, s); err != nil {
|
if err := Convert_v1alpha1_FormatOptions_To_config_FormatOptions(&in.Options, &out.Options, s); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -219,9 +235,34 @@ func autoConvert_v1alpha1_LoggingConfiguration_To_config_LoggingConfiguration(in
|
|||||||
|
|
||||||
func autoConvert_config_LoggingConfiguration_To_v1alpha1_LoggingConfiguration(in *config.LoggingConfiguration, out *LoggingConfiguration, s conversion.Scope) error {
|
func autoConvert_config_LoggingConfiguration_To_v1alpha1_LoggingConfiguration(in *config.LoggingConfiguration, out *LoggingConfiguration, s conversion.Scope) error {
|
||||||
out.Format = in.Format
|
out.Format = in.Format
|
||||||
|
out.FlushFrequency = time.Duration(in.FlushFrequency)
|
||||||
|
out.Verbosity = uint32(in.Verbosity)
|
||||||
|
out.VModule = *(*VModuleConfiguration)(unsafe.Pointer(&in.VModule))
|
||||||
out.Sanitization = in.Sanitization
|
out.Sanitization = in.Sanitization
|
||||||
if err := Convert_config_FormatOptions_To_v1alpha1_FormatOptions(&in.Options, &out.Options, s); err != nil {
|
if err := Convert_config_FormatOptions_To_v1alpha1_FormatOptions(&in.Options, &out.Options, s); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
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)
|
||||||
|
}
|
||||||
|
@ -124,6 +124,11 @@ func (in *LeaderElectionConfiguration) DeepCopy() *LeaderElectionConfiguration {
|
|||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *LoggingConfiguration) DeepCopyInto(out *LoggingConfiguration) {
|
func (in *LoggingConfiguration) DeepCopyInto(out *LoggingConfiguration) {
|
||||||
*out = *in
|
*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)
|
in.Options.DeepCopyInto(&out.Options)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -137,3 +142,39 @@ func (in *LoggingConfiguration) DeepCopy() *LoggingConfiguration {
|
|||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return 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
|
||||||
|
}
|
||||||
|
@ -109,6 +109,11 @@ func (in *LeaderElectionConfiguration) DeepCopy() *LeaderElectionConfiguration {
|
|||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *LoggingConfiguration) DeepCopyInto(out *LoggingConfiguration) {
|
func (in *LoggingConfiguration) DeepCopyInto(out *LoggingConfiguration) {
|
||||||
*out = *in
|
*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)
|
in.Options.DeepCopyInto(&out.Options)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -122,3 +127,39 @@ func (in *LoggingConfiguration) DeepCopy() *LoggingConfiguration {
|
|||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return 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
|
||||||
|
}
|
||||||
|
@ -52,10 +52,12 @@ func init() {
|
|||||||
// List of logs (k8s.io/klog + k8s.io/component-base/logs) flags supported by all logging formats
|
// List of logs (k8s.io/klog + k8s.io/component-base/logs) flags supported by all logging formats
|
||||||
var supportedLogsFlags = map[string]struct{}{
|
var supportedLogsFlags = map[string]struct{}{
|
||||||
"v": {},
|
"v": {},
|
||||||
// TODO: support vmodule after 1.19 Alpha
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BindLoggingFlags binds the Options struct fields to a flagset
|
// BindLoggingFlags binds the Options struct fields to a flagset.
|
||||||
|
//
|
||||||
|
// Programs using LoggingConfiguration must use SkipLoggingConfigurationFlags
|
||||||
|
// when calling AddFlags to avoid the duplicate registration of flags.
|
||||||
func BindLoggingFlags(c *config.LoggingConfiguration, fs *pflag.FlagSet) {
|
func BindLoggingFlags(c *config.LoggingConfiguration, fs *pflag.FlagSet) {
|
||||||
// The help text is generated assuming that flags will eventually use
|
// The help text is generated assuming that flags will eventually use
|
||||||
// hyphens, even if currently no normalization function is set for the
|
// hyphens, even if currently no normalization function is set for the
|
||||||
@ -65,6 +67,10 @@ func BindLoggingFlags(c *config.LoggingConfiguration, fs *pflag.FlagSet) {
|
|||||||
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))
|
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
|
// No new log formats should be added after generation is of flag options
|
||||||
registry.LogRegistry.Freeze()
|
registry.LogRegistry.Freeze()
|
||||||
|
|
||||||
|
fs.DurationVar(&c.FlushFrequency, logFlushFreqFlagName, logFlushFreq, "Maximum number of seconds between log flushes")
|
||||||
|
fs.VarP(&c.Verbosity, "v", "v", "number for the log level verbosity")
|
||||||
|
fs.Var(&c.VModule, "vmodule", "comma-separated list of pattern=N settings for file-filtered logging (only works for text log format)")
|
||||||
fs.BoolVar(&c.Sanitization, "experimental-logging-sanitization", c.Sanitization, `[Experimental] When enabled prevents logging of fields tagged as sensitive (passwords, keys, tokens).
|
fs.BoolVar(&c.Sanitization, "experimental-logging-sanitization", c.Sanitization, `[Experimental] When enabled prevents logging of fields tagged as sensitive (passwords, keys, tokens).
|
||||||
Runtime log sanitization may introduce significant computation overhead and therefore should not be enabled in production.`)
|
Runtime log sanitization may introduce significant computation overhead and therefore should not be enabled in production.`)
|
||||||
|
|
||||||
|
@ -40,12 +40,10 @@ func NewLoggerCommand() *cobra.Command {
|
|||||||
o := logs.NewOptions()
|
o := logs.NewOptions()
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
errs := o.Validate()
|
if err := o.ValidateAndApply(); err != nil {
|
||||||
if len(errs) != 0 {
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||||
fmt.Fprintf(os.Stderr, "%v\n", errs)
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
o.Apply()
|
|
||||||
runLogger()
|
runLogger()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,7 @@ import (
|
|||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
"k8s.io/component-base/config"
|
|
||||||
"k8s.io/component-base/logs"
|
"k8s.io/component-base/logs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -43,14 +41,7 @@ func TestJSONFlag(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestJSONFormatRegister(t *testing.T) {
|
func TestJSONFormatRegister(t *testing.T) {
|
||||||
defaultOptions := config.FormatOptions{
|
newOptions := logs.NewOptions()
|
||||||
JSON: config.JSONOptions{
|
|
||||||
InfoBufferSize: resource.QuantityValue{
|
|
||||||
Quantity: *resource.NewQuantity(0, resource.DecimalSI),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_ = defaultOptions.JSON.InfoBufferSize.String()
|
|
||||||
testcases := []struct {
|
testcases := []struct {
|
||||||
name string
|
name string
|
||||||
args []string
|
args []string
|
||||||
@ -60,22 +51,20 @@ func TestJSONFormatRegister(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "JSON log format",
|
name: "JSON log format",
|
||||||
args: []string{"--logging-format=json"},
|
args: []string{"--logging-format=json"},
|
||||||
want: &logs.Options{
|
want: func() *logs.Options {
|
||||||
Config: config.LoggingConfiguration{
|
c := newOptions.Config.DeepCopy()
|
||||||
Format: logs.JSONLogFormat,
|
c.Format = logs.JSONLogFormat
|
||||||
Options: defaultOptions,
|
return &logs.Options{*c}
|
||||||
},
|
}(),
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Unsupported log format",
|
name: "Unsupported log format",
|
||||||
args: []string{"--logging-format=test"},
|
args: []string{"--logging-format=test"},
|
||||||
want: &logs.Options{
|
want: func() *logs.Options {
|
||||||
Config: config.LoggingConfiguration{
|
c := newOptions.Config.DeepCopy()
|
||||||
Format: "test",
|
c.Format = "test"
|
||||||
Options: defaultOptions,
|
return &logs.Options{*c}
|
||||||
},
|
}(),
|
||||||
},
|
|
||||||
errs: field.ErrorList{&field.Error{
|
errs: field.ErrorList{&field.Error{
|
||||||
Type: "FieldValueInvalid",
|
Type: "FieldValueInvalid",
|
||||||
Field: "format",
|
Field: "format",
|
||||||
@ -94,7 +83,7 @@ func TestJSONFormatRegister(t *testing.T) {
|
|||||||
if !assert.Equal(t, tc.want, o) {
|
if !assert.Equal(t, tc.want, o) {
|
||||||
t.Errorf("Wrong Validate() result for %q. expect %v, got %v", tc.name, tc.want, o)
|
t.Errorf("Wrong Validate() result for %q. expect %v, got %v", tc.name, tc.want, o)
|
||||||
}
|
}
|
||||||
errs := o.Validate()
|
errs := o.ValidateAndApply()
|
||||||
if !assert.ElementsMatch(t, tc.errs, errs) {
|
if !assert.ElementsMatch(t, tc.errs, errs) {
|
||||||
t.Errorf("Wrong Validate() result for %q.\n expect:\t%+v\n got:\t%+v", tc.name, tc.errs, errs)
|
t.Errorf("Wrong Validate() result for %q.\n expect:\t%+v\n got:\t%+v", tc.name, tc.errs, errs)
|
||||||
|
|
||||||
|
@ -41,8 +41,12 @@ const deprecated = "will be removed in a future release, see https://github.com/
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
packageFlags = flag.NewFlagSet("logging", flag.ContinueOnError)
|
packageFlags = flag.NewFlagSet("logging", flag.ContinueOnError)
|
||||||
logFlushFreq time.Duration
|
|
||||||
logrFlush func()
|
logrFlush func()
|
||||||
|
|
||||||
|
// Periodic flushing gets configured either via the global flag
|
||||||
|
// in this file or via LoggingConfiguration.
|
||||||
|
logFlushFreq time.Duration
|
||||||
|
logFlushFreqAdded bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -50,6 +54,21 @@ func init() {
|
|||||||
packageFlags.DurationVar(&logFlushFreq, logFlushFreqFlagName, 5*time.Second, "Maximum number of seconds between log flushes")
|
packageFlags.DurationVar(&logFlushFreq, logFlushFreqFlagName, 5*time.Second, "Maximum number of seconds between log flushes")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type addFlagsOptions struct {
|
||||||
|
skipLoggingConfigurationFlags bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option func(*addFlagsOptions)
|
||||||
|
|
||||||
|
// SkipLoggingConfigurationFlags must be used as option for AddFlags when
|
||||||
|
// the program also uses a LoggingConfiguration struct for configuring
|
||||||
|
// logging. Then only flags not covered by that get added.
|
||||||
|
func SkipLoggingConfigurationFlags() Option {
|
||||||
|
return func(o *addFlagsOptions) {
|
||||||
|
o.skipLoggingConfigurationFlags = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AddFlags registers this package's flags on arbitrary FlagSets. This includes
|
// AddFlags registers this package's flags on arbitrary FlagSets. This includes
|
||||||
// the klog flags, with the original underscore as separator between. If
|
// the klog flags, with the original underscore as separator between. If
|
||||||
// commands want hyphens as separators, they can set
|
// commands want hyphens as separators, they can set
|
||||||
@ -57,22 +76,39 @@ func init() {
|
|||||||
// function on the flag set before calling AddFlags.
|
// function on the flag set before calling AddFlags.
|
||||||
//
|
//
|
||||||
// May be called more than once.
|
// May be called more than once.
|
||||||
func AddFlags(fs *pflag.FlagSet) {
|
func AddFlags(fs *pflag.FlagSet, opts ...Option) {
|
||||||
// Determine whether the flags are already present by looking up one
|
// Determine whether the flags are already present by looking up one
|
||||||
// which always should exist.
|
// which always should exist.
|
||||||
if f := fs.Lookup("v"); f != nil {
|
if fs.Lookup("logtostderr") != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
o := addFlagsOptions{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&o)
|
||||||
|
}
|
||||||
|
|
||||||
// Add flags with pflag deprecation remark for some klog flags.
|
// Add flags with pflag deprecation remark for some klog flags.
|
||||||
packageFlags.VisitAll(func(f *flag.Flag) {
|
packageFlags.VisitAll(func(f *flag.Flag) {
|
||||||
pf := pflag.PFlagFromGoFlag(f)
|
pf := pflag.PFlagFromGoFlag(f)
|
||||||
switch f.Name {
|
switch f.Name {
|
||||||
case "v", logFlushFreqFlagName:
|
case "v":
|
||||||
// unchanged
|
// unchanged, potentially skip it
|
||||||
|
if o.skipLoggingConfigurationFlags {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case logFlushFreqFlagName:
|
||||||
|
// unchanged, potentially skip it
|
||||||
|
if o.skipLoggingConfigurationFlags {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logFlushFreqAdded = true
|
||||||
case "vmodule":
|
case "vmodule":
|
||||||
// TODO: see above
|
// TODO: see above
|
||||||
// pf.Usage += vmoduleUsage
|
// pf.Usage += vmoduleUsage
|
||||||
|
if o.skipLoggingConfigurationFlags {
|
||||||
|
return
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// deprecated, but not hidden
|
// deprecated, but not hidden
|
||||||
pf.Deprecated = deprecated
|
pf.Deprecated = deprecated
|
||||||
@ -87,17 +123,34 @@ func AddFlags(fs *pflag.FlagSet) {
|
|||||||
// in flag.CommandLine) and commands that for historic reasons use Go
|
// in flag.CommandLine) and commands that for historic reasons use Go
|
||||||
// flag.Parse and cannot change to pflag because it would break their command
|
// flag.Parse and cannot change to pflag because it would break their command
|
||||||
// line interface.
|
// line interface.
|
||||||
func AddGoFlags(fs *flag.FlagSet) {
|
func AddGoFlags(fs *flag.FlagSet, opts ...Option) {
|
||||||
|
o := addFlagsOptions{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&o)
|
||||||
|
}
|
||||||
|
|
||||||
// Add flags with deprecation remark added to the usage text of
|
// Add flags with deprecation remark added to the usage text of
|
||||||
// some klog flags.
|
// some klog flags.
|
||||||
packageFlags.VisitAll(func(f *flag.Flag) {
|
packageFlags.VisitAll(func(f *flag.Flag) {
|
||||||
usage := f.Usage
|
usage := f.Usage
|
||||||
switch f.Name {
|
switch f.Name {
|
||||||
case "v", logFlushFreqFlagName:
|
case "v":
|
||||||
// unchanged
|
// unchanged
|
||||||
|
if o.skipLoggingConfigurationFlags {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case logFlushFreqFlagName:
|
||||||
|
// unchanged
|
||||||
|
if o.skipLoggingConfigurationFlags {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logFlushFreqAdded = true
|
||||||
case "vmodule":
|
case "vmodule":
|
||||||
// TODO: see above
|
// TODO: see above
|
||||||
// usage += vmoduleUsage
|
// usage += vmoduleUsage
|
||||||
|
if o.skipLoggingConfigurationFlags {
|
||||||
|
return
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
usage += " (DEPRECATED: " + deprecated + ")"
|
usage += " (DEPRECATED: " + deprecated + ")"
|
||||||
}
|
}
|
||||||
@ -120,8 +173,11 @@ func (writer KlogWriter) Write(data []byte) (n int, err error) {
|
|||||||
func InitLogs() {
|
func InitLogs() {
|
||||||
log.SetOutput(KlogWriter{})
|
log.SetOutput(KlogWriter{})
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
// The default klog flush interval is 5 seconds.
|
if logFlushFreqAdded {
|
||||||
go wait.Forever(klog.Flush, logFlushFreq)
|
// The flag from this file was activated, so use it now.
|
||||||
|
// Otherwise LoggingConfiguration.Apply will do this.
|
||||||
|
go wait.Forever(FlushLogs, logFlushFreq)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlushLogs flushes logs immediately. This should be called at the end of
|
// FlushLogs flushes logs immediately. This should be called at the end of
|
||||||
|
@ -17,14 +17,17 @@ limitations under the License.
|
|||||||
package logs
|
package logs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
|
|
||||||
"k8s.io/klog/v2"
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/component-base/config"
|
"k8s.io/component-base/config"
|
||||||
"k8s.io/component-base/config/v1alpha1"
|
"k8s.io/component-base/config/v1alpha1"
|
||||||
"k8s.io/component-base/logs/registry"
|
"k8s.io/component-base/logs/registry"
|
||||||
"k8s.io/component-base/logs/sanitization"
|
"k8s.io/component-base/logs/sanitization"
|
||||||
|
"k8s.io/klog/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options has klog format parameters
|
// Options has klog format parameters
|
||||||
@ -41,9 +44,22 @@ func NewOptions() *Options {
|
|||||||
return o
|
return o
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate verifies if any unsupported flag is set
|
// 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.
|
||||||
|
func (o *Options) ValidateAndApply() error {
|
||||||
|
errs := o.validate()
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return utilerrors.NewAggregate(errs)
|
||||||
|
}
|
||||||
|
o.apply()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate verifies if any unsupported flag is set
|
||||||
// for non-default logging format
|
// for non-default logging format
|
||||||
func (o *Options) Validate() []error {
|
func (o *Options) validate() []error {
|
||||||
errs := ValidateLoggingConfiguration(&o.Config, nil)
|
errs := ValidateLoggingConfiguration(&o.Config, nil)
|
||||||
if len(errs) != 0 {
|
if len(errs) != 0 {
|
||||||
return errs.ToAggregate().Errors()
|
return errs.ToAggregate().Errors()
|
||||||
@ -51,13 +67,16 @@ func (o *Options) Validate() []error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddFlags add logging-format flag
|
// AddFlags add logging-format flag.
|
||||||
|
//
|
||||||
|
// Programs using LoggingConfiguration must use SkipLoggingConfigurationFlags
|
||||||
|
// when calling AddFlags to avoid the duplicate registration of flags.
|
||||||
func (o *Options) AddFlags(fs *pflag.FlagSet) {
|
func (o *Options) AddFlags(fs *pflag.FlagSet) {
|
||||||
BindLoggingFlags(&o.Config, fs)
|
BindLoggingFlags(&o.Config, fs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply set klog logger from LogFormat type
|
// apply set klog logger from LogFormat type
|
||||||
func (o *Options) Apply() {
|
func (o *Options) apply() {
|
||||||
// if log format not exists, use nil loggr
|
// if log format not exists, use nil loggr
|
||||||
factory, _ := registry.LogRegistry.Get(o.Config.Format)
|
factory, _ := registry.LogRegistry.Get(o.Config.Format)
|
||||||
if factory == nil {
|
if factory == nil {
|
||||||
@ -70,4 +89,11 @@ func (o *Options) Apply() {
|
|||||||
if o.Config.Sanitization {
|
if o.Config.Sanitization {
|
||||||
klog.SetLogFilter(&sanitization.SanitizingFilter{})
|
klog.SetLogFilter(&sanitization.SanitizingFilter{})
|
||||||
}
|
}
|
||||||
|
if err := loggingFlags.Lookup("v").Value.Set(o.Config.Verbosity.String()); err != nil {
|
||||||
|
panic(fmt.Errorf("internal error while setting klog verbosity: %v", err))
|
||||||
|
}
|
||||||
|
if err := loggingFlags.Lookup("vmodule").Value.Set(o.Config.VModule.String()); err != nil {
|
||||||
|
panic(fmt.Errorf("internal error while setting klog vmodule: %v", err))
|
||||||
|
}
|
||||||
|
go wait.Forever(FlushLogs, o.Config.FlushFrequency)
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
"k8s.io/component-base/config"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFlags(t *testing.T) {
|
func TestFlags(t *testing.T) {
|
||||||
@ -36,9 +35,12 @@ func TestFlags(t *testing.T) {
|
|||||||
fs.PrintDefaults()
|
fs.PrintDefaults()
|
||||||
want := ` --experimental-logging-sanitization [Experimental] When enabled prevents logging of fields tagged as sensitive (passwords, keys, tokens).
|
want := ` --experimental-logging-sanitization [Experimental] When enabled prevents logging of fields tagged as sensitive (passwords, keys, tokens).
|
||||||
Runtime log sanitization may introduce significant computation overhead and therefore should not be enabled in production.
|
Runtime log sanitization may introduce significant computation overhead and therefore should not be enabled in production.
|
||||||
|
--log-flush-frequency duration Maximum number of seconds between log flushes (default 5s)
|
||||||
--logging-format string Sets the log format. Permitted formats: "text".
|
--logging-format string Sets the log format. Permitted formats: "text".
|
||||||
Non-default formats don't honor these flags: --add-dir-header, --alsologtostderr, --log-backtrace-at, --log-dir, --log-file, --log-file-max-size, --logtostderr, --one-output, --skip-headers, --skip-log-headers, --stderrthreshold, --vmodule.
|
Non-default formats don't honor these flags: --add-dir-header, --alsologtostderr, --log-backtrace-at, --log-dir, --log-file, --log-file-max-size, --logtostderr, --one-output, --skip-headers, --skip-log-headers, --stderrthreshold, --vmodule.
|
||||||
Non-default choices are currently alpha and subject to change without warning. (default "text")
|
Non-default choices are currently alpha and subject to change without warning. (default "text")
|
||||||
|
-v, --v Level number for the log level verbosity
|
||||||
|
--vmodule pattern=N,... comma-separated list of pattern=N settings for file-filtered logging (only works for text log format)
|
||||||
`
|
`
|
||||||
if !assert.Equal(t, want, output.String()) {
|
if !assert.Equal(t, want, output.String()) {
|
||||||
t.Errorf("Wrong list of flags. expect %q, got %q", want, output.String())
|
t.Errorf("Wrong list of flags. expect %q, got %q", want, output.String())
|
||||||
@ -46,6 +48,7 @@ func TestFlags(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestOptions(t *testing.T) {
|
func TestOptions(t *testing.T) {
|
||||||
|
newOptions := NewOptions()
|
||||||
testcases := []struct {
|
testcases := []struct {
|
||||||
name string
|
name string
|
||||||
args []string
|
args []string
|
||||||
@ -54,33 +57,30 @@ func TestOptions(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Default log format",
|
name: "Default log format",
|
||||||
want: NewOptions(),
|
want: newOptions,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Text log format",
|
name: "Text log format",
|
||||||
args: []string{"--logging-format=text"},
|
args: []string{"--logging-format=text"},
|
||||||
want: NewOptions(),
|
want: newOptions,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "log sanitization",
|
name: "log sanitization",
|
||||||
args: []string{"--experimental-logging-sanitization"},
|
args: []string{"--experimental-logging-sanitization"},
|
||||||
want: &Options{
|
want: func() *Options {
|
||||||
Config: config.LoggingConfiguration{
|
c := newOptions.Config.DeepCopy()
|
||||||
Format: DefaultLogFormat,
|
c.Sanitization = true
|
||||||
Sanitization: true,
|
return &Options{*c}
|
||||||
Options: NewOptions().Config.Options,
|
}(),
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Unsupported log format",
|
name: "Unsupported log format",
|
||||||
args: []string{"--logging-format=test"},
|
args: []string{"--logging-format=test"},
|
||||||
want: &Options{
|
want: func() *Options {
|
||||||
Config: config.LoggingConfiguration{
|
c := newOptions.Config.DeepCopy()
|
||||||
Format: "test",
|
c.Format = "test"
|
||||||
Options: NewOptions().Config.Options,
|
return &Options{*c}
|
||||||
},
|
}(),
|
||||||
},
|
|
||||||
errs: field.ErrorList{&field.Error{
|
errs: field.ErrorList{&field.Error{
|
||||||
Type: "FieldValueInvalid",
|
Type: "FieldValueInvalid",
|
||||||
Field: "format",
|
Field: "format",
|
||||||
@ -99,9 +99,10 @@ func TestOptions(t *testing.T) {
|
|||||||
if !assert.Equal(t, tc.want, o) {
|
if !assert.Equal(t, tc.want, o) {
|
||||||
t.Errorf("Wrong Validate() result for %q. expect %v, got %v", tc.name, tc.want, o)
|
t.Errorf("Wrong Validate() result for %q. expect %v, got %v", tc.name, tc.want, o)
|
||||||
}
|
}
|
||||||
errs := o.Validate()
|
err := o.ValidateAndApply()
|
||||||
if !assert.ElementsMatch(t, tc.errs, errs) {
|
|
||||||
t.Errorf("Wrong Validate() result for %q.\n expect:\t%+v\n got:\t%+v", tc.name, tc.errs, errs)
|
if !assert.ElementsMatch(t, tc.errs.ToAggregate(), err) {
|
||||||
|
t.Errorf("Wrong Validate() result for %q.\n expect:\t%+v\n got:\t%+v", tc.name, tc.errs, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -18,6 +18,8 @@ package logs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
cliflag "k8s.io/component-base/cli/flag"
|
cliflag "k8s.io/component-base/cli/flag"
|
||||||
@ -42,6 +44,26 @@ func ValidateLoggingConfiguration(c *config.LoggingConfiguration, fldPath *field
|
|||||||
errs = append(errs, field.Invalid(fldPath.Child("format"), c.Format, "Unsupported log format"))
|
errs = append(errs, field.Invalid(fldPath.Child("format"), c.Format, "Unsupported log format"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Currently nothing to validate for c.Options.
|
// Currently nothing to validate for c.Options.
|
||||||
|
|
||||||
return errs
|
return errs
|
||||||
|
124
staging/src/k8s.io/component-base/logs/validate_test.go
Normal file
124
staging/src/k8s.io/component-base/logs/validate_test.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
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 logs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"k8s.io/component-base/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestValidateLoggingConfiguration(t *testing.T) {
|
||||||
|
testcases := map[string]struct {
|
||||||
|
config config.LoggingConfiguration
|
||||||
|
expectErrors string
|
||||||
|
}{
|
||||||
|
"okay": {
|
||||||
|
config: config.LoggingConfiguration{
|
||||||
|
Format: "text",
|
||||||
|
Verbosity: 10,
|
||||||
|
VModule: config.VModuleConfiguration{
|
||||||
|
{
|
||||||
|
FilePattern: "gopher*",
|
||||||
|
Verbosity: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"wrong-format": {
|
||||||
|
config: config.LoggingConfiguration{
|
||||||
|
Format: "no-such-format",
|
||||||
|
},
|
||||||
|
expectErrors: `format: Invalid value: "no-such-format": Unsupported log format`,
|
||||||
|
},
|
||||||
|
"verbosity-overflow": {
|
||||||
|
config: config.LoggingConfiguration{
|
||||||
|
Format: "text",
|
||||||
|
Verbosity: math.MaxInt32 + 1,
|
||||||
|
},
|
||||||
|
expectErrors: `verbosity: Invalid value: 0x80000000: Must be <= 2147483647`,
|
||||||
|
},
|
||||||
|
"vmodule-verbosity-overflow": {
|
||||||
|
config: config.LoggingConfiguration{
|
||||||
|
Format: "text",
|
||||||
|
VModule: config.VModuleConfiguration{
|
||||||
|
{
|
||||||
|
FilePattern: "gopher*",
|
||||||
|
Verbosity: math.MaxInt32 + 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectErrors: `vmodule[0]: Invalid value: 0x80000000: Must be <= 2147483647`,
|
||||||
|
},
|
||||||
|
"vmodule-empty-pattern": {
|
||||||
|
config: config.LoggingConfiguration{
|
||||||
|
Format: "text",
|
||||||
|
VModule: config.VModuleConfiguration{
|
||||||
|
{
|
||||||
|
FilePattern: "",
|
||||||
|
Verbosity: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectErrors: `vmodule[0]: Required value: File pattern must not be empty`,
|
||||||
|
},
|
||||||
|
"vmodule-pattern-with-special-characters": {
|
||||||
|
config: config.LoggingConfiguration{
|
||||||
|
Format: "text",
|
||||||
|
VModule: config.VModuleConfiguration{
|
||||||
|
{
|
||||||
|
FilePattern: "foo,bar",
|
||||||
|
Verbosity: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
FilePattern: "foo=bar",
|
||||||
|
Verbosity: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectErrors: `[vmodule[0]: Invalid value: "foo,bar": File pattern must not contain equal sign or comma, vmodule[1]: Invalid value: "foo=bar": File pattern must not contain equal sign or comma]`,
|
||||||
|
},
|
||||||
|
"vmodule-unsupported": {
|
||||||
|
config: config.LoggingConfiguration{
|
||||||
|
Format: "json",
|
||||||
|
VModule: config.VModuleConfiguration{
|
||||||
|
{
|
||||||
|
FilePattern: "foo",
|
||||||
|
Verbosity: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectErrors: `[format: Invalid value: "json": Unsupported log format, vmodule: Forbidden: Only supported for text log format]`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, test := range testcases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
errs := ValidateLoggingConfiguration(&test.config, nil)
|
||||||
|
if len(errs) == 0 {
|
||||||
|
if test.expectErrors != "" {
|
||||||
|
t.Fatalf("did not get expected error(s): %s", test.expectErrors)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, test.expectErrors, errs.ToAggregate().Error())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user