From dd1b70605f109c6d32857a772ba901dc91a4f2da Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Thu, 28 Dec 2023 14:11:21 -0500 Subject: [PATCH] add create_log_macro for easily making log macros --- base/logging.jl | 37 +++++++++++++++++++++++++++++--- stdlib/Logging/docs/src/index.md | 14 ++++++------ stdlib/Logging/src/Logging.jl | 2 ++ stdlib/Logging/test/runtests.jl | 11 +++++----- 4 files changed, 50 insertions(+), 14 deletions(-) diff --git a/base/logging.jl b/base/logging.jl index 2d0f27dcff57a4..e57b56a3977eb8 100644 --- a/base/logging.jl +++ b/base/logging.jl @@ -163,11 +163,11 @@ const AboveMaxLevel = LogLevel( 1000001) const _min_enabled_level = Ref{LogLevel}(Debug) # add to this to dict to introduce a log level for printing -# i.e. custom_log_levels[LogLevel(-500)] = ("MyLog", :magenta) -const custom_log_levels = Dict{LogLevel,Tuple{String,Symbol}}() +# i.e. custom_log_levels[LogLevel(-500)] = (:mylog, :magenta) +const custom_log_levels = Dict{LogLevel,Tuple{Symbol,Symbol}}() function show(io::IO, level::LogLevel) - if level in keys(custom_log_levels) print(io, custom_log_levels[level][1]::String) + if level in keys(custom_log_levels) print(io, custom_log_levels[level][1]) elseif level == BelowMinLevel print(io, "BelowMinLevel") elseif level == Debug print(io, "Debug") elseif level == Info print(io, "Info") @@ -694,4 +694,35 @@ end _global_logstate = LogState(SimpleLogger()) +""" + create_log_macro(name::Symbol, level::Int, color::Union{Int,Symbol}=:default) + create_log_macro(name::Symbol, loglevel::LogLevel, color::Union{Int,Symbol}=:default) + +Creates a custom log macro like `@info`, `@warn` etc. with a given `name`, `level` and +`color`. The macro created is named with the lowercase form of `name` but the given form +is used for the printing. + +See `Base.text_colors` for recognized color values. + +```julia-repl +julia> create_log_macro(:MyLog, 200, :magenta) +@mylog (macro with 1 method) + +julia> @mylog "hello" +[ MyLog: hello +``` +""" +function create_log_macro(name::Symbol, loglevel::LogLevel, color::Union{Int,Symbol}=:default) + haskey(Base.text_colors, color) || @warn "Color $(repr(color)) not recognized" + custom_log_levels[loglevel] = (name, color) + macro_name = Symbol(lowercase(string(name))) + @eval begin + macro $macro_name(exs...) + logmsg_code((@_sourceinfo)..., $loglevel, exs...) + end + end +end +create_log_macro(name::Symbol, level::Int, color::Union{Int,Symbol}=:default) = + create_log_macro(name, LogLevel(level), color) + end # CoreLogging diff --git a/stdlib/Logging/docs/src/index.md b/stdlib/Logging/docs/src/index.md index 3b22e055d4365a..38d321eef01bc0 100644 --- a/stdlib/Logging/docs/src/index.md +++ b/stdlib/Logging/docs/src/index.md @@ -70,13 +70,15 @@ automatically extracted. Let's examine the user-defined data first: Often this log-level is unneeded as throwing an exception can convey all the required information. - You can also asign printing styles for custom log levels. For instance: - ``` - MyLog = LogLevel(-500) - custom_log_levels[MyLog] = ("MyLog", :magenta) - macro mylog(exs...) Base.CoreLogging.logmsg_code((Base.CoreLogging.@_sourceinfo)..., MyLog, exs...) end + You can also create logging macros for custom log levels. For instance: + ```julia-repl + julia> using Logging + + julia> create_log_macro(:MyLog, 200, :magenta) + @mylog (macro with 1 method) - @mylog "foo" + julia> @mylog "hello" + [ MyLog: hello ``` * The *message* is an object describing the event. By convention diff --git a/stdlib/Logging/src/Logging.jl b/stdlib/Logging/src/Logging.jl index 287fc3b075079d..c305ed13b5cdd4 100644 --- a/stdlib/Logging/src/Logging.jl +++ b/stdlib/Logging/src/Logging.jl @@ -21,6 +21,7 @@ for sym in [ Symbol("@warn"), Symbol("@error"), Symbol("@logmsg"), + :create_log_macro, :with_logger, :current_logger, :global_logger, @@ -79,6 +80,7 @@ export @warn, @error, @logmsg, + create_log_macro, with_logger, current_logger, global_logger, diff --git a/stdlib/Logging/test/runtests.jl b/stdlib/Logging/test/runtests.jl index 7cbe0b465a0e56..83fd580c05de42 100644 --- a/stdlib/Logging/test/runtests.jl +++ b/stdlib/Logging/test/runtests.jl @@ -6,10 +6,6 @@ import Logging: min_enabled_level, shouldlog, handle_message @noinline func1() = backtrace() -# see "custom log macro" testset -CustomLog = LogLevel(-500) -macro customlog(exs...) Base.CoreLogging.logmsg_code((Base.CoreLogging.@_sourceinfo)..., esc(CustomLog), exs...) end - @testset "Logging" begin @testset "Core" begin @@ -280,7 +276,12 @@ end end @testset "custom log macro" begin - Logging.custom_log_levels[CustomLog] = ("CustomLog", :magenta) + CustomLog = LogLevel(-500) + + # TODO: Figure out how to avoid the need to `var"@customlog" = ` + # Maybe this should be a macro, but I couldn't figure out a macro creating a macro + var"@customlog" = create_log_macro("CustomLog", CustomLog, :magenta) + @test_logs (CustomLog, "a") min_level=CustomLog @customlog "a" buf = IOBuffer()