-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Refactor zap around Facility #201
Conversation
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.
This is good stuff - the reduction in repeated logic is great.
To your specific questions:
- I'm uncomfortable making Logger a concrete type; I'd like to keep it an interface an un-export the concrete type. It's not important to me that other folks be able to implement options - it's important that they be able to implement loggers.
- I can be convinced, but right off the bat I don't love the name
Facility
. What do you think aboutCore
? - Perhaps the standard log signature should return an error? That gives the
Facility
a way to pipe information to the logger's error output. - I like the unification of Entry and CheckedMessage, but I don't like the caveat on Write. Let's think more about how to make that type less error-prone. We could take the Java-esque approach of allowing field access only through getters and setters, or we could embed an Entry and a Facility in a CheckedEntry type.
e.Time = _timeNow().UTC() | ||
e.enc = enc | ||
return e | ||
// XXX compat with *CheckedMessage, drop? |
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'm on the fence about this. To me, if e := logger.Check(....); e.OK() { }
is nicer than if e := logger.Check(....); e != nil { }
, but it's less idiomatic. I'm fine with removing this little nicety in favor of painful explicitness.
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.
yeah, go is nothing if not the land of nil checking ;-)
func (e *Entry) Fields() KeyValue { | ||
return e.enc | ||
// Write writes the entry any logger reference stored. This only works if the | ||
// Entry was returned by Logger.Check. |
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.
Let's consider ways to avoid this slight weirdness. Perhaps un-export all fields and provide getters & setters? Then there's no way to get an Entry except to use logger.Check...
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.
Will go the route of a CheckedEntry that embeds a Facility and Entry.
Enabled(Entry) bool | ||
Log(Entry, ...Field) | ||
// XXX idea on how we could restore internal enoding error repuorting: | ||
// SetErrorOutput(ws WriteSyncer) |
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.
Do we need this, or can the logger communicate to the Meta with returned errors?
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.
Great point above, all we need to do is make it Log(Entry, ...Field) error
, then reporting isn't the facilities's concern.
func newIOFacility(enc Encoder, out WriteSyncer) *ioFacility { | ||
if out == nil { | ||
out = newLockedWriteSyncer(os.Stdout) | ||
} |
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.
Do we need this little bit of magic? I'd prefer to keep default settings at the top level if we can.
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.
Fair point, may be best moved to func WriterFacility(Encoder, io.Writer) Facility
|
||
Development bool | ||
Hooks []Hook | ||
ErrorOutput WriteSyncer |
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.
These shoudn't be exported if we're going to make Logger a concrete type; they're not safe to interact with while the Logger is in use.
Haven't traced the code flow in detail, but |
Will introduce |
I'll internalize the After that, the next big rocks to be pushed:
As you can see in this work: f764dcf#diff-133c628d7af54d3a9d7bf19081e3ed57R29 , I already bumped up against this need with the tee-spy tests. |
ecaf1d5
to
3f09d8c
Compare
c633e2e
to
87316ea
Compare
* Shift hook running into Meta * Firm up a convenience Meta.Encode method * Unify time.Now calling, drop test stub
87316ea
to
8006f12
Compare
Updated the lead comment with current status notes. |
eb90a65
to
d61fc60
Compare
b616807
to
76e507a
Compare
Addressed feedback and rebased on latest dev. |
Aside from minor changes, this last push contained:
I punted pre-allocating or carving out any static |
// Write writes the entry to any Facility references stored, returning any | ||
// errors, and returns the CheckedEntry reference to a pool for immediate | ||
// re-use. | ||
func (ce *CheckedEntry) Write(fields ...Field) 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.
I want to point out to reviewers this subtle semantic change:
- prior
(*CheckedMessage).Write
was void return, it internally noted any error - new
(*CheckedEntry).Write
returns the error
Is this okay or should I restore the prior behavior that users of Logger.Check().Write()
don't have to handle errors?
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'd prefer to restore the previous behavior. To me, it's unreasonable to expect users to handle errors from the logging library.
We can and should pass around errors internally, but I think we should hide them from the user.
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.
However, let's take this up in a follow-on PR. This one's gone on long enough :)
Since we know the types of the file name and line number, we don't need to use fmt.Sprintf and pay that allocation cost. We can instead manage a byte slice ourselves, which saves a few small allocations. (Eventually, we should pool these byte buffers to save a further allocation.)
@jcorbin - I've tacked on a few commits that clean up some typos and fix up a few uncontroversial bits and pieces. Review at your leisure. Once tests pass, I'm going to merge this PR so that we can move on. Let's address any remaining issues in follow-on PRs (particularly the issue you raised about |
* Add AddCallerSkip option * Improve and expand caller skip test * Fix logger Check v Level-log skipping * logger: drop old Log method; not actually part of the interface since #201
Pivot the zap API significantly to make `Facility` the central extension point. This greatly reduces the surface area for extension authors to implement, and it alters some APIs to make composition more straightforward.
* Add AddCallerSkip option * Improve and expand caller skip test * Fix logger Check v Level-log skipping * logger: drop old Log method; not actually part of the interface since #201
Current state (as of 2016-12-23: done / in review