New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
contextual logging #108995
contextual logging #108995
Conversation
InitLogs overrides the klog default and turns contextual logging off. This ensures that it is only enabled in Kubernetes commands that explicitly enable it via a feature gate. A feature gate for it gets defined in k8s.io/component-base/logs and is then used by Options.ValidateAndApply. The effect of disabling contextual logging is very limited according to benchmarks with kube-scheduler. The feature gets added anyway to satisfy the PRR recommendation that features should be controllable. The following commands have support for contextual logging: - kube-apiserver - kube-controller-manager - kubelet - kube-scheduler - component-base/logs example Supporting a feature gate check in ValidateAndApply and not in InitLogs is a simplification: changing InitLogs to accept a FeatureGate would have implied changing also component-base/cli.Run. This didn't seem worthwhile because ValidateAndApply already covers the relevant commands.
cmd and feature gate changes lgtm |
/approve will defer lgtm to @serathius |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: liggitt, pohly The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
/retest-required |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/hold cancel
/lgtm
none of my comments are blocking, afaict all of @serathius's feedback was addressed. We can address any remaining issues in a follow-up.
@@ -38,11 +38,15 @@ var ( | |||
// NewJSONLogger creates a new json logr.Logger and its associated | |||
// flush function. The separate error stream is optional and may be nil. | |||
// The encoder config is also optional. | |||
func NewJSONLogger(infoStream, errorStream zapcore.WriteSyncer, encoderConfig *zapcore.EncoderConfig) (logr.Logger, func()) { | |||
func NewJSONLogger(v config.VerbosityLevel, infoStream, errorStream zapcore.WriteSyncer, encoderConfig *zapcore.EncoderConfig) (logr.Logger, func()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that we do have some k8s SIGs projects that vendor this... https://cs.k8s.io/?q=NewJSONLogger&i=nope&files=&excludeFiles=&repos=
We may want to add an action required release note saying that this interface has changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we normally announce API changes in staging repos in the release notes, do we?
It's not relevant for end-users and developers who update their dependencies will notice because their code won't compile anymore, which then can be solved easily by looking at a diff.
@@ -53,13 +57,13 @@ func NewJSONLogger(infoStream, errorStream zapcore.WriteSyncer, encoderConfig *z | |||
encoder := zapcore.NewJSONEncoder(*encoderConfig) | |||
var core zapcore.Core | |||
if errorStream == nil { | |||
core = zapcore.NewCore(encoder, infoStream, zapcore.Level(-127)) | |||
core = zapcore.NewCore(encoder, infoStream, zapV) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding from the zapcore docs is that zapcore.Level(-127)
is almost the lowest possible priority debug level (the lowest being -128).
LevelEnabler decides whether a given logging level is enabled when logging a message.
from https://pkg.go.dev/go.uber.org/zap/zapcore#LevelEnabler ... honestly the off-by-1 was probably a typo.
This change will allow us to shed any logs below the verbosity threshold... makes sense to me.
} else { | ||
highPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { | ||
return lvl >= zapcore.ErrorLevel | ||
return lvl >= zapcore.ErrorLevel && lvl >= zapV |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
n.b. zapcore.ErrorLevel
= 2
https://pkg.go.dev/go.uber.org/zap/zapcore#Level
V=2 is our default log level so passing 0 results in the current k8s default behaviour, higher values = more logs.
}) | ||
lowPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { | ||
return lvl < zapcore.ErrorLevel | ||
return lvl < zapcore.ErrorLevel && lvl >= zapV |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible that a consequence of this is that logs could be escalated to the Error stream when they previously were Info?
Answering my own question: no, not possible, because config.VerbosityLevel
is an unsigned int:
type VerbosityLevel uint32 |
@@ -239,7 +239,7 @@ func TestKlogIntegration(t *testing.T) { | |||
t.Run(tc.name, func(t *testing.T) { | |||
var buffer bytes.Buffer | |||
writer := zapcore.AddSync(&buffer) | |||
logger, _ := NewJSONLogger(writer, nil, nil) | |||
logger, _ := NewJSONLogger(100, writer, nil, nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be good to include a comment on the magic constant 100. I deduced it means we log at V=100, flags above in the test set V=2 or lower.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-> #109194
|
||
// This is the default in Kubernetes. Options.ValidateAndApply | ||
// will override this with the result of a feature gate check. | ||
klog.EnableContextualLogging(false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why set this to false
and not contextualLoggingDefault
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When we reach beta, contextualLoggingDefault will be true. At that point, we'll probably still want the feature to be off in those commands which don't have a feauture gate parameter because then a beta feature would be permanently enabled for them. That seems too soon, we probably only should do that when the feature is GA.
This addresses review feedback from kubernetes#108995 (comment).
This addresses review feedback from kubernetes/kubernetes#108995 (comment). Kubernetes-commit: 7b8d711d0255be17de4e6e6918e8e03120af6ab9
This addresses review feedback from kubernetes#108995 (comment).
What type of PR is this?
/kind feature
What this PR does / why we need it:
This completes the infrastructure support for the contextual logging feature:
Which issue(s) this PR fixes:
Related-to: kubernetes/enhancements#3077
Special notes for your reviewer:
The current implementation of the feature gate uses the approach suggested by @liggitt in #105797 (comment): if the code is meant to use non-default state for the contextual logging feature, a FeatureGate instance must be passed in explicitly.
Because enabling that in cli.Run and logs.InitLogs would be a massive churn, only commands using ValidateAndApply will support contextual logging.
Does this PR introduce a user-facing change?
Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.: