initialize logging after flag parsing

It wasn't documented that InitLogs already uses the log flush frequency, so
some commands have called it before parsing (for example, kubectl in the
original code for logs.go). The flag never had an effect in such commands.

Fixing this turned into a major refactoring of how commands set up flags and
run their Cobra command:

- component-base/logs: implicitely registering flags during package init is an
  anti-pattern that makes it impossible to use the package in commands which
  want full control over their command line. Logging flags must be added
  explicitly now, something that the new cli.Run does automatically.

- component-base/logs: AddFlags would have crashed in kubectl-convert if it
  had been called because it relied on the global pflag.CommandLine. This
  has been fixed and kubectl-convert now has the same --log-flush-frequency
  flag as other commands.

- component-base/logs/testinit: an exception are tests where flag.CommandLine has
  to be used. This new package can be imported to add flags to that
  once per test program.

- Normalization of the klog command line flags was inconsistent. Some commands
  unintentionally didn't normalize to the recommended format with hyphens. This
  gets fixed for sample programs, but not for production programs because
  it would be a breaking change.

This refactoring has the following user-visible effects:

- The validation error for `go run ./cmd/kube-apiserver --logging-format=json
  --add-dir-header` now references `add-dir-header` instead of `add_dir_header`.

- `staging/src/k8s.io/cloud-provider/sample` uses flags with hyphen instead of
  underscore.

- `--log-flush-frequency` is not listed anymore in the --logging-format flag's
  `non-default formats don't honor these flags` usage text because it will also
  work for non-default formats once it is needed.

- `cmd/kubelet`: the description of `--logging-format` uses hyphens instead of
  underscores for the flags, which now matches what the command is using.

- `staging/src/k8s.io/component-base/logs/example/cmd`: added logging flags.

- `apiextensions-apiserver` no longer prints a useless stack trace for `main`
  when command line parsing raises an error.
This commit is contained in:
Patrick Ohly 2021-09-16 18:18:35 +02:00
parent c9c4357c03
commit 21d1bcd6b8
42 changed files with 270 additions and 386 deletions

View File

