mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 19:01:49 +00:00
Merge pull request #114609 from pohly/log-runtime-verbosity-level
runtime log verbosity level changes
This commit is contained in:
commit
92f0818cf2
@ -153,6 +153,7 @@ github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
|||||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
|
github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||||
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
|
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
|
||||||
|
1
staging/src/k8s.io/apiserver/go.sum
generated
1
staging/src/k8s.io/apiserver/go.sum
generated
@ -166,6 +166,7 @@ github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
|||||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
|
github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||||
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
|
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
|
||||||
|
1
staging/src/k8s.io/cloud-provider/go.sum
generated
1
staging/src/k8s.io/cloud-provider/go.sum
generated
@ -124,6 +124,7 @@ github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
|||||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
|
github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||||
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
|
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
|
||||||
|
@ -19,7 +19,9 @@ package v1
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"math"
|
"math"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -31,6 +33,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
cliflag "k8s.io/component-base/cli/flag"
|
cliflag "k8s.io/component-base/cli/flag"
|
||||||
"k8s.io/component-base/featuregate"
|
"k8s.io/component-base/featuregate"
|
||||||
|
"k8s.io/component-base/logs/internal/setverbositylevel"
|
||||||
"k8s.io/component-base/logs/klogflags"
|
"k8s.io/component-base/logs/klogflags"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -62,18 +65,41 @@ func NewLoggingConfiguration() *LoggingConfiguration {
|
|||||||
// The optional FeatureGate controls logging features. If nil, the default for
|
// The optional FeatureGate controls logging features. If nil, the default for
|
||||||
// these features is used.
|
// these features is used.
|
||||||
func ValidateAndApply(c *LoggingConfiguration, featureGate featuregate.FeatureGate) error {
|
func ValidateAndApply(c *LoggingConfiguration, featureGate featuregate.FeatureGate) error {
|
||||||
return ValidateAndApplyAsField(c, featureGate, nil)
|
return validateAndApply(c, nil, featureGate, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateAndApplyWithOptions is a variant of ValidateAndApply which accepts
|
||||||
|
// additional options beyond those that can be configured through the API. This
|
||||||
|
// is meant for testing.
|
||||||
|
func ValidateAndApplyWithOptions(c *LoggingConfiguration, options *LoggingOptions, featureGate featuregate.FeatureGate) error {
|
||||||
|
return validateAndApply(c, options, featureGate, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen=false
|
||||||
|
|
||||||
|
// LoggingOptions can be used with ValidateAndApplyWithOptions to override
|
||||||
|
// certain global defaults.
|
||||||
|
type LoggingOptions struct {
|
||||||
|
// ErrorStream can be used to override the os.Stderr default.
|
||||||
|
ErrorStream io.Writer
|
||||||
|
|
||||||
|
// InfoStream can be used to override the os.Stdout default.
|
||||||
|
InfoStream io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateAndApplyAsField is a variant of ValidateAndApply that should be used
|
// ValidateAndApplyAsField is a variant of ValidateAndApply that should be used
|
||||||
// when the LoggingConfiguration is embedded in some larger configuration
|
// when the LoggingConfiguration is embedded in some larger configuration
|
||||||
// structure.
|
// structure.
|
||||||
func ValidateAndApplyAsField(c *LoggingConfiguration, featureGate featuregate.FeatureGate, fldPath *field.Path) error {
|
func ValidateAndApplyAsField(c *LoggingConfiguration, featureGate featuregate.FeatureGate, fldPath *field.Path) error {
|
||||||
|
return validateAndApply(c, nil, featureGate, fldPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateAndApply(c *LoggingConfiguration, options *LoggingOptions, featureGate featuregate.FeatureGate, fldPath *field.Path) error {
|
||||||
errs := Validate(c, featureGate, fldPath)
|
errs := Validate(c, featureGate, fldPath)
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
return errs.ToAggregate()
|
return errs.ToAggregate()
|
||||||
}
|
}
|
||||||
return apply(c, featureGate)
|
return apply(c, options, featureGate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate can be used to check for invalid settings without applying them.
|
// Validate can be used to check for invalid settings without applying them.
|
||||||
@ -156,7 +182,7 @@ func featureEnabled(featureGate featuregate.FeatureGate, feature featuregate.Fea
|
|||||||
return enabled
|
return enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
func apply(c *LoggingConfiguration, featureGate featuregate.FeatureGate) error {
|
func apply(c *LoggingConfiguration, options *LoggingOptions, featureGate featuregate.FeatureGate) error {
|
||||||
contextualLoggingEnabled := contextualLoggingDefault
|
contextualLoggingEnabled := contextualLoggingDefault
|
||||||
if featureGate != nil {
|
if featureGate != nil {
|
||||||
contextualLoggingEnabled = featureGate.Enabled(ContextualLogging)
|
contextualLoggingEnabled = featureGate.Enabled(ContextualLogging)
|
||||||
@ -167,8 +193,19 @@ func apply(c *LoggingConfiguration, featureGate featuregate.FeatureGate) error {
|
|||||||
if format.factory == nil {
|
if format.factory == nil {
|
||||||
klog.ClearLogger()
|
klog.ClearLogger()
|
||||||
} else {
|
} else {
|
||||||
log, flush := format.factory.Create(*c)
|
if options == nil {
|
||||||
klog.SetLoggerWithOptions(log, klog.ContextualLogger(contextualLoggingEnabled), klog.FlushLogger(flush))
|
options = &LoggingOptions{
|
||||||
|
ErrorStream: os.Stderr,
|
||||||
|
InfoStream: os.Stdout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log, control := format.factory.Create(*c, *options)
|
||||||
|
if control.SetVerbosityLevel != nil {
|
||||||
|
setverbositylevel.Mutex.Lock()
|
||||||
|
defer setverbositylevel.Mutex.Unlock()
|
||||||
|
setverbositylevel.Callbacks = append(setverbositylevel.Callbacks, control.SetVerbosityLevel)
|
||||||
|
}
|
||||||
|
klog.SetLoggerWithOptions(log, klog.ContextualLogger(contextualLoggingEnabled), klog.FlushLogger(control.Flush))
|
||||||
}
|
}
|
||||||
if err := loggingFlags.Lookup("v").Value.Set(VerbosityLevelPflag(&c.Verbosity).String()); err != nil {
|
if err := loggingFlags.Lookup("v").Value.Set(VerbosityLevelPflag(&c.Verbosity).String()); err != nil {
|
||||||
return fmt.Errorf("internal error while setting klog verbosity: %v", err)
|
return fmt.Errorf("internal error while setting klog verbosity: %v", err)
|
||||||
|
@ -39,14 +39,29 @@ type logFormat struct {
|
|||||||
feature featuregate.Feature
|
feature featuregate.Feature
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen=false
|
||||||
|
|
||||||
|
// RuntimeControl provides operations that aren't available through the normal
|
||||||
|
// Logger or LogSink API.
|
||||||
|
type RuntimeControl struct {
|
||||||
|
// Flush ensures that all in-memory data is written.
|
||||||
|
// May be nil.
|
||||||
|
Flush func()
|
||||||
|
|
||||||
|
// SetVerbosityLevel changes the level for all Logger instances
|
||||||
|
// derived from the initial one. May be nil.
|
||||||
|
//
|
||||||
|
// The parameter is intentionally a plain uint32 instead of
|
||||||
|
// VerbosityLevel to enable implementations that don't need to import
|
||||||
|
// the API (helps avoid circular dependencies).
|
||||||
|
SetVerbosityLevel func(v uint32) error
|
||||||
|
}
|
||||||
|
|
||||||
// LogFormatFactory provides support for a certain additional,
|
// LogFormatFactory provides support for a certain additional,
|
||||||
// non-default log format.
|
// non-default log format.
|
||||||
type LogFormatFactory interface {
|
type LogFormatFactory interface {
|
||||||
// Create returns a logger with the requested configuration.
|
// Create returns a logger with the requested configuration.
|
||||||
// Returning a flush function for the logger is optional.
|
Create(c LoggingConfiguration, o LoggingOptions) (logr.Logger, RuntimeControl)
|
||||||
// If provided, the caller must ensure that it is called
|
|
||||||
// periodically (if desired) and at program exit.
|
|
||||||
Create(c LoggingConfiguration) (log logr.Logger, flush func())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterLogFormat registers support for a new logging format. This must be called
|
// RegisterLogFormat registers support for a new logging format. This must be called
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2022 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 setverbositylevel stores callbacks that will be invoked by logs.GlogLevel.
|
||||||
|
//
|
||||||
|
// This is a separate package to avoid a dependency from
|
||||||
|
// k8s.io/component-base/logs (uses the callbacks) to
|
||||||
|
// k8s.io/component-base/logs/api/v1 (adds them). Not all users of the logs
|
||||||
|
// package also use the API.
|
||||||
|
package setverbositylevel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Mutex controls access to the callbacks.
|
||||||
|
Mutex sync.Mutex
|
||||||
|
|
||||||
|
Callbacks []func(v uint32) error
|
||||||
|
)
|
@ -14,11 +14,11 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package logs
|
package json
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
@ -35,12 +35,32 @@ var (
|
|||||||
timeNow = time.Now
|
timeNow = time.Now
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewJSONLogger creates a new json logr.Logger and its associated
|
type runtime struct {
|
||||||
// flush function. The separate error stream is optional and may be nil.
|
v uint32
|
||||||
// The encoder config is also optional.
|
}
|
||||||
func NewJSONLogger(v logsapi.VerbosityLevel, infoStream, errorStream zapcore.WriteSyncer, encoderConfig *zapcore.EncoderConfig) (logr.Logger, func()) {
|
|
||||||
|
func (r *runtime) ZapV() zapcore.Level {
|
||||||
// zap levels are inverted: everything with a verbosity >= threshold gets logged.
|
// zap levels are inverted: everything with a verbosity >= threshold gets logged.
|
||||||
zapV := -zapcore.Level(v)
|
return -zapcore.Level(atomic.LoadUint32(&r.v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enabled implements the zapcore.LevelEnabler interface.
|
||||||
|
func (r *runtime) Enabled(level zapcore.Level) bool {
|
||||||
|
return level >= r.ZapV()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *runtime) SetVerbosityLevel(v uint32) error {
|
||||||
|
atomic.StoreUint32(&r.v, v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ zapcore.LevelEnabler = &runtime{}
|
||||||
|
|
||||||
|
// NewJSONLogger creates a new json logr.Logger and its associated
|
||||||
|
// control interface. The separate error stream is optional and may be nil.
|
||||||
|
// The encoder config is also optional.
|
||||||
|
func NewJSONLogger(v logsapi.VerbosityLevel, infoStream, errorStream zapcore.WriteSyncer, encoderConfig *zapcore.EncoderConfig) (logr.Logger, logsapi.RuntimeControl) {
|
||||||
|
r := &runtime{v: uint32(v)}
|
||||||
|
|
||||||
if encoderConfig == nil {
|
if encoderConfig == nil {
|
||||||
encoderConfig = &zapcore.EncoderConfig{
|
encoderConfig = &zapcore.EncoderConfig{
|
||||||
@ -57,13 +77,13 @@ func NewJSONLogger(v logsapi.VerbosityLevel, infoStream, errorStream zapcore.Wri
|
|||||||
encoder := zapcore.NewJSONEncoder(*encoderConfig)
|
encoder := zapcore.NewJSONEncoder(*encoderConfig)
|
||||||
var core zapcore.Core
|
var core zapcore.Core
|
||||||
if errorStream == nil {
|
if errorStream == nil {
|
||||||
core = zapcore.NewCore(encoder, infoStream, zapV)
|
core = zapcore.NewCore(encoder, infoStream, r)
|
||||||
} else {
|
} else {
|
||||||
highPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
|
highPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
|
||||||
return lvl >= zapcore.ErrorLevel && lvl >= zapV
|
return lvl >= zapcore.ErrorLevel && r.Enabled(lvl)
|
||||||
})
|
})
|
||||||
lowPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
|
lowPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
|
||||||
return lvl < zapcore.ErrorLevel && lvl >= zapV
|
return lvl < zapcore.ErrorLevel && r.Enabled(lvl)
|
||||||
})
|
})
|
||||||
core = zapcore.NewTee(
|
core = zapcore.NewTee(
|
||||||
zapcore.NewCore(encoder, errorStream, highPriority),
|
zapcore.NewCore(encoder, errorStream, highPriority),
|
||||||
@ -71,8 +91,12 @@ func NewJSONLogger(v logsapi.VerbosityLevel, infoStream, errorStream zapcore.Wri
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
l := zap.New(core, zap.WithCaller(true))
|
l := zap.New(core, zap.WithCaller(true))
|
||||||
return zapr.NewLoggerWithOptions(l, zapr.LogInfoLevel("v"), zapr.ErrorKey("err")), func() {
|
return zapr.NewLoggerWithOptions(l, zapr.LogInfoLevel("v"), zapr.ErrorKey("err")),
|
||||||
l.Sync()
|
logsapi.RuntimeControl{
|
||||||
|
SetVerbosityLevel: r.SetVerbosityLevel,
|
||||||
|
Flush: func() {
|
||||||
|
_ = l.Sync()
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +115,7 @@ func (f Factory) Feature() featuregate.Feature {
|
|||||||
return logsapi.LoggingBetaOptions
|
return logsapi.LoggingBetaOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f Factory) Create(c logsapi.LoggingConfiguration) (logr.Logger, func()) {
|
func (f Factory) Create(c logsapi.LoggingConfiguration, o logsapi.LoggingOptions) (logr.Logger, logsapi.RuntimeControl) {
|
||||||
// We intentionally avoid all os.File.Sync calls. Output is unbuffered,
|
// We intentionally avoid all os.File.Sync calls. Output is unbuffered,
|
||||||
// therefore we don't need to flush, and calling the underlying fsync
|
// therefore we don't need to flush, and calling the underlying fsync
|
||||||
// would just slow down writing.
|
// would just slow down writing.
|
||||||
@ -100,9 +124,9 @@ func (f Factory) Create(c logsapi.LoggingConfiguration) (logr.Logger, func()) {
|
|||||||
// written to the output stream before the process terminates, but
|
// written to the output stream before the process terminates, but
|
||||||
// doesn't need to worry about data not being written because of a
|
// doesn't need to worry about data not being written because of a
|
||||||
// system crash or powerloss.
|
// system crash or powerloss.
|
||||||
stderr := zapcore.Lock(AddNopSync(os.Stderr))
|
stderr := zapcore.Lock(AddNopSync(o.ErrorStream))
|
||||||
if c.Options.JSON.SplitStream {
|
if c.Options.JSON.SplitStream {
|
||||||
stdout := zapcore.Lock(AddNopSync(os.Stdout))
|
stdout := zapcore.Lock(AddNopSync(o.InfoStream))
|
||||||
size := c.Options.JSON.InfoBufferSize.Value()
|
size := c.Options.JSON.InfoBufferSize.Value()
|
||||||
if size > 0 {
|
if size > 0 {
|
||||||
// Prevent integer overflow.
|
// Prevent integer overflow.
|
||||||
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package logs
|
package json
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package logs
|
package json
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package logs
|
package json
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -23,10 +23,12 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
logsapi "k8s.io/component-base/logs/api/v1"
|
logsapi "k8s.io/component-base/logs/api/v1"
|
||||||
|
"k8s.io/component-base/logs/internal/setverbositylevel"
|
||||||
"k8s.io/component-base/logs/klogflags"
|
"k8s.io/component-base/logs/klogflags"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
)
|
)
|
||||||
@ -182,11 +184,26 @@ func NewLogger(prefix string) *log.Logger {
|
|||||||
return log.New(KlogWriter{}, prefix, 0)
|
return log.New(KlogWriter{}, prefix, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GlogSetter is a setter to set glog level.
|
// GlogSetter modifies the verbosity threshold for the entire program.
|
||||||
|
// Some components have HTTP-based APIs for invoking this at runtime.
|
||||||
func GlogSetter(val string) (string, error) {
|
func GlogSetter(val string) (string, error) {
|
||||||
|
v, err := strconv.ParseUint(val, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
var level klog.Level
|
var level klog.Level
|
||||||
if err := level.Set(val); err != nil {
|
if err := level.Set(val); err != nil {
|
||||||
return "", fmt.Errorf("failed set klog.logging.verbosity %s: %v", val, err)
|
return "", fmt.Errorf("failed set klog.logging.verbosity %s: %v", val, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setverbositylevel.Mutex.Lock()
|
||||||
|
defer setverbositylevel.Mutex.Unlock()
|
||||||
|
for _, cb := range setverbositylevel.Callbacks {
|
||||||
|
if err := cb(uint32(v)); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("successfully set klog.logging.verbosity to %s", val), nil
|
return fmt.Sprintf("successfully set klog.logging.verbosity to %s", val), nil
|
||||||
}
|
}
|
||||||
|
114
staging/src/k8s.io/component-base/logs/logs_test.go
Normal file
114
staging/src/k8s.io/component-base/logs/logs_test.go
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2022 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_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/component-base/logs"
|
||||||
|
logsapi "k8s.io/component-base/logs/api/v1"
|
||||||
|
_ "k8s.io/component-base/logs/json/register"
|
||||||
|
"k8s.io/klog/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGlogSetter(t *testing.T) {
|
||||||
|
testcases := map[string]struct {
|
||||||
|
init func(t *testing.T)
|
||||||
|
// write must write at verbosity level 1.
|
||||||
|
write func()
|
||||||
|
}{
|
||||||
|
"klog": {
|
||||||
|
init: func(t *testing.T) {},
|
||||||
|
write: func() {
|
||||||
|
klog.V(1).Info("hello")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"json": {
|
||||||
|
init: func(t *testing.T) {
|
||||||
|
c := logsapi.NewLoggingConfiguration()
|
||||||
|
c.Format = "json"
|
||||||
|
if err := logsapi.ValidateAndApply(c, nil /* feature gates */); err != nil {
|
||||||
|
t.Fatalf("Unexpected error enabling json output: %v", err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
write: func() {
|
||||||
|
klog.Background().V(1).Info("hello")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
init: func(t *testing.T) {
|
||||||
|
c := logsapi.NewLoggingConfiguration()
|
||||||
|
c.Format = "text"
|
||||||
|
if err := logsapi.ValidateAndApply(c, nil /* feature gates */); err != nil {
|
||||||
|
t.Fatalf("Unexpected error enabling text output: %v", err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
write: func() {
|
||||||
|
klog.Background().V(1).Info("hello")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tc := range testcases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
state := klog.CaptureState()
|
||||||
|
t.Cleanup(state.Restore)
|
||||||
|
tmpdir := t.TempDir()
|
||||||
|
tmpfile := path.Join(tmpdir, "stderr.log")
|
||||||
|
oldStderr := os.Stderr
|
||||||
|
defer func() {
|
||||||
|
os.Stderr = oldStderr
|
||||||
|
}()
|
||||||
|
newStderr, err := os.Create(tmpfile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error creating temp file: %v", err)
|
||||||
|
}
|
||||||
|
os.Stderr = newStderr
|
||||||
|
|
||||||
|
tc.init(t)
|
||||||
|
|
||||||
|
// First write with default verbosity level of 0 -> no output.
|
||||||
|
tc.write()
|
||||||
|
klog.Flush()
|
||||||
|
out, err := os.ReadFile(tmpfile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error reading temp file: %v", err)
|
||||||
|
}
|
||||||
|
if len(out) > 0 {
|
||||||
|
t.Fatalf("Info message should have been discarded, got instead:\n%s", string(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increase verbosity at runtime.
|
||||||
|
if _, err := logs.GlogSetter("1"); err != nil {
|
||||||
|
t.Fatalf("Unexpected error setting verbosity level: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now write again -> output.
|
||||||
|
tc.write()
|
||||||
|
klog.Flush()
|
||||||
|
out, err = os.ReadFile(tmpfile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error reading temp file: %v", err)
|
||||||
|
}
|
||||||
|
if len(out) == 0 {
|
||||||
|
t.Fatal("Info message should have been written, got empty file instead.")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
1
staging/src/k8s.io/controller-manager/go.sum
generated
1
staging/src/k8s.io/controller-manager/go.sum
generated
@ -120,6 +120,7 @@ github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
|||||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
|
github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||||
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
|
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
|
||||||
|
1
staging/src/k8s.io/kube-aggregator/go.sum
generated
1
staging/src/k8s.io/kube-aggregator/go.sum
generated
@ -122,6 +122,7 @@ github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
|||||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
|
github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||||
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
|
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
|
||||||
|
1
staging/src/k8s.io/sample-apiserver/go.sum
generated
1
staging/src/k8s.io/sample-apiserver/go.sum
generated
@ -122,6 +122,7 @@ github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
|||||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
|
github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||||
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
|
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
|
||||||
|
@ -32,7 +32,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
|
||||||
logsapi "k8s.io/component-base/logs/api/v1"
|
logsapi "k8s.io/component-base/logs/api/v1"
|
||||||
logsjson "k8s.io/component-base/logs/json"
|
logsjson "k8s.io/component-base/logs/json"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
@ -175,9 +174,6 @@ func benchmarkOutputFormats(b *testing.B, config loadGeneratorConfig, discard bo
|
|||||||
generateOutput(b, config, nil, out)
|
generateOutput(b, config, nil, out)
|
||||||
})
|
})
|
||||||
b.Run("JSON", func(b *testing.B) {
|
b.Run("JSON", func(b *testing.B) {
|
||||||
c := logsapi.NewLoggingConfiguration()
|
|
||||||
var logger logr.Logger
|
|
||||||
var flush func()
|
|
||||||
var out1, out2 *os.File
|
var out1, out2 *os.File
|
||||||
if !discard {
|
if !discard {
|
||||||
var err error
|
var err error
|
||||||
@ -192,38 +188,30 @@ func benchmarkOutputFormats(b *testing.B, config loadGeneratorConfig, discard bo
|
|||||||
}
|
}
|
||||||
defer out2.Close()
|
defer out2.Close()
|
||||||
}
|
}
|
||||||
b.Run("single-stream", func(b *testing.B) {
|
o := logsapi.LoggingOptions{}
|
||||||
if discard {
|
if discard {
|
||||||
logger, flush = logsjson.NewJSONLogger(c.Verbosity, logsjson.AddNopSync(&output), nil, nil)
|
o.ErrorStream = io.Discard
|
||||||
|
o.InfoStream = io.Discard
|
||||||
} else {
|
} else {
|
||||||
stderr := os.Stderr
|
o.ErrorStream = out1
|
||||||
os.Stderr = out1
|
o.InfoStream = out1
|
||||||
defer func() {
|
|
||||||
os.Stderr = stderr
|
|
||||||
}()
|
|
||||||
logger, flush = logsjson.Factory{}.Create(*c)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.Run("single-stream", func(b *testing.B) {
|
||||||
|
c := logsapi.NewLoggingConfiguration()
|
||||||
|
logger, control := logsjson.Factory{}.Create(*c, o)
|
||||||
klog.SetLogger(logger)
|
klog.SetLogger(logger)
|
||||||
defer klog.ClearLogger()
|
defer klog.ClearLogger()
|
||||||
generateOutput(b, config, flush, out1)
|
generateOutput(b, config, control.Flush, out1)
|
||||||
})
|
})
|
||||||
|
|
||||||
b.Run("split-stream", func(b *testing.B) {
|
b.Run("split-stream", func(b *testing.B) {
|
||||||
if discard {
|
|
||||||
logger, flush = logsjson.NewJSONLogger(c.Verbosity, logsjson.AddNopSync(&output), logsjson.AddNopSync(&output), nil)
|
|
||||||
} else {
|
|
||||||
stdout, stderr := os.Stdout, os.Stderr
|
|
||||||
os.Stdout, os.Stderr = out1, out2
|
|
||||||
defer func() {
|
|
||||||
os.Stdout, os.Stderr = stdout, stderr
|
|
||||||
}()
|
|
||||||
c := logsapi.NewLoggingConfiguration()
|
c := logsapi.NewLoggingConfiguration()
|
||||||
c.Options.JSON.SplitStream = true
|
c.Options.JSON.SplitStream = true
|
||||||
logger, flush = logsjson.Factory{}.Create(*c)
|
logger, control := logsjson.Factory{}.Create(*c, o)
|
||||||
}
|
|
||||||
klog.SetLogger(logger)
|
klog.SetLogger(logger)
|
||||||
defer klog.ClearLogger()
|
defer klog.ClearLogger()
|
||||||
generateOutput(b, config, flush, out1, out2)
|
generateOutput(b, config, control.Flush, out1, out2)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
@ -1998,6 +1998,7 @@ k8s.io/component-base/featuregate
|
|||||||
k8s.io/component-base/featuregate/testing
|
k8s.io/component-base/featuregate/testing
|
||||||
k8s.io/component-base/logs
|
k8s.io/component-base/logs
|
||||||
k8s.io/component-base/logs/api/v1
|
k8s.io/component-base/logs/api/v1
|
||||||
|
k8s.io/component-base/logs/internal/setverbositylevel
|
||||||
k8s.io/component-base/logs/json
|
k8s.io/component-base/logs/json
|
||||||
k8s.io/component-base/logs/json/register
|
k8s.io/component-base/logs/json/register
|
||||||
k8s.io/component-base/logs/klogflags
|
k8s.io/component-base/logs/klogflags
|
||||||
|
Loading…
Reference in New Issue
Block a user