Merge pull request #102431 from serathius/loggingconfig

Use LoggingConfig within LogOptions
This commit is contained in:
Kubernetes Prow Robot 2021-06-16 02:21:59 -07:00 committed by GitHub
commit 71d6a48d3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 70 additions and 46 deletions

View File

@ -30,6 +30,7 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
utilfeature "k8s.io/apiserver/pkg/util/feature"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/logs"
"k8s.io/kubelet/config/v1beta1"
kubeletapis "k8s.io/kubelet/pkg/apis"
"k8s.io/kubernetes/pkg/apis/core"
@ -533,9 +534,7 @@ func AddKubeletConfigFlags(mainfs *pflag.FlagSet, c *kubeletconfig.KubeletConfig
fs.StringSliceVar(&c.EnforceNodeAllocatable, "enforce-node-allocatable", c.EnforceNodeAllocatable, "A comma separated list of levels of node allocatable enforcement to be enforced by kubelet. Acceptable options are 'none', 'pods', 'system-reserved', and 'kube-reserved'. If the latter two options are specified, '--system-reserved-cgroup' and '--kube-reserved-cgroup' must also be set, respectively. If 'none' is specified, no additional options should be set. See https://kubernetes.io/docs/tasks/administer-cluster/reserve-compute-resources/ for more details.")
fs.StringVar(&c.SystemReservedCgroup, "system-reserved-cgroup", c.SystemReservedCgroup, "Absolute name of the top level cgroup that is used to manage non-kubernetes components for which compute resources were reserved via '--system-reserved' flag. Ex. '/system-reserved'. [default='']")
fs.StringVar(&c.KubeReservedCgroup, "kube-reserved-cgroup", c.KubeReservedCgroup, "Absolute name of the top level cgroup that is used to manage kubernetes components for which compute resources were reserved via '--kube-reserved' flag. Ex. '/kube-reserved'. [default='']")
fs.StringVar(&c.Logging.Format, "logging-format", c.Logging.Format, "Sets the log format. Permitted formats: \"text\", \"json\". \nNon-default formats don't honor these flags: --add-dir-header, --alsologtostderr, --log-backtrace-at, --log-dir, --log-file, --log-file-max-size, --logtostderr, --skip-headers, --skip-log-headers, --stderrthreshold, --log-flush-frequency. \nNon-default choices are currently alpha and subject to change without warning.")
fs.BoolVar(&c.Logging.Sanitization, "experimental-logging-sanitization", c.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.`)
logs.BindLoggingFlags(&c.Logging, fs)
// Graduated experimental flags, kept for backward compatibility
fs.BoolVar(&c.KernelMemcgNotification, "experimental-kernel-memcg-notification", c.KernelMemcgNotification, "Use kernelMemcgNotification configuration, this flag will be removed in 1.23.")

View File

@ -434,9 +434,7 @@ 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
// not be generated.
func Run(ctx context.Context, s *options.KubeletServer, kubeDeps *kubelet.Dependencies, featureGate featuregate.FeatureGate) error {
logOption := logs.NewOptions()
logOption.LogFormat = s.Logging.Format
logOption.LogSanitization = s.Logging.Sanitization
logOption := &logs.Options{Config: s.Logging}
logOption.Apply()
// To help debugging, immediately log version
klog.InfoS("Kubelet version", "kubeletVersion", version.Get())

View File

@ -23,6 +23,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
utilvalidation "k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/component-base/logs"
"k8s.io/component-base/metrics"
@ -200,11 +201,8 @@ func ValidateKubeletConfiguration(kc *kubeletconfig.KubeletConfiguration) error
}
allErrors = append(allErrors, metrics.ValidateShowHiddenMetricsVersion(kc.ShowHiddenMetricsForVersion)...)
logOption := logs.NewOptions()
if kc.Logging.Format != "" {
logOption.LogFormat = kc.Logging.Format
if errs := logs.ValidateLoggingConfiguration(&kc.Logging, field.NewPath("logging")); len(errs) > 0 {
allErrors = append(allErrors, errs.ToAggregate().Errors()...)
}
allErrors = append(allErrors, logOption.Validate()...)
return utilerrors.NewAggregate(allErrors)
}

View File

@ -62,6 +62,9 @@ func TestValidateKubeletConfiguration(t *testing.T) {
"CustomCPUCFSQuotaPeriod": true,
"GracefulNodeShutdown": true,
},
Logging: componentbaseconfig.LoggingConfiguration{
Format: "text",
},
}
if allErrors := ValidateKubeletConfiguration(successCase1); allErrors != nil {
t.Errorf("expect no errors, got %v", allErrors)
@ -102,6 +105,9 @@ func TestValidateKubeletConfiguration(t *testing.T) {
FeatureGates: map[string]bool{
"CustomCPUCFSQuotaPeriod": true,
},
Logging: componentbaseconfig.LoggingConfiguration{
Format: "text",
},
}
if allErrors := ValidateKubeletConfiguration(successCase2); allErrors != nil {
t.Errorf("expect no errors, got %v", allErrors)
@ -178,8 +184,11 @@ func TestValidateKubeletConfiguration(t *testing.T) {
CPUCFSQuotaPeriod: metav1.Duration{Duration: 100 * time.Millisecond},
ShutdownGracePeriod: metav1.Duration{Duration: 30 * time.Second},
ShutdownGracePeriodCriticalPods: metav1.Duration{Duration: 60 * time.Second},
Logging: componentbaseconfig.LoggingConfiguration{
Format: "",
},
}
const numErrsErrorCase1 = 28
const numErrsErrorCase1 = 29
if allErrors := ValidateKubeletConfiguration(errorCase1); len(allErrors.(utilerrors.Aggregate).Errors()) != numErrsErrorCase1 {
t.Errorf("expect %d errors, got %v", numErrsErrorCase1, len(allErrors.(utilerrors.Aggregate).Errors()))
}
@ -220,6 +229,9 @@ func TestValidateKubeletConfiguration(t *testing.T) {
"CustomCPUCFSQuotaPeriod": true,
"GracefulNodeShutdown": true,
},
Logging: componentbaseconfig.LoggingConfiguration{
Format: "text",
},
}
const numErrsErrorCase2 = 3
if allErrors := ValidateKubeletConfiguration(errorCase2); len(allErrors.(utilerrors.Aggregate).Errors()) != numErrsErrorCase2 {

View File

@ -24,6 +24,7 @@ import (
"github.com/spf13/pflag"
"k8s.io/klog/v2"
"k8s.io/component-base/config"
json "k8s.io/component-base/logs/json"
)
@ -49,19 +50,17 @@ var supportedLogsFlags = map[string]struct{}{
}
// BindLoggingFlags binds the Options struct fields to a flagset
func BindLoggingFlags(o *Options, fs *pflag.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), ", --"))
formats := fmt.Sprintf(`"%s"`, strings.Join(LogRegistry.List(), `", "`))
fs.StringVar(&o.LogFormat, "logging-format", DefaultLogFormat, 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
LogRegistry.Freeze()
fs.BoolVar(&o.LogSanitization, "experimental-logging-sanitization", o.LogSanitization, `[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.`)
}

View File

@ -17,49 +17,50 @@ limitations under the License.
package logs
import (
"github.com/go-logr/logr"
"github.com/spf13/pflag"
"k8s.io/klog/v2"
"k8s.io/component-base/config"
"k8s.io/component-base/config/v1alpha1"
"k8s.io/component-base/logs/sanitization"
)
// Options has klog format parameters
type Options struct {
LogFormat string
LogSanitization bool
Config config.LoggingConfiguration
}
// NewOptions return new klog options
func NewOptions() *Options {
return &Options{
LogFormat: DefaultLogFormat,
}
c := v1alpha1.LoggingConfiguration{}
v1alpha1.RecommendedLoggingConfiguration(&c)
o := &Options{}
v1alpha1.Convert_v1alpha1_LoggingConfiguration_To_config_LoggingConfiguration(&c, &o.Config, nil)
return o
}
// Validate verifies if any unsupported flag is set
// for non-default logging format
func (o *Options) Validate() []error {
return ValidateLoggingConfiguration(o)
errs := ValidateLoggingConfiguration(&o.Config, nil)
if len(errs) != 0 {
return errs.ToAggregate().Errors()
}
return nil
}
// AddFlags add logging-format flag
func (o *Options) AddFlags(fs *pflag.FlagSet) {
BindLoggingFlags(o, fs)
BindLoggingFlags(&o.Config, fs)
}
// Apply set klog logger from LogFormat type
func (o *Options) Apply() {
// if log format not exists, use nil loggr
loggr, _ := o.Get()
loggr, _ := LogRegistry.Get(o.Config.Format)
klog.SetLogger(loggr)
if o.LogSanitization {
if o.Config.Sanitization {
klog.SetLogFilter(&sanitization.SanitizingFilter{})
}
}
// Get logger with LogFormat field
func (o *Options) Get() (logr.Logger, error) {
return LogRegistry.Get(o.LogFormat)
}

View File

@ -18,11 +18,13 @@ package logs
import (
"bytes"
"fmt"
"testing"
"github.com/spf13/pflag"
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/component-base/config"
)
func TestFlags(t *testing.T) {
@ -48,7 +50,7 @@ func TestOptions(t *testing.T) {
name string
args []string
want *Options
errs []error
errs field.ErrorList
}{
{
name: "Default log format",
@ -63,24 +65,35 @@ func TestOptions(t *testing.T) {
name: "JSON log format",
args: []string{"--logging-format=json"},
want: &Options{
LogFormat: JSONLogFormat,
Config: config.LoggingConfiguration{
Format: JSONLogFormat,
},
},
},
{
name: "log sanitization",
args: []string{"--experimental-logging-sanitization"},
want: &Options{
LogFormat: DefaultLogFormat,
LogSanitization: true,
Config: config.LoggingConfiguration{
Format: DefaultLogFormat,
Sanitization: true,
},
},
},
{
name: "Unsupported log format",
args: []string{"--logging-format=test"},
want: &Options{
LogFormat: "test",
Config: config.LoggingConfiguration{
Format: "test",
},
},
errs: []error{fmt.Errorf("unsupported log format: test")},
errs: field.ErrorList{&field.Error{
Type: "FieldValueInvalid",
Field: "format",
BadValue: "test",
Detail: "Unsupported log format",
}},
},
}
@ -95,7 +108,8 @@ func TestOptions(t *testing.T) {
}
errs := o.Validate()
if !assert.ElementsMatch(t, tc.errs, errs) {
t.Errorf("Wrong Validate() result for %q. expect %v, got %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)
}
})
}

View File

@ -22,20 +22,23 @@ import (
"strings"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/component-base/config"
)
func ValidateLoggingConfiguration(o *Options) []error {
errs := []error{}
if o.LogFormat != DefaultLogFormat {
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, fmt.Errorf("non-default logging format doesn't honor flag: %s", fname))
errs = append(errs, field.Invalid(fldPath.Child("format"), c.Format, fmt.Sprintf("Non-default format doesn't honor flag: %s", fname)))
}
}
}
if _, err := o.Get(); err != nil {
errs = append(errs, fmt.Errorf("unsupported log format: %s", o.LogFormat))
if _, err := LogRegistry.Get(c.Format); err != nil {
errs = append(errs, field.Invalid(fldPath.Child("format"), c.Format, "Unsupported log format"))
}
return errs
}