Skip to content

Commit 0c37f1c

Browse files
committed
Use ProgressMeter to draw progress bars
1 parent cabd0d0 commit 0c37f1c

File tree

4 files changed

+83
-17
lines changed

4 files changed

+83
-17
lines changed

Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ version = "0.1.0"
55

66
[deps]
77
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
8+
ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca"
89

910
[compat]
1011
julia = "1"

src/TerminalLogger.jl

Lines changed: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
TerminalLogger(stream=stderr, min_level=Info; meta_formatter=default_metafmt,
2+
TerminalLogger(stream=stderr, min_level=$ProgressLevel; meta_formatter=default_metafmt,
33
show_limited=true, right_justify=0)
44
55
Logger with formatting optimized for readability in a text console, for example
@@ -28,12 +28,13 @@ struct TerminalLogger <: AbstractLogger
2828
right_justify::Int
2929
message_limits::Dict{Any,Int}
3030
sticky_messages::StickyMessages
31+
bars::Dict{Any,Progress}
3132
end
32-
function TerminalLogger(stream::IO=stderr, min_level=Info;
33+
function TerminalLogger(stream::IO=stderr, min_level=ProgressLevel;
3334
meta_formatter=default_metafmt, show_limited=true,
3435
right_justify=0)
3536
TerminalLogger(stream, min_level, meta_formatter,
36-
show_limited, right_justify, Dict{Any,Int}(), StickyMessages(stream))
37+
show_limited, right_justify, Dict{Any,Int}(), StickyMessages(stream), Dict{Any,Progress}())
3738
end
3839

3940
shouldlog(logger::TerminalLogger, level, _module, group, id) =
@@ -94,6 +95,71 @@ function termlength(str)
9495
return N
9596
end
9697

98+
# Since `ProgressMeter.Progress` requires an integer to update its state,
99+
# we convert `progress` to `fakecount` by `_progress_count * progress`.
100+
const _progress_count = 1000
101+
102+
function handle_progress(logger, message, id, progress)
103+
# Don't do anything when it's already done:
104+
if (progress == "done" || progress >= 1) && !haskey(logger.bars, id)
105+
return
106+
end
107+
108+
try
109+
bar = get!(logger.bars, id) do
110+
Progress(
111+
_progress_count;
112+
dt = -1.0, # bypass time-based throttling
113+
output = IOContext(
114+
IOBuffer(),
115+
:displaysize => displaysize(logger.stream),
116+
:color => get(logger.stream, :color, false),
117+
),
118+
)
119+
end
120+
if message != ""
121+
message = string(message)
122+
if !endswith(message, " ")
123+
message *= " "
124+
end
125+
bar.desc = message
126+
end
127+
128+
# Do what `ProgressMeter.tty_width` does:
129+
#...length of percentage and ETA string with days is 29 characters
130+
bar.barlen = max(0, displaysize(logger.stream)[2] - (length(bar.desc) + 29))
131+
132+
fakecount = if progress == "done" || progress >= 1
133+
_progress_count
134+
elseif progress >= 0
135+
floor(Int, _progress_count * progress)
136+
else
137+
0
138+
end
139+
update!(bar, fakecount)
140+
141+
# Using `stripg` to get rid of `\r` etc.:
142+
msg = lstrip(String(take!(bar.output.io)), '\r')
143+
# Strip off control characters:
144+
i = findlast("\e", msg)
145+
if i !== nothing
146+
msg = msg[1:first(i)-1]
147+
end
148+
149+
if progress == "done" || progress >= 1
150+
pop!(logger.sticky_messages, id)
151+
println(logger.stream, msg)
152+
else
153+
push!(logger.sticky_messages, id => msg)
154+
end
155+
finally
156+
if progress == "done" || progress >= 1
157+
pop!(logger.sticky_messages, id) # redundant (but safe) if no error
158+
pop!(logger.bars, id, nothing)
159+
end
160+
end
161+
end
162+
97163
function handle_message(logger::TerminalLogger, level, message, _module, group, id,
98164
filepath, line; maxlog=nothing, progress=nothing,
99165
sticky=nothing, kwargs...)
@@ -103,6 +169,11 @@ function handle_message(logger::TerminalLogger, level, message, _module, group,
103169
remaining > 0 || return
104170
end
105171

172+
if progress == "done" || progress isa Real
173+
handle_progress(logger, message, id, progress)
174+
return
175+
end
176+
106177
substr(s) = SubString(s, 1, length(s)) # julia 0.6 compat
107178

108179
# Generate a text representation of the message and all key value pairs,
@@ -129,14 +200,6 @@ function handle_message(logger::TerminalLogger, level, message, _module, group,
129200
end
130201
end
131202

132-
if progress !== nothing
133-
if (progress isa Symbol && progress == :done) || progress == 1
134-
sticky = :done
135-
else
136-
sticky = true
137-
end
138-
end
139-
140203
# Format lines as text with appropriate indentation and with a box
141204
# decoration on the left.
142205
color,prefix,suffix = logger.meta_formatter(level, _module, group, id, filepath, line)
@@ -162,12 +225,6 @@ function handle_message(logger::TerminalLogger, level, message, _module, group,
162225
printstyled(iob, prefix, " ", bold=true, color=color)
163226
end
164227
print(iob, " "^indent, msg)
165-
if i == 1 && progress !== nothing
166-
progress = clamp(convert(Float64, progress), 0.0, 1.0)
167-
barfulllen = dsize[2] - length(boxstr) - length(prefix) - indent - length(msg) - 2
168-
barlen = round(Int, barfulllen*progress)
169-
print(iob, ' ', '='^barlen, ' '^(barfulllen-barlen))
170-
end
171228
if i == length(msglines) && !isempty(suffix)
172229
npad = max(0, justify_width - nonpadwidth) + minsuffixpad
173230
print(iob, " "^npad)

src/TerminalLoggers.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,13 @@ using Logging:
77
import Logging:
88
handle_message, shouldlog, min_enabled_level, catch_exceptions
99

10+
using ProgressMeter:
11+
Progress, update!
12+
1013
export TerminalLogger
1114

15+
const ProgressLevel = LogLevel(-1)
16+
1217
include("StickyMessages.jl")
1318
include("TerminalLogger.jl")
1419

test/TerminalLogger.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,4 +225,7 @@ import TerminalLoggers.default_metafmt
225225
\e[36m\e[1m│ \e[22m\e[39mline2
226226
\e[36m\e[1m└ \e[22m\e[39m\e[90mSUFFIX\e[39m
227227
"""
228+
229+
@test genmsg("", progress=0.1, width=60) ==
230+
"Progress: 10%|██▏ | ETA: 0:00:00"
228231
end

0 commit comments

Comments
 (0)