Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

logging: redirect closed streams to stderr/stdout #40423

Merged
merged 1 commit into from
Apr 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions base/logging.jl
Original file line number Diff line number Diff line change
Expand Up @@ -611,21 +611,25 @@ attached to the task.
"""
current_logger() = current_logstate().logger

const closed_stream = IOBuffer(UInt8[])
close(closed_stream)

#-------------------------------------------------------------------------------
# SimpleLogger
"""
SimpleLogger(stream=stderr, min_level=Info)
SimpleLogger([stream,] min_level=Info)

Simplistic logger for logging all messages with level greater than or equal to
`min_level` to `stream`.
`min_level` to `stream`. If stream is closed then messages with log level
greater or equal to `Warn` will be logged to `stderr` and below to `stdout`.
"""
struct SimpleLogger <: AbstractLogger
stream::IO
min_level::LogLevel
message_limits::Dict{Any,Int}
end
SimpleLogger(stream::IO=stderr, level=Info) = SimpleLogger(stream, level, Dict{Any,Int}())
SimpleLogger(stream::IO, level=Info) = SimpleLogger(stream, level, Dict{Any,Int}())
SimpleLogger(level=Info) = SimpleLogger(closed_stream, level)

shouldlog(logger::SimpleLogger, level, _module, group, id) =
get(logger.message_limits, id, 1) > 0
Expand All @@ -644,7 +648,11 @@ function handle_message(logger::SimpleLogger, level::LogLevel, message, _module,
remaining > 0 || return
end
buf = IOBuffer()
iob = IOContext(buf, logger.stream)
stream = logger.stream
if !isopen(stream)
stream = level < Warn ? stdout : stderr
end
iob = IOContext(buf, stream)
levelstr = level == Warn ? "Warning" : string(level)
msglines = split(chomp(string(message)::String), '\n')
println(iob, "┌ ", levelstr, ": ", msglines[1])
Expand All @@ -656,10 +664,10 @@ function handle_message(logger::SimpleLogger, level::LogLevel, message, _module,
println(iob, "│ ", key, " = ", val)
end
println(iob, "└ @ ", _module, " ", filepath, ":", line)
write(logger.stream, take!(buf))
write(stream, take!(buf))
nothing
end

_global_logstate = LogState(SimpleLogger(Core.stderr, CoreLogging.Info))
_global_logstate = LogState(SimpleLogger())

end # CoreLogging
23 changes: 17 additions & 6 deletions stdlib/Logging/src/ConsoleLogger.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

"""
ConsoleLogger(stream=stderr, min_level=Info; meta_formatter=default_metafmt,
ConsoleLogger([stream,] min_level=Info; meta_formatter=default_metafmt,
show_limited=true, right_justify=0)

Logger with formatting optimized for readability in a text console, for example
Expand Down Expand Up @@ -30,12 +30,19 @@ struct ConsoleLogger <: AbstractLogger
right_justify::Int
message_limits::Dict{Any,Int}
end
function ConsoleLogger(stream::IO=stderr, min_level=Info;
function ConsoleLogger(stream::IO, min_level=Info;
meta_formatter=default_metafmt, show_limited=true,
right_justify=0)
ConsoleLogger(stream, min_level, meta_formatter,
show_limited, right_justify, Dict{Any,Int}())
end
function ConsoleLogger(min_level=Info;
meta_formatter=default_metafmt, show_limited=true,
right_justify=0)
ConsoleLogger(closed_stream, min_level, meta_formatter,
show_limited, right_justify, Dict{Any,Int}())
end


shouldlog(logger::ConsoleLogger, level, _module, group, id) =
get(logger.message_limits, id, 1) > 0
Expand Down Expand Up @@ -110,12 +117,16 @@ function handle_message(logger::ConsoleLogger, level::LogLevel, message, _module
# Generate a text representation of the message and all key value pairs,
# split into lines.
msglines = [(indent=0, msg=l) for l in split(chomp(string(message)::String), '\n')]
dsize = displaysize(logger.stream)::Tuple{Int,Int}
stream = logger.stream
if !isopen(stream)
stream = level < Warn ? stdout : stderr
end
dsize = displaysize(stream)::Tuple{Int,Int}
nkwargs = length(kwargs)::Int
if nkwargs > hasmaxlog
valbuf = IOBuffer()
rows_per_value = max(1, dsize[1] ÷ (nkwargs + 1 - hasmaxlog))
valio = IOContext(IOContext(valbuf, logger.stream),
valio = IOContext(IOContext(valbuf, stream),
:displaysize => (rows_per_value, dsize[2] - 5),
:limit => logger.show_limited)
for (key, val) in kwargs
Expand All @@ -136,7 +147,7 @@ function handle_message(logger::ConsoleLogger, level::LogLevel, message, _module
color, prefix, suffix = logger.meta_formatter(level, _module, group, id, filepath, line)::Tuple{Union{Symbol,Int},String,String}
minsuffixpad = 2
buf = IOBuffer()
iob = IOContext(buf, logger.stream)
iob = IOContext(buf, stream)
nonpadwidth = 2 + (isempty(prefix) || length(msglines) > 1 ? 0 : length(prefix)+1) +
msglines[end].indent + termlength(msglines[end].msg) +
(isempty(suffix) ? 0 : length(suffix)+minsuffixpad)
Expand Down Expand Up @@ -164,6 +175,6 @@ function handle_message(logger::ConsoleLogger, level::LogLevel, message, _module
println(iob)
end

write(logger.stream, take!(buf))
write(stream, take!(buf))
nothing
end
5 changes: 4 additions & 1 deletion stdlib/Logging/src/Logging.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ for sym in [
@eval const $sym = Base.CoreLogging.$sym
end

using Base.CoreLogging:
closed_stream

export
AbstractLogger,
LogLevel,
Expand Down Expand Up @@ -56,7 +59,7 @@ include("ConsoleLogger.jl")
# handle_message, shouldlog, min_enabled_level, catch_exceptions,

function __init__()
global_logger(ConsoleLogger(stderr))
global_logger(ConsoleLogger())
end

end
32 changes: 30 additions & 2 deletions test/corelogging.jl
Original file line number Diff line number Diff line change
Expand Up @@ -341,15 +341,43 @@ end
String(take!(io))
end

function genmsg_out(level, message, _module, filepath, line; kws...)
fname = tempname()
f = open(fname, "w")
logger = SimpleLogger()
redirect_stdout(f) do
handle_message(logger, level, message, _module, :group, :id,
filepath, line; kws...)
end
close(f)
buf = read(fname)
rm(fname)
String(buf)
end

function genmsg_err(level, message, _module, filepath, line; kws...)
fname = tempname()
f = open(fname, "w")
logger = SimpleLogger()
redirect_stderr(f) do
handle_message(logger, level, message, _module, :group, :id,
filepath, line; kws...)
end
close(f)
buf = read(fname)
rm(fname)
String(buf)
end

# Simple
@test genmsg(Info, "msg", Main, "some/path.jl", 101) ==
@test genmsg_out(Info, "msg", Main, "some/path.jl", 101) ==
"""
┌ Info: msg
└ @ Main some/path.jl:101
"""

# Multiline message
@test genmsg(Warn, "line1\nline2", Main, "some/path.jl", 101) ==
@test genmsg_err(Warn, "line1\nline2", Main, "some/path.jl", 101) ==
"""
┌ Warning: line1
│ line2
Expand Down