Skip to content
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

Merged
merged 83 commits into from
Dec 30, 2016
Merged

Refactor zap around Facility #201

merged 83 commits into from
Dec 30, 2016

Conversation

jcorbin
Copy link
Contributor

@jcorbin jcorbin commented Dec 6, 2016

Current state (as of 2016-12-23: done / in review

Copy link
Contributor

@akshayjshah akshayjshah left a 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:

  1. 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.
  2. I can be convinced, but right off the bat I don't love the name Facility. What do you think about Core?
  3. Perhaps the standard log signature should return an error? That gives the Facility a way to pipe information to the logger's error output.
  4. 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?
Copy link
Contributor

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.

Copy link
Contributor Author

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.
Copy link
Contributor

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...

Copy link
Contributor Author

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)
Copy link
Contributor

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?

Copy link
Contributor Author

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)
}
Copy link
Contributor

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.

Copy link
Contributor Author

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
Copy link
Contributor

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.

@akshayjshah
Copy link
Contributor

Haven't traced the code flow in detail, but Entry definitely escapes to the heap; let's make sure we pool it and have a very clear story for where it's returned to the pool (preferably one that's entirely controlled by the Logger, so implementors of our various interfaces don't have to get pooling right).

@jcorbin
Copy link
Contributor Author

jcorbin commented Dec 6, 2016

Will introduce *CheckedEntry which we can pool and/or verify its heap escape velocity; then Entry will only ever be passed and received by value.

@jcorbin
Copy link
Contributor Author

jcorbin commented Dec 6, 2016

I'll internalize the Logger type to be just logger again, and then re-introduce the Logger type as an interface.

After that, the next big rocks to be pushed:

  • Entry => CheckedEntry split
  • Drop the LevelEnabler from logger; demote it from Option status
  • At least use LevelEnabler in most concrete Facility types; take LevelEnabler as part of the Facility contract if necessary for composition

As you can see in this work: f764dcf#diff-133c628d7af54d3a9d7bf19081e3ed57R29 , I already bumped up against this need with the tee-spy tests.

@jcorbin jcorbin force-pushed the logger_v_meta branch 2 times, most recently from ecaf1d5 to 3f09d8c Compare December 7, 2016 01:12
@jcorbin jcorbin mentioned this pull request Dec 7, 2016
4 tasks
@jcorbin jcorbin force-pushed the logger_v_meta branch 4 times, most recently from c633e2e to 87316ea Compare December 8, 2016 23:21
jcorbin referenced this pull request Dec 9, 2016
* Shift hook running into Meta
* Firm up a convenience Meta.Encode method
* Unify time.Now calling, drop test stub
@jcorbin
Copy link
Contributor Author

jcorbin commented Dec 9, 2016

Updated the lead comment with current status notes.

@jcorbin jcorbin force-pushed the logger_v_meta branch 3 times, most recently from eb90a65 to d61fc60 Compare December 10, 2016 01:30
akshayjshah pushed a commit that referenced this pull request Dec 12, 2016
* add the levelenablerfunc for #201

* add the test for levelenablerfunc #205

* remove the comment in test and change code into the buf.Line()
@jcorbin jcorbin force-pushed the logger_v_meta branch 4 times, most recently from b616807 to 76e507a Compare December 13, 2016 22:42
jcorbin pushed a commit that referenced this pull request Dec 13, 2016
* add the levelenablerfunc for #201

* add the test for levelenablerfunc #205

* remove the comment in test and change code into the buf.Line()
@jcorbin jcorbin changed the base branch from master to dev December 13, 2016 22:43
@jcorbin
Copy link
Contributor Author

jcorbin commented Dec 23, 2016

Addressed feedback and rebased on latest dev.

@jcorbin
Copy link
Contributor Author

jcorbin commented Dec 23, 2016

Aside from minor changes, this last push contained:

  • dropped hook support: addCaller and addStack are now in the canon (please consider the new TODO inside the logger struct)
  • nuked WriterFacility default to stdout
  • made WriterFacility take a WriteSyncer
  • axed Facility.Log; just have logger.Log use Facility.Check all the time
    • this compounded for another win around the new addCaller / addStack shape: we avoid collecting if the Log is actually a noop
  • brought back safeToWrite inside of CheckedEntry

I punted pre-allocating or carving out any static Facility space inside CheckedEntry for future work.

// 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 {
Copy link
Contributor Author

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?

Copy link
Contributor

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.

Copy link
Contributor

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 :)

Joshua T Corbin and others added 6 commits December 23, 2016 10:00
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.)
@akshayjshah
Copy link
Contributor

@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 CheckedEntry.Write returning errors).

@akshayjshah akshayjshah changed the title Refactor zap around Faclity Refactor zap around Facility Dec 30, 2016
@akshayjshah akshayjshah merged commit 3378a0a into dev Dec 30, 2016
jcorbin added a commit that referenced this pull request Jan 10, 2017
* 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
@akshayjshah akshayjshah deleted the logger_v_meta branch January 24, 2017 17:24
akshayjshah pushed a commit that referenced this pull request Feb 15, 2017
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.
akshayjshah pushed a commit that referenced this pull request Feb 15, 2017
* 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants