Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: component-base logs: update klog verbosity also at runtime #124312

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 12 additions & 4 deletions staging/src/k8s.io/component-base/logs/api/v1/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,10 +276,10 @@ func apply(c *LoggingConfiguration, options *LoggingOptions, featureGate feature
}
klog.SetLoggerWithOptions(log, opts...)
}
if err := loggingFlags.Lookup("v").Value.Set(VerbosityLevelPflag(&c.Verbosity).String()); err != nil {
if err := loggingFlags.Lookup("v").Value.Set(VerbosityLevelPflag(&c.Verbosity, nil).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 {
if err := loggingFlags.Lookup("vmodule").Value.Set(VModuleConfigurationPflag(&c.VModule, nil).String()); err != nil {
return fmt.Errorf("internal error while setting klog vmodule: %v", err)
}
klog.StartFlushDaemon(c.FlushFrequency.Duration.Duration)
Expand Down Expand Up @@ -363,8 +363,8 @@ func addFlags(c *LoggingConfiguration, fs flagSet) {
logRegistry.freeze()

fs.DurationVar(&c.FlushFrequency.Duration.Duration, LogFlushFreqFlagName, c.FlushFrequency.Duration.Duration, "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)")
fs.VarP(VerbosityLevelPflag(&c.Verbosity, lookupValue(&loggingFlags, "v")), "v", "v", "number for the log level verbosity")
fs.Var(VModuleConfigurationPflag(&c.VModule, lookupValue(&loggingFlags, "vmodule")), "vmodule", "comma-separated list of pattern=N settings for file-filtered logging (only works for text log format)")

fs.BoolVar(&c.Options.Text.SplitStream, "log-text-split-stream", false, "[Alpha] In text 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.Text.InfoBufferSize, "log-text-info-buffer-size", "[Alpha] In text 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.")
Expand All @@ -377,6 +377,14 @@ func addFlags(c *LoggingConfiguration, fs flagSet) {
}
}

func lookupValue(fs *pflag.FlagSet, flagName string) pflag.Value {
f := fs.Lookup(flagName)
if f == nil {
return nil
}
return f.Value
}

// SetRecommendedLoggingConfiguration sets the default logging configuration
// for fields that are unset.
//
Expand Down
99 changes: 55 additions & 44 deletions staging/src/k8s.io/component-base/logs/api/v1/pflags.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package v1

import (
"flag"
"fmt"
"strconv"
"strings"
Expand All @@ -26,88 +27,98 @@ import (

// 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}
func VModuleConfigurationPflag(value *VModuleConfiguration, parentValue flag.Value) pflag.Value {
return &vmoduleConfigurationPFlag{value: value, parentValue: parentValue}
}

type vmoduleConfigurationPFlag struct {
value *VModuleConfiguration
value *VModuleConfiguration
parentValue flag.Value
}

// String returns the -vmodule parameter (comma-separated list of pattern=N).
func (wrapper vmoduleConfigurationPFlag) String() string {
if wrapper.value == nil {
return ""
func (wrapper *vmoduleConfigurationPFlag) String() string {
if wrapper.value != nil {
var patterns []string
for _, item := range *wrapper.value {
patterns = append(patterns, fmt.Sprintf("%s=%d", item.FilePattern, item.Verbosity))
}
return strings.Join(patterns, ",")
}
var patterns []string
for _, item := range *wrapper.value {
patterns = append(patterns, fmt.Sprintf("%s=%d", item.FilePattern, item.Verbosity))
if wrapper.parentValue != nil {
return wrapper.parentValue.String()
}
return strings.Join(patterns, ",")
return ""
}

// 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)
func (wrapper *vmoduleConfigurationPFlag) Set(value string) error {
if wrapper.value != nil {
// 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)})
}
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)})
}
if wrapper.parentValue != nil {
return wrapper.parentValue.Set(value)
}
return nil
}

func (wrapper vmoduleConfigurationPFlag) Type() string {
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}
func VerbosityLevelPflag(value *VerbosityLevel, parentValue pflag.Value) pflag.Value {
return &verbosityLevelPflag{value: value, parentValue: parentValue}
}

type verbosityLevelPflag struct {
value *VerbosityLevel
value *VerbosityLevel
parentValue pflag.Value
}

func (wrapper verbosityLevelPflag) String() string {
if wrapper.value == nil {
return "0"
func (wrapper *verbosityLevelPflag) String() string {
if wrapper.value != nil {
return strconv.FormatInt(int64(*wrapper.value), 10)
}
return strconv.FormatInt(int64(*wrapper.value), 10)
}

func (wrapper verbosityLevelPflag) Get() interface{} {
if wrapper.value == nil {
return VerbosityLevel(0)
if wrapper.parentValue != nil {
return wrapper.parentValue.String()
}
return *wrapper.value
return "0"

}

func (wrapper verbosityLevelPflag) Set(value string) error {
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)
if wrapper.parentValue != nil {
return wrapper.parentValue.Set(value)
}
return nil
}

func (wrapper verbosityLevelPflag) Type() string {
func (wrapper *verbosityLevelPflag) Type() string {
return "Level"
}
2 changes: 1 addition & 1 deletion staging/src/k8s.io/component-base/logs/api/v1/text.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (f textFactory) Create(c LoggingConfiguration, o LoggingOptions) (logr.Logg
loggerConfig := textlogger.NewConfig(options...)

// This should never fail, we produce a valid string here.
_ = loggerConfig.VModule().Set(VModuleConfigurationPflag(&c.VModule).String())
_ = loggerConfig.VModule().Set(VModuleConfigurationPflag(&c.VModule, nil).String())

return textlogger.NewLogger(loggerConfig),
RuntimeControl{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func TestVModule(t *testing.T) {
for _, test := range testcases {
t.Run(test.arg, func(t *testing.T) {
var actual VModuleConfiguration
value := VModuleConfigurationPflag(&actual)
value := VModuleConfigurationPflag(&actual, nil)
err := value.Set(test.arg)
if test.expectError != "" {
if err == nil {
Expand Down