Skip to content

Commit

Permalink
add @create_log_macro for easily making log macros
Browse files Browse the repository at this point in the history
  • Loading branch information
IanButterworth committed Dec 29, 2023
1 parent 7a91126 commit a80071e
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 18 deletions.
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ Standard library changes
argument is the output of `bunchkaufman` or `lu` ([#50471]).
* Structured matrices now retain either the axes of the parent (for `Symmetric`/`Hermitian`/`AbstractTriangular`/`UpperHessenberg`), or that of the principal diagonal (for banded matrices) ([#52480]).

#### Logging
* New `@create_log_macro` macro for creating new log macros like `@info`, `@warn` etc. For instance
`@create_log_macro MyLog 1500 :magenta` will create `@mylog` to be used like `@mylog "hello"` which
will show as `┌ MyLog: hello` etc. ([#52196])

#### Printf

#### Profile
Expand Down
35 changes: 31 additions & 4 deletions base/logging.jl
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,10 @@ const AboveMaxLevel = LogLevel( 1000001)
# Global log limiting mechanism for super fast but inflexible global log limiting.
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}}()
const custom_log_levels = Dict{LogLevel,Tuple{Symbol,Union{Symbol,Int}}}()

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")
Expand Down Expand Up @@ -694,4 +692,33 @@ end

_global_logstate = LogState(SimpleLogger())

"""
@create_log_macro(name::Symbol, level::Int, color::Union{Int,Symbol})
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
```
"""
macro create_log_macro(name, level, color)
macro_name = Symbol(lowercase(string(name)))
macro_string = QuoteNode(name)
loglevel = LogLevel(level)
quote
custom_log_levels[$(esc(loglevel))] = ($(macro_string), $(esc(color)))
macro $(esc(macro_name))(exs...)
$logmsg_code(($@_sourceinfo)..., $(esc(loglevel)), exs...)
end
end
end

end # CoreLogging
14 changes: 8 additions & 6 deletions stdlib/Logging/docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion stdlib/Logging/src/ConsoleLogger.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ end
showvalue(io, ex::Exception) = showerror(io, ex)

function default_logcolor(level::LogLevel)
level in keys(custom_log_levels) ? custom_log_levels[level][2]::Symbol :
level in keys(custom_log_levels) ? custom_log_levels[level][2] :
level < Info ? Base.debug_color() :
level < Warn ? Base.info_color() :
level < Error ? Base.warn_color() :
Expand Down
2 changes: 2 additions & 0 deletions stdlib/Logging/src/Logging.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ for sym in [
Symbol("@warn"),
Symbol("@error"),
Symbol("@logmsg"),
Symbol("@create_log_macro"),
:with_logger,
:current_logger,
:global_logger,
Expand Down Expand Up @@ -79,6 +80,7 @@ export
@warn,
@error,
@logmsg,
@create_log_macro,
with_logger,
current_logger,
global_logger,
Expand Down
20 changes: 13 additions & 7 deletions stdlib/Logging/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -280,17 +276,27 @@ end
end

@testset "custom log macro" begin
Logging.custom_log_levels[CustomLog] = ("CustomLog", :magenta)
@test_logs (CustomLog, "a") min_level=CustomLog @customlog "a"
@create_log_macro CustomLog -500 :magenta

llevel = LogLevel(-500)

@test_logs (llevel, "a") min_level=llevel @customlog "a"

buf = IOBuffer()
io = IOContext(buf, :displaysize=>(30,80), :color=>false)
logger = ConsoleLogger(io, CustomLog)
logger = ConsoleLogger(io, llevel)

with_logger(logger) do
@customlog "a"
end
@test occursin("CustomLog: a", String(take!(buf)))

@create_log_macro CustomLog2 1500 1

with_logger(logger) do
@customlog2 "hello"
end
@test occursin("CustomLog2: a", String(take!(buf)))
end

end

0 comments on commit a80071e

Please sign in to comment.