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
initialize logging after flag parsing + refactor commands #105076
Conversation
/sig instrumentation |
1ee0c2f
to
12e55cf
Compare
12e55cf
to
3dbb7a4
Compare
/remove-sig api-machinery |
go flushForever() | ||
} | ||
|
||
func flushForever() { |
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.
how does this differ from wait.Forever?
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.
wait.Forever
is passed the period once and value changes don't have an effect. This new code looks at the current period each time it needs to decide how long to sleep, therefore changes in that value have an effect.
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.
Oh, now I get what you are doing. Can you add something to that effect to the description of flushForever?
For my knowledge, why/how would someone re-configure a flag? Aren't flags only set once?
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.
Usually yes, although that isn't required. The same flag set could also be used multiple times. The main reason for this change is that the logging is initialized in main() (which makes sense - the sooner the better) and flag parsing happens at a later time when the goroutine is already running.
I've added a comment explaining this.
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.
Should we just require InitLogs to be called after flag parsing? We can recommend calling defer logs.FlushLogs()
in main() ASAP to capture logs for cases where logging isn't setup yet.
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 had considered that, but came to the conclusion that enhancing the implementation is going to be simpler than checking and modifying all places where InitLogs is called.
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 mean... I lean towards the flush frequency not being configurable after startup. How many places would we have to change?
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 just counted 19, in various parts of the code base. Simply from a practical point of view I don't look forward to modify all of those.
But it's not just that. I think the current API with InitLogs
being called as early as possible makes sense. It's easy to use and review in commands ("InitLogs and FlushLogs called in main()? Okay, done."). In the package, it gives us an opportunity to make some changes before log messages are emitted.
return g.duration.String() | ||
} | ||
|
||
func (g *guardedDuration) Set(value string) error { |
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.
Does this implement a particular interface? Or why are these functions needed?
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.
They implement flag.Value resp. pflag.Value methods. There's a type assertion further down (var _ pflag.Value = &guardedDuration{}
). Shall I call that out already as method comment ("Set implements flag.Value.Set", etc.)?
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.
Ah. I just missed it.
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.
Thanks for looking at this. 👍
go flushForever() | ||
} | ||
|
||
func flushForever() { |
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.
wait.Forever
is passed the period once and value changes don't have an effect. This new code looks at the current period each time it needs to decide how long to sleep, therefore changes in that value have an effect.
return g.duration.String() | ||
} | ||
|
||
func (g *guardedDuration) Set(value string) error { |
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.
They implement flag.Value resp. pflag.Value methods. There's a type assertion further down (var _ pflag.Value = &guardedDuration{}
). Shall I call that out already as method comment ("Set implements flag.Value.Set", etc.)?
3dbb7a4
to
b5719b0
Compare
/retest |
Or another alternative: considering that the @serathius @thockin: any comments? |
I think that flag was added for completeness but never exercised (obv.). Logging before flag parsing is problematic for a million reasons. My feeling is that this is now bordering on overly-encapsulated. This flag doesn't mean anything for many log impls so "less is more". We should push the configuration of logging toward |
Don't know, we should ask root level approvers for that (assuming that you prefer to go through one approver vs approver per binary). @dims what's your opinion on this? |
Thanks for running manual tests, my main worry was about about human error, but included script should really help with that. It should allow reviewers/approver verify results on their own. |
/test pull-kubernetes-node-e2e-containerd |
Can we do a followup issue/PR(s) to add automated tests? I don't feel like this is THAT dangerous (famous last words?) to warrant abandoning it, given that we've NEVER had tests on this... |
I can't commit to working on that. For now I've filed #105392. |
/test pull-kubernetes-node-e2e-containerd |
I'll go ahead and approve this but leave a hold - @serathius if you want to discuss more, we can, but @pohly I think we can call for lazy-consensus. If no major objections before @pohly EOD Tuesday, (Europe time, I think) you (@pohly) can drop the hold. Fair? Thanks! /lgtm |
I think that we should be ok with validating this using the script, hope that noone will break us before this is merged. I think we are good to go. |
@pohly: The following test failed, say
Full PR test history. Your PR dashboard. Please help us cut down on flakes by linking to an open issue when you hit one in your PR. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
/retest |
What type of PR is this?
/kind bug
What this PR does / why we need it:
It wasn't documented that InitLogs already uses the log flush frequency, so
some commands have called it before parsing (for example, kubectl in the
original code for logs.go). The
--log-flush-frequency
flag never had an effectin such commands.
Other fixes:
usage text is long, but only print the usage text if the error actually was for
flag parsing.
Parameters with underscores are still accepted.
kube-apiserver --logging-format=json --add-dir-header
now referencesadd-dir-header
instead ofadd_dir_header
.--log-flush-frequency
is not listed anymore in the--logging-format
flag'snon-default formats don't honor these flags
usage text because it will alsowork for non-default formats once it is needed.
cmd/kubelet
: the description of--logging-format
uses hyphens instead ofunderscores for the flags, which now matches what the command is using.
staging/src/k8s.io/component-base/logs/example/cmd
: added logging flags.apiextensions-apiserver
,kube-aggregator
,sample-apiserver
: they no longerprint useless stack traces for
main
and goroutines when command line parsing fails;however, they also don't do that for other errors
Which issue(s) this PR fixes:
There's no bug open for this as far as I know. I found the problem while refactoring the code.
It fixes some things discovered while working the code:
Fixes: #105244
Special notes for your reviewer:
This turned into a major refactoring. Future changes for deprecating klog flags should become simpler.
Does this PR introduce a user-facing change?