1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2025-04-15 00:36:23 +00:00

nfd-worker: dynamic configuration of klog

Make it possible to dynamically (at run-time) alter most of the logging
configuration from the config file.
This commit is contained in:
Markus Lehtonen 2021-02-23 20:42:17 +02:00
parent 7da7fde8f6
commit 3f18e880b4
11 changed files with 311 additions and 3 deletions

View file

@ -20,6 +20,7 @@ import (
"flag"
"fmt"
"os"
"strings"
"k8s.io/klog/v2"
@ -112,6 +113,8 @@ func initFlags(flagset *flag.FlagSet) (*worker.Args, *worker.ConfigOverrideArgs)
flagset.StringVar(&args.ServerNameOverride, "server-name-override", "",
"Hostname expected from server certificate, useful in testing")
initKlogFlags(flagset, args)
// Flags overlapping with config file options
overrides := &worker.ConfigOverrideArgs{
LabelWhiteList: &utils.RegexpVal{},
@ -132,3 +135,24 @@ func initFlags(flagset *flag.FlagSet) (*worker.Args, *worker.ConfigOverrideArgs)
return args, overrides
}
func initKlogFlags(flagset *flag.FlagSet, args *worker.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.Title(v)
}
return strings.Join(split, "")
}

View file

@ -59,3 +59,19 @@ func TestParseArgs(t *testing.T) {
})
})
}
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)
}
})
})
}

View file

@ -77,6 +77,21 @@ worker:
# noPublish: false
# sleepInterval: 60s
# sources: [all]
# 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-worker restart to take effect after being changed
# logDir:
# logFile:
# logFileMaxSize: 1800
# skipLogHeaders: false
#sources:
# cpu:
# cpuid:

View file

