-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Add WithFatalHook/CheckedEntry.After to replace OnFatal/CheckedEntry.Should #1088
Merged
abhinav
merged 7 commits into
uber-go:master
from
cardil:feature/retcode-from-error-message
Apr 26, 2022
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
5fe5ca9
Deterministic calc of POSIX return code for Fatal
cardil e6465c2
Adjusting to @abhinav review
cardil 39c2ed3
Misc fixes
sywhang 68e4105
coverage is good
sywhang 48f79d3
exit_test: Don't embed "want"
abhinav d247606
TestLoggerWithFatalHook: Simplify
abhinav 7481e89
CheckWriteHook: Simpler interface compliance check
abhinav File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,10 +27,9 @@ import ( | |
"sync" | ||
"time" | ||
|
||
"go.uber.org/multierr" | ||
"go.uber.org/zap/internal/bufferpool" | ||
"go.uber.org/zap/internal/exit" | ||
|
||
"go.uber.org/multierr" | ||
) | ||
|
||
var ( | ||
|
@@ -152,6 +151,13 @@ type Entry struct { | |
Stack string | ||
} | ||
|
||
// CheckWriteHook allows to customize the action to take after a Fatal log entry | ||
// is processed. | ||
type CheckWriteHook interface { | ||
// OnWrite gets invoked when an entry is written | ||
OnWrite(*CheckedEntry, []Field) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It may be useful to document that the fields here are not all fields on the logger, but just the fields specific to the message. |
||
} | ||
|
||
// CheckWriteAction indicates what action to take after a log entry is | ||
// processed. Actions are ordered in increasing severity. | ||
type CheckWriteAction uint8 | ||
|
@@ -164,10 +170,25 @@ const ( | |
WriteThenGoexit | ||
// WriteThenPanic causes a panic after Write. | ||
WriteThenPanic | ||
// WriteThenFatal causes a fatal os.Exit after Write. | ||
// WriteThenFatal causes an os.Exit(1) after Write. | ||
WriteThenFatal | ||
) | ||
|
||
// OnWrite implements the OnWrite method to keep CheckWriteAction compatible | ||
// with the new CheckWriteHook interface which deprecates CheckWriteAction. | ||
func (a CheckWriteAction) OnWrite(ce *CheckedEntry, _ []Field) { | ||
switch a { | ||
case WriteThenGoexit: | ||
runtime.Goexit() | ||
case WriteThenPanic: | ||
panic(ce.Message) | ||
case WriteThenFatal: | ||
exit.Exit() | ||
} | ||
} | ||
|
||
var _ CheckWriteHook = CheckWriteAction(0) | ||
|
||
// CheckedEntry is an Entry together with a collection of Cores that have | ||
// already agreed to log it. | ||
// | ||
|
@@ -178,15 +199,15 @@ type CheckedEntry struct { | |
Entry | ||
ErrorOutput WriteSyncer | ||
dirty bool // best-effort detection of pool misuse | ||
should CheckWriteAction | ||
after CheckWriteHook | ||
cores []Core | ||
} | ||
|
||
func (ce *CheckedEntry) reset() { | ||
ce.Entry = Entry{} | ||
ce.ErrorOutput = nil | ||
ce.dirty = false | ||
ce.should = WriteThenNoop | ||
ce.after = nil | ||
for i := range ce.cores { | ||
// don't keep references to cores | ||
ce.cores[i] = nil | ||
|
@@ -224,17 +245,11 @@ func (ce *CheckedEntry) Write(fields ...Field) { | |
ce.ErrorOutput.Sync() | ||
} | ||
|
||
should, msg := ce.should, ce.Message | ||
putCheckedEntry(ce) | ||
|
||
switch should { | ||
case WriteThenPanic: | ||
panic(msg) | ||
case WriteThenFatal: | ||
exit.Exit() | ||
case WriteThenGoexit: | ||
runtime.Goexit() | ||
hook := ce.after | ||
if hook != nil { | ||
hook.OnWrite(ce, fields) | ||
} | ||
putCheckedEntry(ce) | ||
} | ||
|
||
// AddCore adds a Core that has agreed to log this CheckedEntry. It's intended to be | ||
|
@@ -252,11 +267,19 @@ func (ce *CheckedEntry) AddCore(ent Entry, core Core) *CheckedEntry { | |
// Should sets this CheckedEntry's CheckWriteAction, which controls whether a | ||
// Core will panic or fatal after writing this log entry. Like AddCore, it's | ||
// safe to call on nil CheckedEntry references. | ||
// Deprecated: Use After(ent Entry, after CheckWriteHook) instead. | ||
func (ce *CheckedEntry) Should(ent Entry, should CheckWriteAction) *CheckedEntry { | ||
return ce.After(ent, should) | ||
} | ||
|
||
// After sets this CheckEntry's CheckWriteHook, which will be called after this | ||
// log entry has been written. It's safe to call this on nil CheckedEntry | ||
// references. | ||
func (ce *CheckedEntry) After(ent Entry, hook CheckWriteHook) *CheckedEntry { | ||
if ce == nil { | ||
ce = getCheckedEntry() | ||
ce.Entry = ent | ||
} | ||
ce.should = should | ||
ce.after = hook | ||
return ce | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
The documentation should probably call out that users of the logging package expect execution to end at
Fatal
, and so it's recommended that this either:It's pretty common to see code like:
This code would panic, but could be other cases where data ends up getting corrupt etc. It's similar to catching panics, but a little riskier since it doesn't even half execution of the specific goroutine that calls
Fatal
.Should we make it more difficult to allow execution to continue by disallowing
WriteThenNoop
for this case (user can still specify their own hook).One other option is to always
runtime.Goexit
at minimum after anonFatal
, that completely disallows execution to continue for the goroutine callingFatal
, but may be too restrictive, it could simplify testing to allow continue execution after capturing that aFatal
happened, because the test is confident that there's no other logic that would be inadvertently executed.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.
That's fair. Taking a second look, I may have misunderstood the WriteThenNoop hook to mean that it actually allows no-op-ing the Fatal log. But after testing it out, it seems that WriteThenNoop turns into a "os.Exit" as the logic suggests.