diff --git a/cmd/nfd-master/main.go b/cmd/nfd-master/main.go index 0718be36e..a3016091d 100644 --- a/cmd/nfd-master/main.go +++ b/cmd/nfd-master/main.go @@ -20,6 +20,7 @@ import ( "flag" "fmt" "os" + "strings" "time" "k8s.io/klog/v2" @@ -40,8 +41,6 @@ func main() { printVersion := flags.Bool("version", false, "Print version and exit.") args, overrides := initFlags(flags) - // Inject klog flags - klog.InitFlags(flags) _ = flags.Parse(os.Args[1:]) if len(flags.Args()) > 0 { @@ -137,6 +136,8 @@ func initFlags(flagset *flag.FlagSet) (*master.Args, *master.ConfigOverrideArgs) flagset.BoolVar(&args.EnableLeaderElection, "enable-leader-election", false, "Enables a leader election. Enable this when running more than one replica on nfd master.") + initKlogFlags(flagset, args) + overrides := &master.ConfigOverrideArgs{ LabelWhiteList: &utils.RegexpVal{}, DenyLabelNs: &utils.StringSetVal{}, @@ -165,3 +166,24 @@ func initFlags(flagset *flag.FlagSet) (*master.Args, *master.ConfigOverrideArgs) return args, overrides } + +func initKlogFlags(flagset *flag.FlagSet, args *master.Args) { + args.Klog = make(map[string]*utils.KlogFlagVal) + + flags := flag.NewFlagSet("klog flags", flag.ContinueOnError) + //flags.SetOutput(ioutil.Discard) + klog.InitFlags(flags) + flags.VisitAll(func(f *flag.Flag) { + name := klogConfigOptName(f.Name) + args.Klog[name] = utils.NewKlogFlagVal(f) + flagset.Var(args.Klog[name], f.Name, f.Usage) + }) +} + +func klogConfigOptName(flagName string) string { + split := strings.Split(flagName, "_") + for i, v := range split[1:] { + split[i+1] = strings.ToUpper(v[0:1]) + v[1:] + } + return strings.Join(split, "") +} diff --git a/cmd/nfd-master/main_test.go b/cmd/nfd-master/main_test.go new file mode 100644 index 000000000..53d1625b6 --- /dev/null +++ b/cmd/nfd-master/main_test.go @@ -0,0 +1,39 @@ +/* +Copyright 2023 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 main + +import ( + "testing" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestKlogConfigOptName(t *testing.T) { + Convey("When converting names of klog command line flags", t, func() { + tcs := map[string]string{ + "": "", + "a": "a", + "an_arg": "anArg", + "arg_with_many_parts": "argWithManyParts", + } + Convey("resulting config option names should be as expected", func() { + for input, expected := range tcs { + So(klogConfigOptName(input), ShouldEqual, expected) + } + }) + }) +} diff --git a/deployment/components/master-config/nfd-master.conf.example b/deployment/components/master-config/nfd-master.conf.example index 44fa186e1..11d320272 100644 --- a/deployment/components/master-config/nfd-master.conf.example +++ b/deployment/components/master-config/nfd-master.conf.example @@ -5,6 +5,21 @@ # enableTaints: false # labelWhiteList: "foo" # resyncPeriod: "2h" +# klog: +# addDirHeader: false +# alsologtostderr: false +# logBacktraceAt: +# logtostderr: true +# skipHeaders: false +# stderrthreshold: 2 +# v: 0 +# vmodule: +## NOTE: the following options are not dynamically run-time configurable +## and require a nfd-master restart to take effect after being changed +# logDir: +# logFile: +# logFileMaxSize: 1800 +# skipLogHeaders: false # leaderElection: # leaseDuration: 15s # # this value has to be lower than leaseDuration and greater than retryPeriod*1.2 diff --git a/deployment/helm/node-feature-discovery/values.yaml b/deployment/helm/node-feature-discovery/values.yaml index d285da176..5b35a678f 100644 --- a/deployment/helm/node-feature-discovery/values.yaml +++ b/deployment/helm/node-feature-discovery/values.yaml @@ -21,6 +21,21 @@ master: # enableTaints: false # labelWhiteList: "foo" # resyncPeriod: "2h" + # klog: + # addDirHeader: false + # alsologtostderr: false + # logBacktraceAt: + # logtostderr: true + # skipHeaders: false + # stderrthreshold: 2 + # v: 0 + # vmodule: + ## NOTE: the following options are not dynamically run-time configurable + ## and require a nfd-master restart to take effect after being changed + # logDir: + # logFile: + # logFileMaxSize: 1800 + # skipLogHeaders: false # leaderElection: # leaseDuration: 15s # # this value has to be lower than leaseDuration and greater than retryPeriod*1.2 diff --git a/docs/reference/master-configuration-reference.md b/docs/reference/master-configuration-reference.md index 550115fee..98a44c3b0 100644 --- a/docs/reference/master-configuration-reference.md +++ b/docs/reference/master-configuration-reference.md @@ -191,7 +191,7 @@ leaderElection: retryPeriod: 2s ``` -### nfdApiParallelism +## nfdApiParallelism The `nfdApiParallelism` option can be used to specify the maximum number of concurrent node updates. @@ -205,3 +205,106 @@ Example: ```yaml nfdApiParallelism: 1 ``` + +## klog + +The following options specify the logger configuration. Most of which can be +dynamically adjusted at run-time. + +> **NOTE:** The logger options can also be specified via command line flags +> which take precedence over any corresponding config file options. + +### klog.addDirHeader + +If true, adds the file directory to the header of the log messages. + +Default: `false` + +Run-time configurable: yes + +### klog.alsologtostderr + +Log to standard error as well as files. + +Default: `false` + +Run-time configurable: yes + +### klog.logBacktraceAt + +When logging hits line file:N, emit a stack trace. + +Default: *empty* + +Run-time configurable: yes + +### klog.logDir + +If non-empty, write log files in this directory. + +Default: *empty* + +Run-time configurable: no + +### klog.logFile + +If non-empty, use this log file. + +Default: *empty* + +Run-time configurable: no + +### klog.logFileMaxSize + +Defines the maximum size a log file can grow to. Unit is megabytes. If the +value is 0, the maximum file size is unlimited. + +Default: `1800` + +Run-time configurable: no + +### klog.logtostderr + +Log to standard error instead of files + +Default: `true` + +Run-time configurable: yes + +### klog.skipHeaders + +If true, avoid header prefixes in the log messages. + +Default: `false` + +Run-time configurable: yes + +### klog.skipLogHeaders + +If true, avoid headers when opening log files. + +Default: `false` + +Run-time configurable: no + +### klog.stderrthreshold + +Logs at or above this threshold go to stderr (default 2) + +Run-time configurable: yes + +### klog.v + +Number for the log level verbosity. + +Default: `0` + +Run-time configurable: yes + +### klog.vmodule + +Comma-separated list of `pattern=N` settings for file-filtered logging. + +Default: *empty* + +Run-time configurable: yes diff --git a/pkg/nfd-master/nfd-master.go b/pkg/nfd-master/nfd-master.go index 9f283398c..56b9f2f77 100644 --- a/pkg/nfd-master/nfd-master.go +++ b/pkg/nfd-master/nfd-master.go @@ -78,6 +78,7 @@ type NFDConfig struct { ResyncPeriod utils.DurationVal LeaderElection LeaderElectionConfig NfdApiParallelism int + Klog map[string]string } // LeaderElectionConfig contains the configuration for leader election @@ -106,6 +107,7 @@ type Args struct { ConfigFile string Instance string KeyFile string + Klog map[string]*utils.KlogFlagVal Kubeconfig string CrdController bool EnableNodeFeatureApi bool @@ -201,6 +203,7 @@ func newDefaultConfig() *NFDConfig { RetryPeriod: utils.DurationVal{Duration: time.Duration(2) * time.Second}, RenewDeadline: utils.DurationVal{Duration: time.Duration(10) * time.Second}, }, + Klog: make(map[string]string), } } @@ -1166,6 +1169,28 @@ func (m *nfdMaster) createExtendedResourcePatches(n *corev1.Node, extendedResour return patches } +func (m *nfdMaster) configureKlog(c *NFDConfig) error { + // Handle klog + for k, a := range m.args.Klog { + if !a.IsSetFromCmdline() { + v, ok := c.Klog[k] + if !ok { + v = a.DefValue() + } + if err := a.SetFromConfig(v); err != nil { + return fmt.Errorf("failed to set logger option klog.%s = %v: %v", k, v, err) + } + } + } + for k := range c.Klog { + if _, ok := m.args.Klog[k]; !ok { + klog.InfoS("unknown logger option in config", "optionName", k) + } + } + + return nil +} + // Parse configuration options func (m *nfdMaster) configure(filepath string, overrides string) error { // Create a new default config @@ -1224,6 +1249,11 @@ func (m *nfdMaster) configure(filepath string, overrides string) error { } m.config = c + + if err := m.configureKlog(c); err != nil { + return err + } + if !c.NoPublish { kubeconfig, err := m.getKubeconfig() if err != nil {