Skip to content

Commit d0efc46

Browse files
NHDalyvtjnash
andauthored
Add try/catch around handle_message() to catch errors during logging. (JuliaLang#57004) (#204)
Fixes JuliaLang#56889. Before this PR, an exception thrown while constructing the objects to log (the `msg`) would be caught and logged. However, an exception thrown while _printing_ the msg to an IO would _not_ be caught, and can abort the program. This breaks the promise that enabling verbose debug logging shouldn't introduce new crashes. After this PR, an exception thrown during handle_message is caught and logged, just like an exception during `msg` construction: ```julia julia> struct Foo end julia> Base.show(::IO, ::Foo) = error("oh no") julia> begin # Unexpectedly, the execption thrown while printing `Foo()` escapes @info Foo() # So we never reach this line! :'( println("~~~~~ ALL DONE ~~~~~~~~") end ┌ Error: Exception while generating log record in module Main at REPL[10]:3 │ exception = │ oh no │ Stacktrace: │ [1] error(s::String) │ @ Base ./error.jl:44 │ [2] show(::IOBuffer, ::Foo) │ @ Main ./REPL[9]:1 ... │ [30] repl_main │ @ ./client.jl:593 [inlined] │ [31] _start() │ @ Base ./client.jl:568 └ @ Main REPL[10]:3 ~~~~~ ALL DONE ~~~~~~~~ ``` This PR respects the change made in JuliaLang#36600 to keep the codegen as small as possible, by putting the new try/catch into a no-inlined function, so that we don't have to introduce a new try/catch in the macro-generated code body. --------- Co-authored-by: Jameson Nash <[email protected]>
1 parent 4fdcc11 commit d0efc46

File tree

2 files changed

+26
-1
lines changed

2 files changed

+26
-1
lines changed

base/logging.jl

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ function logmsg_code(_module, file, line, level, message, exs...)
398398
end
399399
line = $(log_data._line)
400400
local msg, kwargs
401-
$(logrecord) && invokelatest($handle_message,
401+
$(logrecord) && $handle_message_nothrow(
402402
logger, level, msg, _module, group, id, file, line;
403403
kwargs...)
404404
end
@@ -409,6 +409,18 @@ function logmsg_code(_module, file, line, level, message, exs...)
409409
end
410410
end
411411

412+
@noinline function handle_message_nothrow(logger, level, msg, _module, group, id, file, line; kwargs...)
413+
@nospecialize
414+
try
415+
@invokelatest handle_message(
416+
logger, level, msg, _module, group, id, file, line;
417+
kwargs...)
418+
419+
catch err
420+
@invokelatest logging_error(logger, level, _module, group, id, file, line, err, true)
421+
end
422+
end
423+
412424
function process_logmsg_exs(_orig_module, _file, _line, level, message, exs...)
413425
@nospecialize
414426
local _group, _id

test/corelogging.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,19 @@ end
114114
@test only(collect_test_logs(logmsg)[1]).kwargs[:x] === "the y"
115115
end
116116
end
117+
@testset "Log message handle_message exception handling" begin
118+
# Exceptions in log handling (printing) of msg are caught by default.
119+
struct Foo end
120+
Base.show(::IO, ::Foo) = 1 ÷ 0
121+
122+
# We cannot use `@test_logs` here, since test_logs does not actually _print_ the message
123+
# (i.e. it does not invoke handle_message). To test exception handling during printing,
124+
# we have to use `@test_warn` to see what was printed.
125+
@test_warn r"Error: Exception while generating log record in module .*DivideError: integer division error"s @info Foo()
126+
127+
# Exceptions in log handling (printing) of attributes are caught by default
128+
@test_warn r"Error: Exception while generating log record in module .*DivideError: integer division error"s @info "foo" x=Foo()
129+
end
117130

118131
@testset "Special keywords" begin
119132
logger = TestLogger()

0 commit comments

Comments
 (0)