Conversation
Add AbstractLogLevel as the supertype of all log level types. Introduce "log level severity" including a `severity` function which maps any user-defined log level to an integer log level severity. This more cleanly separates out the ordinal notion of log severity from the categorical aspects of the log level. Log levels can be ordered by comparing their severities. This gives a certian type of pre-order which is reflexive, transitive and total, but not antisymmetric. This is the same as the ordering of complex numbers by their magnitude. Change to using `print` rather than `show` for formatting log levels for display. This seems to resolve the old conundrum of "do we print Warn as it appears in the program as "Warn" or in human-friendly form as "Warning""? The early (global) decision about log level filtering within the macro is now lowered to `shouldlog(level)` which is more natural and more customizable.
| """ | ||
| struct LogLevel | ||
| struct LogLevel <: AbstractLogLevel | ||
| level::Int32 |
There was a problem hiding this comment.
Can we just change this to Int?
Or make severity return an Int32
I feel like the overhead of converting it each time is not worth it.
| end | ||
| end | ||
|
|
||
| show(io::IO, level::LogLevel) = print(io, level == Warn ? "Warn" : level) |
| `_module`, `group` and with unique log identifier `id`. | ||
|
|
||
| For very early filtering of custom log levels, users may override | ||
| `shouldlog(level)`. |
There was a problem hiding this comment.
Is there a practical example other than severity(level) >= _min_enabled_severity[]?
There was a problem hiding this comment.
Never mind. I guess one application might be some kind of "zero-cost @debug" like ToggleableAsserts.jl https://discourse.julialang.org/t/ann-toggleableasserts-jl/31291
There was a problem hiding this comment.
You got it, this is exactly what I had in mind!
There was a problem hiding this comment.
By the way, this has been re-invented multiple times, for example https://discourse.julialang.org/t/defensive-programming-assert/8383/11?u=chris_foster :-D
|
I don't have time ATM to review this in detail (sorry). I just went through the OP and the code quickly but it looks good to me. For example, I think recommending
It may be a super nit-picking (in the sense that this doesn't matter in writing the code and docs), but I find it strange to treat the categorical part as the main concept of log level. According to Merriam-Webster one of the meaning is:
So, I think conceptualizing |
|
Thanks @tkf I always appreciate your thoughtful and insightful input. I think we reached consensus in #33418, on the subject of
By default this is true, but I have in mind some "interesting" uses for I was planning to use @oxinabox's write-up from the following comment as a starting point for the documentation: #33418 (comment) |
|
I commented on log "level" because I thought maybe it makes sense to use some other concept instead of "level" if the log level is not really about ordering. But log level is a very familiar concept for those who used other logging systems so I am not sure if it is a good idea to invent something new here. (BTW, |
|
re: depwarn, another way to implement it is: That also compiles away. |
Indeed, this approach has many benefits and of course we'll continue to support it.
In what sense? I don't know of any way this could compile away. What I mean when I say "compile away" is that the compiler is able to optimize code like if shouldlog(stuff...)
more_logging_stuff
endinto something like if false
more_logging_stuff
endvia constant propagation / inlining etc, which then gets removed via dead code elimination. That means that the result of In your example |
|
How about |
|
Thinking about how to use log levels as filtering (ref JuliaLogging/ProgressLogging.jl#9, SciML/DiffEqBase.jl#450), I think it would be nice to have a way to declare the "default value" of supportedby(level::AbstractLogLevel, logger) = true
supports(logger::AbstractLogger, level) = supportedby(level, logger)with real_shouldlog_used_by_the_macro(logger, level, _module, group, id) =
supports(logger, level) && shouldlog(logger, level, _module, group, id)Proposed API
|
|
Oops, posted a half-done comment here by mistake! Re-posting something more complete... this has been languishing because I'm not sure whether we should address the categorical nature of |
This resolves #33418 by implementing something similar to #33418 (comment), but including various improvements which came up in the conversation.
The premise here is that log levels are a combination of two different things:
<applied to their severities.Here I've introduced an
AbstractLogLevelas the appropriate supertype for user defined log levels, and added aseverityfunction which can be applied to any log level to compute the (integer) severity. Theprintfunction is now recommended to compute log level labels from the level instance.This is an improvement on using
my_level = LogLevel(some_int)because it allows custom levels to be represented with an appropriate label in pretty printing, and allows various modules to define custom levels independently without risk of confusion in the logging backends. It's also an improvement over the previous (undocumented) convention of allowing any custom type for a level because theseverityfunction is more clearly defined.Detail
Add AbstractLogLevel as the supertype of all log level types.
Introduce "log level severity" including a
severityfunction whichmaps any user-defined log level to an integer log level severity. This
more cleanly separates out the ordinal notion of log severity from the
categorical aspects of the log level.
Log levels can be ordered by comparing their severities. This gives a
certian type of pre-order which is reflexive, transitive and total, but
not antisymmetric. This is the same as the ordering of complex numbers
by their magnitude.
Change to using
printrather thanshowfor formatting log levels fordisplay. This seems to resolve the old conundrum of "do we print Warn as
it appears in the program as "Warn" or in human-friendly form as
"Warning""?
The early (global) decision about log level filtering within the macro
is now lowered to
shouldlog(level)which is more natural and morecustomizable.
A bug in
ConsoleLoggerwas fixed where custom log levels could not actually be used with it easily.Compatibility
User defined log level types worked previously, but were undocumented and had a less sensible API. Nevertheless, I've attempted to include some fallback definitions so that this older pattern can continue to work. However, I have not
depwarned these fallbacks yet becauseLoggingis still released in lockstep withBaseand this might make it hard for package authors to support both <=1.3 as well as 1.4 (/ 1.5 whenever this gets merged).TODO