@ -232,6 +232,10 @@ configuration file, instead.
The following logging-related flags are inherited from the
[klog](https://pkg.go.dev/k8s.io/klog/v2) package.
Note: The logger setup can also be specified via the `core.klog` configuration
file options. However, the command line flags take precedence over any
corresponding config file options specified.
#### -add_dir_header
If true, adds the file directory to the header of the log messages.

View file

@ -104,6 +104,109 @@ core:
noPublish: true
```
### core.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.
#### core.klog.addDirHeader
If true, adds the file directory to the header of the log messages.
Default: false
Run-time configurable: yes
#### core.klog.alsologtostderr
Log to standard error as well as files.
Default: false
Run-time configurable: yes
#### core.klog.logBacktraceAt
When logging hits line file:N, emit a stack trace.
Default: *empty*
Run-time configurable: yes
#### core.klog.logDir
If non-empty, write log files in this directory.
Default: *empty*
Run-time configurable: no
#### core.klog.logFile
If non-empty, use this log file.
Default: *empty*
Run-time configurable: no
#### core.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
#### core.klog.logtostderr
Log to standard error instead of files
Default: true
Run-time configurable: yes
#### core.klog.skipHeaders
If true, avoid header prefixes in the log messages.
Default: false
Run-time configurable: yes
#### core.klog.skipLogHeaders
If true, avoid headers when opening log files.
Default: false
Run-time configurable: no
#### core.klog.stderrthreshold
Logs at or above this threshold go to stderr (default 2)
Run-time configurable: yes
#### core.klog.v
Number for the log level verbosity.
Default: 0
Run-time configurable: yes
#### core.klog.vmodule
Comma-separated list of `pattern=N` settings for file-filtered logging.
Default: *empty*
Run-time configurable: yes
## sources
The `sources` section contains feature source specific configuration parameters.

View file

@ -156,6 +156,21 @@ data:
# noPublish: false
# sleepInterval: 60s
# sources: [all]
# 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-worker restart to take effect after being changed
# logDir:
# logFile:
# logFileMaxSize: 1800
# skipLogHeaders: false
#sources:
# cpu:
# cpuid:

View file

@ -118,6 +118,21 @@ data:
# noPublish: false
# sleepInterval: 60s
# sources: [all]
# 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-worker restart to take effect after being changed
# logDir:
# logFile:
# logFileMaxSize: 1800
# skipLogHeaders: false
#sources:
# cpu:
# cpuid:

View file

@ -128,6 +128,21 @@ data:
# noPublish: false
# sleepInterval: 60s
# sources: [all]
# 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-worker restart to take effect after being changed
# logDir:
# logFile:
# logFileMaxSize: 1800
# skipLogHeaders: false
#sources:
# cpu:
# cpuid:

View file

@ -3,6 +3,21 @@
# noPublish: false
# sleepInterval: 60s
# sources: [all]
# 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-worker restart to take effect after being changed
# logDir:
# logFile:
# logFileMaxSize: 1800
# skipLogHeaders: false
#sources:
# cpu:
# cpuid:

View file

@ -66,6 +66,7 @@ type NFDConfig struct {
}
type coreConfig struct {
Klog map[string]string
LabelWhiteList utils.RegexpVal
NoPublish bool
Sources []string
@ -88,6 +89,7 @@ type Args struct {
Server string
ServerNameOverride string
Klog map[string]*utils.KlogFlagVal
Overrides ConfigOverrideArgs
}
@ -209,6 +211,7 @@ func newDefaultConfig() *NFDConfig {
LabelWhiteList: utils.RegexpVal{Regexp: *regexp.MustCompile("")},
SleepInterval: duration{60 * time.Second},
Sources: []string{"all"},
Klog: make(map[string]string),
},
}
}
@ -384,8 +387,26 @@ func (c *coreConfig) sanitize() {
}
}
func (w *nfdWorker) configureCore(c coreConfig) {
// Determine enabled feature sourcds
func (w *nfdWorker) configureCore(c coreConfig) error {
// Handle klog
for k, a := range w.args.Klog {
if !a.IsSetFromCmdline() {
v, ok := c.Klog[k]
if !ok {
v = a.DefValue()
}
if err := a.SetFromConfig(v); err != nil {
return err
}
}
}
for k := range c.Klog {
if _, ok := w.args.Klog[k]; !ok {
klog.Warningf("unknown logger option in config: %q", k)
}
}
// Determine enabled feature sources
sourceList := map[string]struct{}{}
all := false
for _, s := range c.Sources {
@ -416,6 +437,7 @@ func (w *nfdWorker) configureCore(c coreConfig) {
}
klog.Warningf("skipping unknown source(s) %q specified in core.sources (or --sources)", strings.Join(names, ", "))
}
return nil
}
// Parse configuration options
@ -468,7 +490,9 @@ func (w *nfdWorker) configure(filepath string, overrides string) error {
w.config = c
w.configureCore(c.Core)
if err := w.configureCore(c.Core); err != nil {
return err
}
// (Re-)configure all "real" sources, test sources are not configurable
for _, s := range allSources {

View file

@ -18,6 +18,7 @@ package utils
import (
"encoding/json"
"flag"
"fmt"
"regexp"
"sort"
@ -98,3 +99,64 @@ func (a *StringSliceVal) String() string {
}
return strings.Join(*a, ",")
}
// KlogFlagVal is a wrapper to allow dynamic control of klog from the config file
type KlogFlagVal struct {
flag *flag.Flag
isSetFromCmdLine bool
}
// Set implements flag.Value interface
func (k *KlogFlagVal) Set(value string) error {
k.isSetFromCmdLine = true
return k.flag.Value.Set(value)
}
// String implements flag.Value interface
func (k *KlogFlagVal) String() string {
if k.flag == nil {
return ""
}
// Need to handle "log_backtrace_at" in a special way
s := k.flag.Value.String()
if k.flag.Name == "log_backtrace_at" && s == ":0" {
s = ""
}
return s
}
// DefValue returns the default value of KlogFlagVal as string
func (k *KlogFlagVal) DefValue() string {
// Need to handle "log_backtrace_at" in a special way
d := k.flag.DefValue
if k.flag.Name == "log_backtrace_at" && d == ":0" {
d = ""
}
return d
}
// SetFromConfig sets the value without marking it as set from the cmdline
func (k *KlogFlagVal) SetFromConfig(value string) error {
return k.flag.Value.Set(value)
}
// IsSetFromCmdline returns true if the value has been set via Set()
func (k *KlogFlagVal) IsSetFromCmdline() bool { return k.isSetFromCmdLine }
// IsBoolFlag implements flag.boolFlag.IsBoolFlag() for wrapped klog flags.
func (k *KlogFlagVal) IsBoolFlag() bool {
if ba, ok := k.flag.Value.(boolFlag); ok {
return ba.IsBoolFlag()
}
return false
}
// NewKlogFlagVal wraps a klog flag into KlogFlagVal type
func NewKlogFlagVal(f *flag.Flag) *KlogFlagVal {
return &KlogFlagVal{flag: f}
}
// boolFlag replicates boolFlag interface internal to the flag package
type boolFlag interface {
IsBoolFlag() bool
}