-
Notifications
You must be signed in to change notification settings - Fork 301
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
=multiplex #139 more properly handle logLevel in multiplex handler #140
Conversation
e56b909
to
e26592e
Compare
2a7153a
to
af24c58
Compare
logging2.history.assertExist(level: .debug, message: "debug") | ||
logging2.history.assertExist(level: .info, message: "info") | ||
logging2.history.assertExist(level: .warning, message: "warning") | ||
} |
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 test explains the feature
I now realized the current behavior is documented:
but it's admittably a bit weird... not sure what to do here tbh. The current behavior has some upsides (detailed control) but it is somewhat unexpected as witnessed by #139 as well as my going down this rabbit hole. Do we have opinions what do do here @glbrntt @Lukasa (optionally, only if you have time and want to chime in @weissi) @tomerd ? |
Yeah, I think this behavioural change needs to happen. The logical semantics of MultiplexLogHandler, in my mind, would be that its effective log level is the lowest of all log handlers it wraps, and that it only dispatches the messages to log handlers whose actual log level is lower than that of the message. This makes it maximally useful. |
Cool, very much agreed, that's what the current PR brings it to 👍 I'll sanity check the metadata handling again here soon; I guess the semantics could be:
or something like that; rather than the [0] based one |
I agree with what's been said above: the current behaviour is weird; this change introduces the behaviour I would have expected. |
a0e545a
to
d3164d6
Compare
Sources/Logging/Logging.swift
Outdated
/// If the log level is _set_ on a `Logger` backed by an `MultiplexLogHandler` the log level will apply to *all* | ||
/// underlying log handlers. Allowing a logger to still select at what level it wants to log, regardless if the underlying | ||
/// handler is a multiplex or a normal one. If for some reason one might want to not allow changing a log level of a specific | ||
/// handled passed into the multiplex log handler, this is possible by wrapping it in a handler which ignores any log level changes. |
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.
docs and examples on how the log level works
Sources/Logging/Logging.swift
Outdated
/// A query through the multiplex log handler the key `one` naturally returns `handler1`'s value, and a query for `two` | ||
/// naturally returns `handler2`'s value. Querying for the key `all` will return `handler1`'s value, as that handler was indicated | ||
/// "more important" than the second handler. The same rule applies when querying for the `metadata` property of the | ||
/// multiplex log handler - it constructs `Metadata` uniquing values |
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.
docs and examples how metadata works
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 actually had a "smart and configurable" EffectiveMetadataMode
based impl but I stepped back from it for a few hours to re-think and it was getting too complex IMO for what it is -- realistically this is not a "big problem that needs fancy solving" -- normally users just care about setting metadata on things and maybe some handlers have something specific to them, the conflicting cases should be rare and this simple rule is better than slamming more complexity into it.
// I even had an impl which would "collect all values if the same key is present in a few handlers into a logger metadata value Array etc... Way too fancy for what we're looking at I then realized.
|
||
/// Create a `MultiplexLogHandler`. | ||
/// | ||
/// - parameters: | ||
/// - handlers: An array of `LogHandler`s, each of which will receive the log messages sent to this `Logger`. | ||
/// The array must not be empty. | ||
public init(_ handlers: [LogHandler]) { | ||
assert(!handlers.isEmpty) | ||
assert(!handlers.isEmpty, "MultiplexLogHandler.handlers MUST NOT be empty") |
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.
explicit messages always better IMO
Sources/Logging/Logging.swift
Outdated
self.handlers = handlers | ||
self.effectiveLogLevel = MultiplexLogHandler.effectiveLogLevel(handlers.map { $0.logLevel }) | ||
self.effectiveLogLevel = handlers.map({ $0.logLevel }).min() ?? .trace |
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 ?? will never trigger but it's semantically "aha makes sense, we take the lowest" so I prefer that to writing !
here
d3164d6
to
1974886
Compare
effectiveMetadata.reserveCapacity(self.handlers.first!.metadata.count) // !-safe, we always have at least one handler | ||
return self.handlers.reduce(into: effectiveMetadata) { effectiveMetadata, handler in | ||
effectiveMetadata.merge(handler.metadata, uniquingKeysWith: { l, _ in l }) | ||
} |
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.
We pick the "left" over any following ones "first handlers in the list are more important"
return value | ||
} | ||
} | ||
return nil |
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.
Again, implements the "first is most important"
55f9711
to
cdb4869
Compare
I poked at the metadata quite a bit over the weekend and think I've arrived at what is a good tradeoff here. The metadata handling change is: cdb4869 And please see the comments in-line. Short version though: we should not magically rely on the first handler, but we should prefer more-first passed in handler metadata values over latter ones. This is simple to explain and implement without some crazy things (I had some advanced implementations with merge strategies and whatnot, but they ended up feeling wrong in their own ways, so I believe a simple rule like this (see added docs) is a good tradeoff, esp since we should not expect to be hitting this in reality much -- it is the underlying handlers doing their job, and barely anyone should be reading from the logger metadata to "just have a look at it" after all). |
cdb4869
to
003a288
Compare
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.
lgtm
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.
One little grammar nit in a doc comment, otherwise this is a good 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.
Looks good aside from a couple of typos.
Co-authored-by: Cory Benfield <[email protected]> Co-authored-by: George Barnett <[email protected]>
Thanks for the review and cleanups folks 👍 |
Motivation:
Log level handling is a bit too naive in the multiplex handler when underlying loggers have varying levels.
Modifications:
Result: