Skip to content

Commit

Permalink
added log{info,warn} for redirection of messages
Browse files Browse the repository at this point in the history
  • Loading branch information
bjarthur committed May 7, 2016
1 parent c688bac commit 86dc94b
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 19 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ Language changes
* The built-in `NTuple` type has been removed; `NTuple{N,T}` is now
implemented internally as `Tuple{Vararg{T,N}}` ([#11242]).

* `loginfo` and `logwarn` can be used to redirect `info` and `warn` messages,
respectively, either universally or on a per-module/function basis ([#16213]).

Command-line option changes
---------------------------

Expand Down
14 changes: 0 additions & 14 deletions base/docs/helpdb/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3599,13 +3599,6 @@ behavior, including program corruption or segfaults, at any later time.
"""
unsafe_convert

"""
warn(msg)
Display a warning. Argument `msg` is a string describing the warning to be displayed.
"""
warn

"""
erfinv(x)
Expand Down Expand Up @@ -4648,13 +4641,6 @@ multiple of four, this is equivalent to a `copy`.
"""
rotl90(A, k)

"""
info(msg)
Display an informational message. Argument `msg` is a string describing the information to be displayed.
"""
info

"""
eigmin(A)
Expand Down
75 changes: 73 additions & 2 deletions base/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -332,18 +332,77 @@ println_with_color(color::Symbol, msg::AbstractString...) =

## warnings and messages ##

"""
info(msg...)
Display an informational message. Argument `msg` is a string describing the information to be displayed.
See also `loginfo`.
"""
function info(io::IO, msg...; prefix="INFO: ")
println_with_color(info_color(), io, prefix, chomp(string(msg...)))
st = StackTraces.remove_frames!(stacktrace(), :info)[1]
mo = st.outer_linfo.value.def.module
fu = st.func
if !isempty(log_info_to)
if haskey(log_info_to, (mo,fu))
io = log_info_to[(mo,fu)]
elseif haskey(log_info_to, mo)
io = log_info_to[mo]
elseif haskey(log_info_to, nothing)
io = log_info_to[nothing]
end
end
println_with_color(info_color(), io, prefix, chomp(string(msg...)), " ($mo.$fu)")
end
info(msg...; prefix="INFO: ") = info(STDERR, msg..., prefix=prefix)

# print a warning only once

const have_warned = Set()
const log_warn_to = Dict()
const log_info_to = Dict()

"""
logwarn([io [, m [, f]]])
Stream output of warnings to `io`, overriding what was otherwise specified.
Optionally, divert stream only for module `m`, or specifically function `f`
within `m`. See `Base.log_warn_to` for the current set of redirections. Call
`logwarn` with no arguments to reset everything.
"""
logwarn(io::IO, m::Module, f::Symbol) = log_warn_to[(m,f)]=io
logwarn(io::IO, m::Module) = log_warn_to[m]=io
logwarn(io::IO) = log_warn_to[nothing]=io
logwarn() = empty!(log_warn_to)

"""
loginfo([io [, m [, f]]])
Stream output of informational messages to `io`, overriding what was otherwise
specified. Optionally, divert stream only for module `m`, or specifically
function `f` within `m`. See `Base.log_warn_to` for the current set of
redirections. Call `loginfo` with no arguments to reset everything.
"""
loginfo(io::IO, m::Module, f::Symbol) = log_info_to[(m,f)]=io
loginfo(io::IO, m::Module) = log_info_to[m]=io
loginfo(io::IO) = log_info_to[nothing]=io
loginfo() = empty!(log_info_to)

export logwarn, loginfo

warn_once(io::IO, msg...) = warn(io, msg..., once=true)
warn_once(msg...) = warn(STDERR, msg..., once=true)

"""
warn(msg..., [prefix="WARNING: ", once=false, key=nothing, bt=nothing, filename=nothing, lineno::Int=0])
Display a warning. Argument `msg` is a string describing the warning to be
displayed. Set `once` to true and specify a `key` to only display `msg` the
first time `warn` is called. If `bt` is not nothing a backtrace is displayed.
If `filename` is not nothing both it and `lineno` are displayed.
See also `logwarn`.
"""
function warn(io::IO, msg...;
prefix="WARNING: ", once=false, key=nothing, bt=nothing,
filename=nothing, lineno::Int=0)
Expand All @@ -355,7 +414,19 @@ function warn(io::IO, msg...;
(key in have_warned) && return
push!(have_warned, key)
end
print_with_color(warn_color(), io, prefix, str)
st = StackTraces.remove_frames!(stacktrace(), :warn)[1]
mo = st.outer_linfo.value.def.module
fu = st.func
if !isempty(log_warn_to)
if haskey(log_warn_to, (mo,fu))
io = log_warn_to[(mo,fu)]
elseif haskey(log_warn_to, mo)
io = log_warn_to[mo]
elseif haskey(log_warn_to, nothing)
io = log_warn_to[nothing]
end
end
print_with_color(warn_color(), io, prefix, str, " ($mo.$fu)")
if bt !== nothing
show_backtrace(io, bt)
end
Expand Down
22 changes: 19 additions & 3 deletions doc/stdlib/io-network.rst
Original file line number Diff line number Diff line change
Expand Up @@ -464,17 +464,33 @@ Text I/O

``color`` may take any of the values ``:normal``\ , ``:bold``\ , ``:black``\ , ``:blue``\ , ``:cyan``\ , ``:green``\ , ``:magenta``\ , ``:red``\ , ``:white``\ , or ``:yellow``\ .

.. function:: info(msg)
.. function:: info(msg...)

.. Docstring generated from Julia source
Display an informational message. Argument ``msg`` is a string describing the information to be displayed.

.. function:: warn(msg)
See also ``loginfo``\ .

.. function:: warn(msg..., [prefix="WARNING: ", once=false, key=nothing, bt=nothing, filename=nothing, lineno::Int=0])

.. Docstring generated from Julia source
Display a warning. Argument ``msg`` is a string describing the warning to be displayed. Set ``once`` to true and specify a ``key`` to only display ``msg`` the first time ``warn`` is called. If ``bt`` is not nothing a backtrace is displayed. If ``filename`` is not nothing both it and ``lineno`` are displayed.

See also ``logwarn``\ .

.. function:: loginfo([io [, m [, f]]])

.. Docstring generated from Julia source
Stream output of informational messages to ``io``\ , overriding what was otherwise specified. Optionally, divert stream only for module ``m``\ , or specifically function ``f`` within ``m``\ . See ``Base.log_warn_to`` for the current set of redirections. Call ``loginfo`` with no arguments to reset everything.

.. function:: logwarn([io [, m [, f]]])

.. Docstring generated from Julia source
Display a warning. Argument ``msg`` is a string describing the warning to be displayed.
Stream output of warnings to ``io``\ , overriding what was otherwise specified. Optionally, divert stream only for module ``m``\ , or specifically function ``f`` within ``m``\ . See ``Base.log_warn_to`` for the current set of redirections. Call ``logwarn`` with no arguments to reset everything.

.. function:: @printf([io::IOStream], "%Fmt", args...)

Expand Down
47 changes: 47 additions & 0 deletions test/misc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,53 @@ let bt = backtrace()
end
end

module Foo
barw(io) = warn(io,"barw")
poohw(io) = warn(io,"poohw")
bari(io) = info(io,"bari")
poohi(io) = info(io,"poohi")
end

@test contains(sprint(Foo.barw), "WARNING: barw (Foo.barw)")
@test contains(sprint(Foo.poohw), "WARNING: poohw (Foo.poohw)")
@test contains(sprint(io->warn(io,"test")), "WARNING: test (Main")
logwarn(DevNull, Foo, :barw)
@test sprint(Foo.barw) == ""
@test contains(sprint(Foo.poohw), "WARNING: poohw (Foo.poohw)")
@test contains(sprint(io->warn(io,"test")), "WARNING: test (Main")
logwarn(DevNull, Foo)
@test sprint(Foo.barw) == ""
@test sprint(Foo.poohw) == ""
@test contains(sprint(io->warn(io,"test")), "WARNING: test (Main")
logwarn(DevNull)
@test sprint(Foo.barw) == ""
@test sprint(Foo.poohw) == ""
@test sprint(io->warn(io,"test")) == ""
logwarn()
@test contains(sprint(Foo.barw), "WARNING: barw (Foo.barw)")
@test contains(sprint(Foo.poohw), "WARNING: poohw (Foo.poohw)")
@test contains(sprint(io->warn(io,"test")), "WARNING: test (Main")

@test contains(sprint(Foo.bari), "INFO: bari (Foo.bari)")
@test contains(sprint(Foo.poohi), "INFO: poohi (Foo.poohi)")
@test contains(sprint(io->info(io,"test")), "INFO: test (Main")
loginfo(DevNull, Foo, :bari)
@test sprint(Foo.bari) == ""
@test contains(sprint(Foo.poohi), "INFO: poohi (Foo.poohi)")
@test contains(sprint(io->info(io,"test")), "INFO: test (Main")
loginfo(DevNull, Foo)
@test sprint(Foo.bari) == ""
@test sprint(Foo.poohi) == ""
@test contains(sprint(io->info(io,"test")), "INFO: test (Main")
loginfo(DevNull)
@test sprint(Foo.bari) == ""
@test sprint(Foo.poohi) == ""
@test sprint(io->info(io,"test")) == ""
loginfo()
@test contains(sprint(Foo.bari), "INFO: bari (Foo.bari)")
@test contains(sprint(Foo.poohi), "INFO: poohi (Foo.poohi)")
@test contains(sprint(io->info(io,"test")), "INFO: test (Main")

# test assert() method
@test_throws AssertionError assert(false)
let res = assert(true)
Expand Down

0 comments on commit 86dc94b

Please sign in to comment.