@ -25,9 +25,7 @@ limitations under the License.
package main
import (
"math/rand"
"os"
"time"
"github.com/spf13/pflag"
@ -36,8 +34,8 @@ import (
"k8s.io/cloud-provider/app"
cloudcontrollerconfig "k8s.io/cloud-provider/app/config"
"k8s.io/cloud-provider/options"
"k8s.io/component-base/cli"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/logs"
_ "k8s.io/component-base/metrics/prometheus/clientgo" // load all the prometheus client-go plugins
_ "k8s.io/component-base/metrics/prometheus/version" // for version metric registration
"k8s.io/klog/v2"
@ -46,8 +44,6 @@ import (
)
func main() {
rand.Seed(time.Now().UnixNano())
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
ccmOptions, err := options.NewCloudControllerManagerOptions()
@ -79,13 +75,8 @@ func main() {
}
command := app.NewCloudControllerManagerCommand(ccmOptions, cloudInitializer, controllerInitializers, fss, wait.NeverStop)
logs.InitLogs()
defer logs.FlushLogs()
if err := command.Execute(); err != nil {
os.Exit(1)
}
code := cli.Run(command)
os.Exit(code)
}
func cloudInitializer(config *cloudcontrollerconfig.CompletedConfig) cloudprovider.Interface {

View File

@ -19,14 +19,12 @@ limitations under the License.
package main
import (
"math/rand"
"os"
"time"
"github.com/spf13/pflag"
"k8s.io/component-base/cli"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/logs"
_ "k8s.io/component-base/logs/json/register" // for JSON log format registration
_ "k8s.io/component-base/metrics/prometheus/clientgo" // load all the prometheus client-go plugins
_ "k8s.io/component-base/metrics/prometheus/version" // for version metric registration
@ -34,16 +32,9 @@ import (
)
func main() {
rand.Seed(time.Now().UnixNano())
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
command := app.NewAPIServerCommand()
logs.InitLogs()
defer logs.FlushLogs()
if err := command.Execute(); err != nil {
os.Exit(1)
}
code := cli.Run(command)
os.Exit(code)
}

View File

@ -27,6 +27,7 @@ import (
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/cli/globalflag"
"k8s.io/component-base/logs"
)
func TestAddCustomGlobalFlags(t *testing.T) {
@ -48,6 +49,7 @@ func TestAddCustomGlobalFlags(t *testing.T) {
// Get all flags from flags.CommandLine, except flag `test.*`.
wantedFlag := []string{"help"}
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
logs.AddFlags(pflag.CommandLine)
normalizeFunc := nfs.GetNormalizeFunc()
pflag.VisitAll(func(flag *pflag.Flag) {
if !strings.Contains(flag.Name, "test.") {

View File

@ -21,14 +21,12 @@ limitations under the License.
package main
import (
"math/rand"
"os"
"time"
"github.com/spf13/pflag"
"k8s.io/component-base/cli"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/logs"
_ "k8s.io/component-base/logs/json/register" // for JSON log format registration
_ "k8s.io/component-base/metrics/prometheus/clientgo" // load all the prometheus client-go plugin
_ "k8s.io/component-base/metrics/prometheus/version" // for version metric registration
@ -36,16 +34,9 @@ import (
)
func main() {
rand.Seed(time.Now().UnixNano())
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
command := app.NewControllerManagerCommand()
logs.InitLogs()
defer logs.FlushLogs()
if err := command.Execute(); err != nil {
os.Exit(1)
}
code := cli.Run(command)
os.Exit(code)
}

View File

@ -20,6 +20,7 @@ package app
import (
"errors"
goflag "flag"
"fmt"
"io/ioutil"
"net"
@ -509,6 +510,7 @@ with the apiserver API to configure the proxy.`,
return nil
},
}
cmd.SetGlobalNormalizationFunc(pflag.CommandLine.GetNormalizeFunc())
var err error
opts.config, err = opts.ApplyDefaults(opts.config)
@ -518,7 +520,9 @@ with the apiserver API to configure the proxy.`,
os.Exit(1)
}
opts.AddFlags(cmd.Flags())
fs := cmd.Flags()
opts.AddFlags(fs)
fs.AddGoFlagSet(goflag.CommandLine) // for --boot-id-file and --machine-id-file
// TODO handle error
cmd.MarkFlagFilename("config", "yaml", "yml", "json")

View File

@ -17,35 +17,21 @@ limitations under the License.
package main
import (
goflag "flag"
"math/rand"
"os"
"time"
"github.com/spf13/pflag"
"k8s.io/component-base/cli"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/logs"
_ "k8s.io/component-base/metrics/prometheus/restclient" // for client metric registration
_ "k8s.io/component-base/metrics/prometheus/version" // for version metric registration
"k8s.io/kubernetes/cmd/kube-proxy/app"
)
func main() {
rand.Seed(time.Now().UnixNano())
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
command := app.NewProxyCommand()
// TODO: once we switch everything over to Cobra commands, we can go back to calling
// utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
// normalize func and add the go flag set by hand.
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
// utilflag.InitFlags()
logs.InitLogs()
defer logs.FlushLogs()
if err := command.Execute(); err != nil {
os.Exit(1)
}
code := cli.Run(command)
os.Exit(code)
}

View File

@ -25,6 +25,7 @@ import (
goruntime "runtime"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apiserver/pkg/authentication/authenticator"
@ -99,6 +100,8 @@ for more information about scheduling and the kube-scheduler component.`,
return nil
},
}
cmd.SetGlobalNormalizationFunc(pflag.CommandLine.GetNormalizeFunc())
fs := cmd.Flags()
verflag.AddFlags(namedFlagSets.FlagSet("global"))
globalflag.AddGlobalFlags(namedFlagSets.FlagSet("global"), cmd.Name())

View File

@ -17,15 +17,12 @@ limitations under the License.
package main
import (
"fmt"
"math/rand"
"os"
"time"
"github.com/spf13/pflag"
"k8s.io/component-base/cli"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/logs"
_ "k8s.io/component-base/logs/json/register" // for JSON log format registration
_ "k8s.io/component-base/metrics/prometheus/clientgo"
_ "k8s.io/component-base/metrics/prometheus/version" // for version metric registration
@ -33,31 +30,9 @@ import (
)
func main() {
if err := runSchedulerCmd(); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}
}
func runSchedulerCmd() error {
rand.Seed(time.Now().UnixNano())
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
command := app.NewSchedulerCommand()
logs.InitLogs()
defer logs.FlushLogs()
err := command.ParseFlags(os.Args[1:])
if err != nil {
// when fail to parse flags, return error with the usage message.
return fmt.Errorf("%v\n%s", err, command.UsageString())
}
if err := command.Execute(); err != nil {
return err
}
return nil
code := cli.Run(command)
os.Exit(code)
}

View File

@ -17,20 +17,21 @@ limitations under the License.
package main
import (
goflag "flag"
"os"
"github.com/spf13/pflag"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/component-base/cli"
cliflag "k8s.io/component-base/cli/flag"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/util/logs"
"k8s.io/kubernetes/pkg/kubectl/cmd/convert"
)
func main() {
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
flags := pflag.NewFlagSet("kubectl-convert", pflag.ExitOnError)
flags.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
pflag.CommandLine = flags
kubeConfigFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag()
@ -38,20 +39,8 @@ func main() {
matchVersionKubeConfigFlags := cmdutil.NewMatchVersionFlags(kubeConfigFlags)
f := cmdutil.NewFactory(matchVersionKubeConfigFlags)
// TODO: once we switch everything over to Cobra commands, we can go back to calling
// cliflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
// normalize func and add the go flag set by hand.
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
// cliflag.InitFlags()
logs.InitLogs()
defer logs.FlushLogs()
cmd := convert.NewCmdConvert(f, genericclioptions.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr})
matchVersionKubeConfigFlags.AddFlags(cmd.PersistentFlags())
if err := cmd.Execute(); err != nil {
os.Exit(1)
}
code := cli.Run(cmd)
os.Exit(code)
}

View File

@ -17,36 +17,22 @@ limitations under the License.
package main
import (
goflag "flag"
"math/rand"
"os"
"time"
"github.com/spf13/pflag"
"k8s.io/component-base/cli"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/kubectl/pkg/cmd"
"k8s.io/kubectl/pkg/util/logs"
// Import to initialize client auth plugins.
_ "k8s.io/client-go/plugin/pkg/client/auth"
)
func main() {
rand.Seed(time.Now().UnixNano())
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
command := cmd.NewDefaultKubectlCommand()
// TODO: once we switch everything over to Cobra commands, we can go back to calling
// cliflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
// normalize func and add the go flag set by hand.
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
// cliflag.InitFlags()
logs.InitLogs()
defer logs.FlushLogs()
if err := command.Execute(); err != nil {
os.Exit(1)
}
code := cli.Run(command)
os.Exit(code)
}

View File

@ -27,7 +27,6 @@ import (
// libs that provide registration functions
"k8s.io/component-base/logs"
"k8s.io/component-base/version/verflag"
"k8s.io/klog/v2"
// ensure libs have a chance to globally register their flags
_ "k8s.io/kubernetes/pkg/credentialprovider/azure"
@ -38,7 +37,6 @@ import (
// against the global flagsets from "flag" and "github.com/spf13/pflag".
// We do this in order to prevent unwanted flags from leaking into the Kubelet's flagset.
func AddGlobalFlags(fs *pflag.FlagSet) {
addKlogFlags(fs)
addCadvisorFlags(fs)
addCredentialProviderFlags(fs)
verflag.AddFlags(fs)
@ -88,10 +86,3 @@ func addCredentialProviderFlags(fs *pflag.FlagSet) {
fs.AddFlagSet(local)
}
// addKlogFlags adds flags from k8s.io/klog
func addKlogFlags(fs *pflag.FlagSet) {
local := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
klog.InitFlags(local)
fs.AddGoFlagSet(local)
}

View File

@ -383,6 +383,7 @@ func (f *KubeletFlags) AddFlags(mainfs *pflag.FlagSet) {
// AddKubeletConfigFlags adds flags for a specific kubeletconfig.KubeletConfiguration to the specified FlagSet
func AddKubeletConfigFlags(mainfs *pflag.FlagSet, c *kubeletconfig.KubeletConfiguration) {
fs := pflag.NewFlagSet("", pflag.ExitOnError)
fs.SetNormalizeFunc(mainfs.GetNormalizeFunc())
defer func() {
// All KubeletConfiguration flags are now deprecated, and any new flags that point to
// KubeletConfiguration fields are deprecated-on-creation. When removing flags at the end

View File

@ -259,6 +259,9 @@ HTTP server: The kubelet can also listen for HTTP and respond to a simple API
}
}
// Config and flags parsed, now we can initialize logging.
logs.InitLogs()
// construct a KubeletServer from kubeletFlags and kubeletConfig
kubeletServer := &options.KubeletServer{
KubeletFlags: *kubeletFlags,

View File

@ -26,6 +26,9 @@ import (
"os"
"time"
"github.com/spf13/cobra"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/logs"
_ "k8s.io/component-base/logs/json/register" // for JSON log format registration
_ "k8s.io/component-base/metrics/prometheus/restclient"
@ -34,13 +37,23 @@ import (
)
func main() {
command := app.NewKubeletCommand()
// kubelet uses a config file and does its own special
// parsing of flags and that config file. It initializes
// logging after it is done with that. Therefore it does
// not use cli.Run like other, simpler commands.
code := run(command)
os.Exit(code)
}
func run(command *cobra.Command) int {
defer logs.FlushLogs()
rand.Seed(time.Now().UnixNano())
command := app.NewKubeletCommand()
logs.InitLogs()
defer logs.FlushLogs()
command.SetGlobalNormalizationFunc(cliflag.WordSepNormalizeFunc)
if err := command.Execute(); err != nil {
os.Exit(1)
return 1
}
return 0
}

View File

@ -20,7 +20,6 @@ import (
"errors"
goflag "flag"
"fmt"
"math/rand"
"os"
"time"
@ -36,8 +35,8 @@ import (
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/events"
"k8s.io/component-base/cli"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/logs"
_ "k8s.io/component-base/metrics/prometheus/restclient" // for client metric registration
_ "k8s.io/component-base/metrics/prometheus/version" // for version metric registration
"k8s.io/component-base/version"
@ -131,22 +130,11 @@ func (c *hollowNodeConfig) createHollowKubeletOptions() *kubemark.HollowKubletOp
}
func main() {
rand.Seed(time.Now().UnixNano())
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
command := newHollowNodeCommand()
// TODO: once we switch everything over to Cobra commands, we can go back to calling
// cliflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
// normalize func and add the go flag set by hand.
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
// cliflag.InitFlags()
logs.InitLogs()
defer logs.FlushLogs()
if err := command.Execute(); err != nil {
os.Exit(1)
}
code := cli.Run(command)
os.Exit(code)
}
// newControllerManagerCommand creates a *cobra.Command object with default parameters
@ -172,7 +160,11 @@ func newHollowNodeCommand() *cobra.Command {
return nil
},
}
s.addFlags(cmd.Flags())
cmd.SetGlobalNormalizationFunc(pflag.CommandLine.GetNormalizeFunc())
fs := cmd.Flags()
fs.AddGoFlagSet(goflag.CommandLine) // for flags like --docker-only
s.addFlags(fs)
return cmd
}

View File

@ -20,6 +20,7 @@ import (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"k8s.io/klog/v2"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@ -100,6 +101,7 @@ func NewCmdConvert(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *co
cmdutil.CheckErr(o.RunConvert())
},
}
cmd.SetGlobalNormalizationFunc(pflag.CommandLine.GetNormalizeFunc())
cmd.Flags().BoolVar(&o.local, "local", o.local, "If true, convert will NOT try to contact api-server but run locally.")
cmd.Flags().StringVar(&o.OutputVersion, "output-version", o.OutputVersion, i18n.T("Output the formatted object with the given group version (for ex: 'extensions/v1beta1')."))

View File

@ -279,5 +279,5 @@
- k8s.io/pod-security-admission
- k8s.io/component-base/featuregate
- k8s.io/component-base/logs
- k8s.io/component-base/cli/flag
- k8s.io/component-base/cli
- k8s.io/utils

View File

@ -17,24 +17,16 @@ limitations under the License.
package main
import (
"flag"
"os"
"k8s.io/klog/v2"
"k8s.io/apiextensions-apiserver/pkg/cmd/server"
genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/component-base/logs"
"k8s.io/component-base/cli"
)
func main() {
logs.InitLogs()
defer logs.FlushLogs()
stopCh := genericapiserver.SetupSignalHandler()
cmd := server.NewServerCommand(os.Stdout, os.Stderr, stopCh)
cmd.Flags().AddGoFlagSet(flag.CommandLine)
if err := cmd.Execute(); err != nil {
klog.Fatal(err)
}
code := cli.Run(cmd)
os.Exit(code)
}

View File

@ -40,6 +40,7 @@ import (
"k8s.io/apimachinery/pkg/util/wait"
etcd3watcher "k8s.io/apiserver/pkg/storage/etcd3"
"k8s.io/client-go/dynamic"
_ "k8s.io/component-base/logs/testinit" // enable logging flags
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"

View File

@ -29,6 +29,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
_ "k8s.io/component-base/logs/testinit" // enable logging flags
)
var swaggerMetadataDescriptions = metav1.ObjectMeta{}.SwaggerDoc()

View File

@ -25,6 +25,8 @@ import (
"time"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/runtime/schema"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/sets"
@ -101,6 +103,7 @@ the cloud specific control loops shipped with Kubernetes.`,
return nil
},
}
cmd.SetGlobalNormalizationFunc(pflag.CommandLine.GetNormalizeFunc())
fs := cmd.Flags()
namedFlagSets := s.Flags(ControllerNames(controllerInitFuncConstructors), ControllersDisabledByDefault.List())

View File

@ -21,9 +21,7 @@ limitations under the License.
package main
import (
"math/rand"
"os"
"time"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/util/wait"
@ -31,8 +29,8 @@ import (
"k8s.io/cloud-provider/app"
"k8s.io/cloud-provider/app/config"
"k8s.io/cloud-provider/options"
"k8s.io/component-base/cli"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/logs"
_ "k8s.io/component-base/metrics/prometheus/clientgo" // load all the prometheus client-go plugins
_ "k8s.io/component-base/metrics/prometheus/version" // for version metric registration
"k8s.io/klog/v2"
@ -41,7 +39,7 @@ import (
)
func main() {
rand.Seed(time.Now().UnixNano())
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
ccmOptions, err := options.NewCloudControllerManagerOptions()
if err != nil {
@ -50,19 +48,8 @@ func main() {
fss := cliflag.NamedFlagSets{}
command := app.NewCloudControllerManagerCommand(ccmOptions, cloudInitializer, controllerInitializers(), fss, wait.NeverStop)
// TODO: once we switch everything over to Cobra commands, we can go back to calling
// utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
// normalize func and add the go flag set by hand.
// Here is an sample
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
// utilflag.InitFlags()
logs.InitLogs()
defer logs.FlushLogs()
if err := command.Execute(); err != nil {
os.Exit(1)
}
code := cli.Run(command)
os.Exit(code)
}
// If custom ClientNames are used, as below, then the controller will not use

View File

@ -19,34 +19,20 @@ package globalflag
import (
"flag"
"fmt"
"os"
"github.com/spf13/pflag"
"k8s.io/component-base/logs"
"k8s.io/klog/v2"
)
// AddGlobalFlags explicitly registers flags that libraries (klog, verflag, etc.) register
// 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.
func AddGlobalFlags(fs *pflag.FlagSet, name string) {
addKlogFlags(fs)
logs.AddFlags(fs)
fs.BoolP("help", "h", false, fmt.Sprintf("help for %s", name))
}
// addKlogFlags adds flags from k8s.io/klog
func addKlogFlags(fs *pflag.FlagSet) {
local := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
klog.InitFlags(local)
normalizeFunc := fs.GetNormalizeFunc()
local.VisitAll(func(fl *flag.Flag) {
fl.Name = string(normalizeFunc(fs, fl.Name))
fs.AddGoFlag(fl)
})
}
// Register adds a flag to local that targets the Value associated with the Flag named globalName in flag.CommandLine.
func Register(local *pflag.FlagSet, globalName string) {
if f := flag.CommandLine.Lookup(globalName); f != nil {

View File

@ -26,6 +26,7 @@ import (
"github.com/spf13/pflag"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/logs"
)
func TestAddGlobalFlags(t *testing.T) {
@ -42,6 +43,7 @@ func TestAddGlobalFlags(t *testing.T) {
// Get all flags from flags.CommandLine, except flag `test.*`.
wantedFlag := []string{"help"}
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
logs.AddFlags(pflag.CommandLine)
normalizeFunc := nfs.GetNormalizeFunc()
pflag.VisitAll(func(flag *pflag.Flag) {
if !strings.Contains(flag.Name, "test.") {

View File

@ -19,6 +19,7 @@ package logs
import (
"flag"
"fmt"
"sort"
"strings"
"github.com/spf13/pflag"
@ -36,9 +37,17 @@ const (
// LogRegistry is new init LogFormatRegistry struct
var LogRegistry = NewLogFormatRegistry()
// 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() {
// Text format is default klog format
LogRegistry.Register(DefaultLogFormat, nil)
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
@ -49,11 +58,7 @@ var supportedLogsFlags = map[string]struct{}{
// BindLoggingFlags binds the Options struct fields to a flagset
func BindLoggingFlags(c *config.LoggingConfiguration, fs *pflag.FlagSet) {
normalizeFunc := func(name string) string {
f := fs.GetNormalizeFunc()
return string(f(fs, name))
}
unsupportedFlags := fmt.Sprintf("--%s", strings.Join(UnsupportedLoggingFlags(normalizeFunc), ", --"))
unsupportedFlags := strings.Join(unsupportedLoggingFlagNames(fs.GetNormalizeFunc()), ", ")
formats := fmt.Sprintf(`"%s"`, strings.Join(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
@ -62,30 +67,37 @@ func BindLoggingFlags(c *config.LoggingConfiguration, fs *pflag.FlagSet) {
Runtime log sanitization may introduce significant computation overhead and therefore should not be enabled in production.`)
}
// UnsupportedLoggingFlags lists unsupported logging flags
func UnsupportedLoggingFlags(normalizeFunc func(name string) string) []string {
allFlags := []string{}
// k8s.io/klog flags
fs := &flag.FlagSet{}
klog.InitFlags(fs)
fs.VisitAll(func(flag *flag.Flag) {
// 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 {
name := flag.Name
if normalizeFunc != nil {
name = normalizeFunc(name)
}
allFlags = append(allFlags, name)
// Normalization changes flag.Name, so make a copy.
clone := *flag
pfs.AddFlag(&clone)
}
})
// k8s.io/component-base/logs flags
pfs := &pflag.FlagSet{}
AddFlags(pfs)
// Apply normalization.
pfs.SetNormalizeFunc(normalizeFunc)
var allFlags []*pflag.Flag
pfs.VisitAll(func(flag *pflag.Flag) {
if _, found := supportedLogsFlags[flag.Name]; !found {
allFlags = append(allFlags, flag.Name)
}
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
}

View File

@ -22,7 +22,10 @@ import (
"os"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"k8s.io/component-base/cli"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/logs"
"k8s.io/klog/v2"
@ -30,13 +33,14 @@ import (
)
func main() {
command := NewLoggerCommand()
logs.InitLogs()
defer logs.FlushLogs()
// NamedFlagSets use the global pflag.CommandLine. We don't use those
// in this command (yet), but set it globally anyway for consistency
// with other commands.
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
if err := command.Execute(); err != nil {
os.Exit(1)
}
command := NewLoggerCommand()
code := cli.Run(command)
os.Exit(code)
}
func NewLoggerCommand() *cobra.Command {
@ -52,6 +56,8 @@ func NewLoggerCommand() *cobra.Command {
runLogger()
},
}
cmd.SetGlobalNormalizationFunc(pflag.CommandLine.GetNormalizeFunc())
o.AddFlags(cmd.Flags())
return cmd
}

View File

@ -14,6 +14,9 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// Package logs contains support for logging options, flags and setup.
// Commands must explicitly enable command line flags. They no longer
// get added automatically when importing this package.
package logs
import (
@ -29,16 +32,42 @@ import (
const logFlushFreqFlagName = "log-flush-frequency"
var logFlushFreq = pflag.Duration(logFlushFreqFlagName, 5*time.Second, "Maximum number of seconds between log flushes")
var (
packageFlags = flag.NewFlagSet("logging", flag.ContinueOnError)
logFlushFreq time.Duration
)
func init() {
klog.InitFlags(flag.CommandLine)
klog.InitFlags(packageFlags)
packageFlags.DurationVar(&logFlushFreq, logFlushFreqFlagName, 5*time.Second, "Maximum number of seconds between log flushes")
}
// AddFlags registers this package's flags on arbitrary FlagSets, such that they point to the
// same value as the global flags.
// AddFlags registers this package's flags on arbitrary FlagSets. This includes
// the klog flags, with the original underscore as separator between. If
// commands want hyphens as separators, they can set
// k8s.io/component-base/cli/flag/WordSepNormalizeFunc as normalization
// function on the flag set before calling AddFlags.
//
// May be called more than once.
func AddFlags(fs *pflag.FlagSet) {
fs.AddFlag(pflag.Lookup(logFlushFreqFlagName))
// Determine whether the flags are already present by looking up one
// which always should exist.
if f := fs.Lookup("v"); f != nil {
return
}
fs.AddGoFlagSet(packageFlags)
}
// AddGoFlags is a variant of AddFlags for traditional Go flag.FlagSet.
// Commands should use pflag whenever possible for the sake of consistency.
// Cases where this function is needed include tests (they have to set up flags
// in flag.CommandLine) and commands that for historic reasons use Go
// flag.Parse and cannot change to pflag because it would break their command
// line interface.
func AddGoFlags(fs *flag.FlagSet) {
packageFlags.VisitAll(func(f *flag.Flag) {
fs.Var(f.Value, f.Name, f.Usage)
})
}
// KlogWriter serves as a bridge between the standard log package and the glog package.
@ -50,15 +79,19 @@ func (writer KlogWriter) Write(data []byte) (n int, err error) {
return len(data), nil
}
// InitLogs initializes logs the way we want for kubernetes.
// InitLogs initializes logs the way we want for Kubernetes.
// It should be called after parsing flags. If called before that,
// it will use the default log settings.
func InitLogs() {
log.SetOutput(KlogWriter{})
log.SetFlags(0)
// The default glog flush interval is 5 seconds.
go wait.Forever(klog.Flush, *logFlushFreq)
// The default klog flush interval is 5 seconds.
go wait.Forever(klog.Flush, logFlushFreq)
}
// FlushLogs flushes logs immediately.
// FlushLogs flushes logs immediately. This should be called at the end of
// the main function via defer to ensure that all pending log messages
// are printed before exiting the program.
func FlushLogs() {
klog.Flush()
}

View File

@ -37,7 +37,7 @@ func TestFlags(t *testing.T) {
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.
--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, --log-flush-frequency.
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")
`
if !assert.Equal(t, want, output.String()) {

View File

@ -0,0 +1,32 @@
/*
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 testinit adds logging flags to a Ginkgo or Go test program during
// initialization, something that the logs package itself no longer does.
//
// Normal commands should not use this and instead manage logging flags with
// logs.Options and/or cli.Run.
package testinit
import (
"flag"
"k8s.io/component-base/logs"
)
func init() {
logs.AddGoFlags(flag.CommandLine)
}

View File

@ -17,23 +17,22 @@ limitations under the License.
package logs
import (
"flag"
"fmt"
"strings"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/util/validation/field"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/config"
)
func ValidateLoggingConfiguration(c *config.LoggingConfiguration, fldPath *field.Path) field.ErrorList {
errs := field.ErrorList{}
if c.Format != DefaultLogFormat {
allFlags := UnsupportedLoggingFlags(hyphensToUnderscores)
for _, fname := range allFlags {
if flagIsSet(fname, hyphensToUnderscores) {
errs = append(errs, field.Invalid(fldPath.Child("format"), c.Format, fmt.Sprintf("Non-default format doesn't honor flag: %s", fname)))
// WordSepNormalizeFunc is just a guess. Most commands 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)))
}
}
}
@ -42,27 +41,3 @@ func ValidateLoggingConfiguration(c *config.LoggingConfiguration, fldPath *field
}
return errs
}
// hyphensToUnderscores replaces hyphens with underscores
// we should always use underscores instead of hyphens when validate flags
func hyphensToUnderscores(s string) string {
return strings.Replace(s, "-", "_", -1)
}
func flagIsSet(name string, normalizeFunc func(name string) string) bool {
f := flag.Lookup(name)
if f != nil {
return f.DefValue != f.Value.String()
}
if normalizeFunc != nil {
f = flag.Lookup(normalizeFunc(name))
if f != nil {
return f.DefValue != f.Value.String()
}
}
pf := pflag.Lookup(name)
if pf != nil {
return pf.DefValue != pf.Value.String()
}
panic("failed to lookup unsupported log flag")
}

View File

@ -17,13 +17,10 @@ limitations under the License.
package main
import (
"flag"
"os"
"k8s.io/klog/v2"
genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/component-base/logs"
"k8s.io/component-base/cli"
"k8s.io/kube-aggregator/pkg/cmd/server"
// force compilation of packages we'll later rely upon
@ -35,14 +32,9 @@ import (
)
func main() {
logs.InitLogs()
defer logs.FlushLogs()
stopCh := genericapiserver.SetupSignalHandler()
options := server.NewDefaultOptions(os.Stdout, os.Stderr)
cmd := server.NewCommandStartAggregator(options, stopCh)
cmd.Flags().AddGoFlagSet(flag.CommandLine)
if err := cmd.Execute(); err != nil {
klog.Fatal(err)
}
code := cli.Run(cmd)
os.Exit(code)
}

View File

@ -17,7 +17,6 @@ limitations under the License.
package cmd
import (
"flag"
"fmt"
"io"
"net/http"
@ -255,13 +254,11 @@ func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
return nil
},
}
// From this point and forward we get warnings on flags that contain "_" separators
// when adding them with hyphen instead of the original name.
cmds.SetGlobalNormalizationFunc(cliflag.WarnWordSepNormalizeFunc)
flags := cmds.PersistentFlags()
flags.SetNormalizeFunc(cliflag.WarnWordSepNormalizeFunc) // Warn for "_" flags
// Normalize all flags that are coming from other packages or pre-configurations
// a.k.a. change all "_" to "-". e.g. glog package
flags.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
addProfilingFlags(flags)
@ -270,12 +267,10 @@ func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
kubeConfigFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag()
kubeConfigFlags.AddFlags(flags)
matchVersionKubeConfigFlags := cmdutil.NewMatchVersionFlags(kubeConfigFlags)
matchVersionKubeConfigFlags.AddFlags(cmds.PersistentFlags())
matchVersionKubeConfigFlags.AddFlags(flags)
// Updates hooks to add kubectl command headers: SIG CLI KEP 859.
addCmdHeaderHooks(cmds, kubeConfigFlags)
cmds.PersistentFlags().AddGoFlagSet(flag.CommandLine)
f := cmdutil.NewFactory(matchVersionKubeConfigFlags)
// Sending in 'nil' for the getLanguageFn() results in using
@ -285,9 +280,6 @@ func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
// the language, instead of just loading from the LANG env. variable.
i18n.LoadTranslations("kubectl", nil)
// From this point and forward we get warnings on flags that contain "_" separators
cmds.SetGlobalNormalizationFunc(cliflag.WarnWordSepNormalizeFunc)
ioStreams := genericclioptions.IOStreams{In: in, Out: out, ErrOut: err}
// Proxy command is incompatible with CommandHeaderRoundTripper, so
@ -392,6 +384,9 @@ func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
cmds.AddCommand(apiresources.NewCmdAPIResources(f, ioStreams))
cmds.AddCommand(options.NewCmdOptions(ioStreams.Out))
// Stop warning about normalization of flags. That makes it possible to
// add the klog flags later.
cmds.SetGlobalNormalizationFunc(cliflag.WordSepNormalizeFunc)
return cmds
}

View File

@ -1,62 +0,0 @@
/*
Copyright 2014 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 (
"flag"
"log"
"time"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/klog/v2"
)
var logFlushFreq = pflag.Duration("log-flush-frequency", 5*time.Second, "Maximum number of seconds between log flushes")
// TODO(thockin): This is temporary until we agree on log dirs and put those into each cmd.
func init() {
klog.InitFlags(flag.CommandLine)
flag.Set("logtostderr", "true")
}
// KlogWriter serves as a bridge between the standard log package and the glog package.
type KlogWriter struct{}
// Write implements the io.Writer interface.
func (writer KlogWriter) Write(data []byte) (n int, err error) {
klog.InfoDepth(1, string(data))
return len(data), nil
}
// InitLogs initializes logs the way we want for kubernetes.
func InitLogs() {
log.SetOutput(KlogWriter{})
log.SetFlags(0)
// The default glog flush interval is 5 seconds.
go wait.Until(klog.Flush, *logFlushFreq, wait.NeverStop)
}
// FlushLogs flushes logs immediately.
func FlushLogs() {
klog.Flush()
}
// NewLogger creates a new log.Logger which sends logs to klog.Info.
func NewLogger(prefix string) *log.Logger {
return log.New(KlogWriter{}, prefix, 0)
}

View File

@ -27,6 +27,7 @@ import (
"time"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
admissionv1 "k8s.io/api/admission/v1"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
@ -58,6 +59,7 @@ Security Standards.`,
},
Args: cobra.NoArgs,
}
cmd.SetGlobalNormalizationFunc(pflag.CommandLine.GetNormalizeFunc())
opts.AddFlags(cmd.Flags())
return cmd

View File

@ -17,34 +17,18 @@ limitations under the License.
package main
import (
"flag"
"math/rand"
"os"
"time"
"github.com/spf13/pflag"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/logs"
"k8s.io/component-base/cli"
_ "k8s.io/component-base/logs/json/register" // for JSON log format registration
"k8s.io/klog/v2"
"k8s.io/pod-security-admission/cmd/webhook/server"
)
func main() {
rand.Seed(time.Now().UnixNano())
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
// Due to historic reasons, this command does *not* normalize command
// line flags.
command := server.NewServerCommand()
logs.InitLogs()
defer logs.FlushLogs()
logFlags := flag.NewFlagSet("klog", flag.ContinueOnError)
klog.InitFlags(logFlags)
command.Flags().AddGoFlagSet(logFlags)
if err := command.Execute(); err != nil {
os.Exit(1)
}
code := cli.Run(command)
os.Exit(code)
}

View File

@ -7,12 +7,12 @@ go 1.16
require (
github.com/google/gofuzz v1.1.0
github.com/spf13/cobra v1.2.1
github.com/spf13/pflag v1.0.5
k8s.io/apimachinery v0.0.0
k8s.io/apiserver v0.0.0
k8s.io/client-go v0.0.0
k8s.io/code-generator v0.0.0
k8s.io/component-base v0.0.0
k8s.io/klog/v2 v2.20.0
k8s.io/kube-openapi v0.0.0-20210817084001-7fbd8d59e5b8
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a
)

View File

@ -17,25 +17,22 @@ limitations under the License.
package main
import (
"flag"
"os"
"k8s.io/klog/v2"
"github.com/spf13/pflag"
genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/component-base/logs"
"k8s.io/component-base/cli"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/sample-apiserver/pkg/cmd/server"
)
func main() {
logs.InitLogs()
defer logs.FlushLogs()
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
stopCh := genericapiserver.SetupSignalHandler()
options := server.NewWardleServerOptions(os.Stdout, os.Stderr)
cmd := server.NewCommandStartWardleServer(options, stopCh)
cmd.Flags().AddGoFlagSet(flag.CommandLine)
if err := cmd.Execute(); err != nil {
klog.Fatal(err)
}
code := cli.Run(cmd)
os.Exit(code)
}

View File

@ -61,6 +61,9 @@ import (
_ "k8s.io/kubernetes/test/e2e/framework/providers/kubemark"
_ "k8s.io/kubernetes/test/e2e/framework/providers/openstack"
_ "k8s.io/kubernetes/test/e2e/framework/providers/vsphere"
// Ensure that logging flags are part of the command line.
_ "k8s.io/component-base/logs/testinit"
)
const (

View File

@ -42,6 +42,7 @@ import (
utilyaml "k8s.io/apimachinery/pkg/util/yaml"
clientset "k8s.io/client-go/kubernetes"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/logs"
"k8s.io/kubernetes/pkg/util/rlimit"
commontest "k8s.io/kubernetes/test/e2e/common"
"k8s.io/kubernetes/test/e2e/framework"
@ -105,6 +106,7 @@ func TestMain(m *testing.M) {
e2econfig.CopyFlags(e2econfig.Flags, flag.CommandLine)
framework.RegisterCommonFlags(flag.CommandLine)
registerNodeFlags(flag.CommandLine)
logs.AddFlags(pflag.CommandLine)
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
// Mark the run-services-mode flag as hidden to prevent user from using it.
pflag.CommandLine.MarkHidden("run-services-mode")

View File

@ -17,11 +17,11 @@ limitations under the License.
package main
import (
"flag"
"os"
"github.com/spf13/cobra"
"k8s.io/klog/v2"
"k8s.io/component-base/cli"
auditproxy "k8s.io/kubernetes/test/images/agnhost/audit-proxy"
"k8s.io/kubernetes/test/images/agnhost/connect"
crdconvwebhook "k8s.io/kubernetes/test/images/agnhost/crd-conversion-webhook"
@ -85,8 +85,6 @@ func main() {
// NOTE(claudiub): Some tests are passing logging related flags, so we need to be able to
// accept them. This will also include them in the printed help.
loggingFlags := &flag.FlagSet{}
klog.InitFlags(loggingFlags)
rootCmd.PersistentFlags().AddGoFlagSet(loggingFlags)
rootCmd.Execute()
code := cli.Run(rootCmd)
os.Exit(code)
}

View File

@ -0,0 +1,22 @@
/*
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 framework
import (
// All integration tests are expected to have logging flags.
_ "k8s.io/component-base/logs/testinit"
)

3
vendor/modules.txt vendored
View File

@ -1935,6 +1935,7 @@ k8s.io/code-generator/pkg/util
k8s.io/code-generator/third_party/forked/golang/reflect
# k8s.io/component-base v0.0.0 => ./staging/src/k8s.io/component-base
## explicit
k8s.io/component-base/cli
k8s.io/component-base/cli/flag
k8s.io/component-base/cli/globalflag
k8s.io/component-base/codec
@ -1952,6 +1953,7 @@ k8s.io/component-base/logs/json
k8s.io/component-base/logs/json/register
k8s.io/component-base/logs/logreduction
k8s.io/component-base/logs/sanitization
k8s.io/component-base/logs/testinit
k8s.io/component-base/metrics
k8s.io/component-base/metrics/legacyregistry
k8s.io/component-base/metrics/prometheus/clientgo
@ -2148,7 +2150,6 @@ k8s.io/kubectl/pkg/util/fieldpath
k8s.io/kubectl/pkg/util/hash
k8s.io/kubectl/pkg/util/i18n
k8s.io/kubectl/pkg/util/interrupt
k8s.io/kubectl/pkg/util/logs
k8s.io/kubectl/pkg/util/openapi
k8s.io/kubectl/pkg/util/openapi/testing
k8s.io/kubectl/pkg/util/openapi/validation