Skip to content

Commit 677d925

Browse files
committed
Alternative approach to debug logging utilities.
Alternative to what's proposed in #63. In particular, the pieces proposed here include: * More general "verbosity" argument separate and supporing any log level * Convenience macros for passing verbosity (i.e. `@debugv 1 "hey"` => `@debug "hey" verbosity=1`) * A `LevelOverrideLogger` for overriding the level of any nested logger * A convenience `LoggingExtras.with` function for *very* easily passing a temporary log level and/or verbosity while a function is run. My thoughts have evolved here for supporting package developers wishing to have an easy way to support multiple levels of debug verbosity logging. The approach I'm converging on is: * Package devs support accepting a `verbose::Int=0` keyword arg to high-level user-facing API functions; *very early on*, this keyword arg is "handled" by checking the level and wrapping the remaining function body in a `LoggingExtras.with` call to enable verbose debug logging. An important key here is that as a package dev, I *don't* have to thread the `verbose` keyword through a potentially messy nested call graph of a function. I can just wrap the invocation in `LoggingExtras.with` and then sprinkle `@debugv N` calls at any nested depth I'd like. * For users, this also provides an extremely easy/intuitive interface for enabling verbose debug logging. I don't have to fiddle with configuring a logger or messing w/ global state, I just pass `verbose=1` or `verbose=3` and any verbose logs will be written out. If this approach sounds reasonable, I can clean up this PR w/ docs/examples/tests.
1 parent 78df79e commit 677d925

File tree

4 files changed

+66
-1
lines changed

4 files changed

+66
-1
lines changed

src/LoggingExtras.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import Base.CoreLogging:
1010

1111
export TeeLogger, TransformerLogger, FileLogger,
1212
ActiveFilteredLogger, EarlyFilteredLogger, MinLevelLogger,
13-
DatetimeRotatingFileLogger, FormatLogger
13+
DatetimeRotatingFileLogger, FormatLogger,
14+
@debugv, @infov, @warnv, @errorv, @logmsgv
1415

1516
######
1617
# Re export Logging.jl from stdlib
@@ -50,6 +51,9 @@ include("minlevelfiltered.jl")
5051
include("filelogger.jl")
5152
include("formatlogger.jl")
5253
include("datetime_rotation.jl")
54+
include("overridelogger.jl")
55+
include("verbosity.jl")
56+
include("util.jl")
5357
include("deprecated.jl")
5458

5559
end # module

src/overridelogger.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
struct LevelOverrideLogger{T <: AbstractLogger} <: AbstractLogger
2+
level::LogLevel
3+
logger::T
4+
end
5+
6+
7+
handle_message(logger::LevelOverrideLogger, args...; kwargs...) =
8+
handle_message(logger.logger, args...; kwargs...)
9+
10+
function shouldlog(logger::LevelOverrideLogger, level, args...)
11+
level >= logger.level && shouldlog(logger.logger, level, args...)
12+
end
13+
14+
min_enabled_level(logger::LevelOverrideLogger) = logger.level
15+
catch_exceptions(logger::LevelOverrideLogger) = catch_exceptions(logger.logger)

src/util.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
function with(f; level::Union{Int, LogLevel}=Info, verbosity::Int=0)
2+
with_logger(genlogger(level, verbosity)) do
3+
f()
4+
end
5+
end
6+
7+
genlogger(l, v) = ActiveFilteredLogger(
8+
LogVerbosityCheck(v),
9+
TransformerLogger(
10+
args -> merge(args, (kwargs=Base.structdiff(values(args.kwargs), (verbosity=0,)),)),
11+
LevelOverrideLogger(l, current_logger())
12+
)
13+
)
14+
15+
struct LogVerbosityCheck
16+
verbosity::Int
17+
end
18+
19+
function (f::LogVerbosityCheck)(logargs)
20+
kw = values(logargs.kwargs)
21+
return !haskey(kw, :verbosity) || f.verbosity >= kw.verbosity
22+
end

src/verbosity.jl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""Calls @debug with the passed verbosity level"""
2+
macro debugv(verbosity::Int64, msg, exs...)
3+
return esc(:($Base.@debug $msg verbosity=$verbosity $(exs...)))
4+
end
5+
6+
"""Calls @info with the passed verbosity level"""
7+
macro infov(verbosity::Int64, msg, exs...)
8+
return esc(:($Base.@info $msg verbosity=$verbosity $(exs...)))
9+
end
10+
11+
"""Calls @warn with the passed verbosity level"""
12+
macro warnv(verbosity::Int64, msg, exs...)
13+
return esc(:($Base.@warn $msg verbosity=$verbosity $(exs...)))
14+
end
15+
16+
"""Calls @error with the passed verbosity level"""
17+
macro errorv(verbosity::Int64, msg, exs...)
18+
return esc(:($Base.@error $msg verbosity=$verbosity $(exs...)))
19+
end
20+
21+
"""Calls @error with the passed verbosity level"""
22+
macro logmsgv(verbosity::Int64, level, msg, exs...)
23+
return esc(:($Base.@logmsgv $level $msg verbosity=$verbosity $(exs...)))
24+
end

0 commit comments

Comments
 (0)