-
-
Notifications
You must be signed in to change notification settings - Fork 2.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
log/experimental_level #357
Conversation
type Config struct { | ||
// Allowed enumerates the accepted log levels. If a log event is encountered | ||
// with a LevelKey set to a value that isn't explicitly allowed, the event | ||
// will be equelched, and ErrSquelched returned. |
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.
s/equelched/squelched/ ?
A good start; could be better. |
Ahoy, @ChrisHines @jstordeur @nelz9999 — this PR represents my vision for leveled logging. To the best of my ability it abides the guidelines set forth in the package log README section about enhancements, though it's certainly possible that I've overlooked something. Thus I'd love some early feedback, in particular things you want to do that seem difficult or impossible with this API, and/or any concerns you have about allocations. |
Also cc: @AlmogBaku for your feedback, if you care to provide it :) |
Also cc: @seh for your feedback, if you care to provide it :) |
Comments from my first reading:
|
logger = log.NewContext(logger).With("caller", log.DefaultCaller) | ||
|
||
level.Info(logger).Log("foo", "bar") | ||
if want, have := `caller=level_test.go:134 level=info foo=bar`, strings.TrimSpace(buf.String()); want != have { |
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.
Oof, this looks brittle... If anyone adds/removes non-zero number of lines above this, the line number will get out of sync.
In general, I really like this as an elegant way of eliding all the different concerns. Thank you! I agree with @ChrisHines that defaulting to squelch non-"level" logs quietly is challenging. Do you think there would be negative impact on inverting I think it would be possible to have |
Thanks for the feedback! Exactly what I needed, thanks.
Yes—and yes to similar feedback from @nelz9999. Upon reflection, I agree. Updated.
It's true. I'd love to be able to do as @nelz9999 suggests and have the level key be part of the config struct. But, the UX of level.Debug(logger).Log is absolutely foundational to this proposal, and I can't think of a way to parameterize the level key in a way that preserves it. I'll keep thinking. For now I've made levelKey an unexported const, as in practice I can't think of many who would want to change it.
Great point. I've also unexported and made const the various fooLevelValues, and changed the AllowFoo vars to functions. This makes the level value strings a bit more difficult to change—users will have to replace the whole value chain, so to speak—but in practice I think no one would actually do that, and it makes things safer, as you note.
Yes! It is. But we've done similar things elsewhere in the project, and the nice thing is when it breaks you know exactly why :) I'm considering if it might be better to have a default-allow, rather than default-deny policy. That would lead to enumerating a Disallowed (c.f. Allowed) set of levels. But I need to think on that a bit more. Also considering if it might make sense to have some way to declare that all un-leveled log events should get a specified level. But that may have too-complex interactions with other decisions that are important for UX. Need to think there, too. |
- Unexport level key and default level values - Migrate Allow vars to functions - By default, un-leveled log events are allowed
d4a3c9d
to
6cabf8e
Compare
So, one of the things I think I'm seeing in both the original But what if the I know this impacts a higher package, but it seems like a very flexible way of allowing arbitrary extensions built on top of the |
Hi, level.Debug(logger).Log("foo", "bar")
//Instead of standard API like
logger.Debug("foo", "bar")
logger = level.New(logger, level.Config{Allowed: level.AllowWarnAndAbove})
//Instead of
logger = level.New(logger, level.Config{Level: level.DEBUG}) I find it a little bit confusing from DX, since the majority of the loggers from any language I know looks pretty similar.. Other Notes
Bottom lineAlthough we have a problem with implementing the log-levels as an implementation of |
@AlmogBaku |
I'm going to merge this as-is so a user can get sort of alpha-style access to it, and I'll start another issue to track iterations, enhancements, or potentially deleting it. Thanks again to everyone! |
Sorry, for that 😞 On Wednesday, 7 September 2016, Peter Bourgon notifications@github.com
www.rimoto.com http://www.rimoto.net/ Almog Baku CTO & Cofounder * |
continue | ||
} | ||
hasLevel = true | ||
if i >= len(keyvals) { |
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.
What is this check for? Unless I'm missing something I believe this is always false.
Please see #368 for an alternate approach. |
Still need to get some more tests and benchmarks in, but this API feels usable.
At the callsite, things work like this.
The filtering comes in at construction time.
The Config object allows precise control over the behavior when callers log without a level, or log with a disallowed level; see that struct for details. And while the level package includes default Debug, Info, Warn, and Error levels, the user is free to define their own level values, provide whatever wrappers they like to the constructors, and define their own helper functions. It's all pretty flat.