Skip to content

Commit 037403c

Browse files
authored
Threadsafe TerminalLogger (#41)
Added a big lock around TerminalLogger state to make it safe to use from multiple threads. Also * Bump version * Fix tests which are now broken on julia 1.6 due to formatting detail of Matrix. * Update CI to run on more recent Julia versions
1 parent 9ed38e2 commit 037403c

File tree

5 files changed

+83
-28
lines changed

5 files changed

+83
-28
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ jobs:
1313
matrix:
1414
version:
1515
- '1.0'
16-
- '1.3'
16+
- '1.6'
17+
- '1'
18+
- 'nightly'
1719
os:
1820
- ubuntu-latest
1921
- macOS-latest

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "TerminalLoggers"
22
uuid = "5d786b92-1e48-4d6f-9151-6b4477ca9bed"
33
authors = ["Chris Foster <[email protected]>"]
4-
version = "0.1.4"
4+
version = "0.1.5"
55

66
[deps]
77
LeftChildRightSiblingTrees = "1d6d02ad-be62-4b6b-8a6d-2f90e265016e"

src/TerminalLogger.jl

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ struct TerminalLogger <: AbstractLogger
3434
message_limits::Dict{Any,Int}
3535
sticky_messages::StickyMessages
3636
bartrees::Vector{Node{ProgressBar}}
37+
lock::ReentrantLock
3738
end
3839
function TerminalLogger(stream::IO=stderr, min_level=ProgressLevel;
3940
meta_formatter=default_metafmt, show_limited=true,
@@ -49,11 +50,15 @@ function TerminalLogger(stream::IO=stderr, min_level=ProgressLevel;
4950
Dict{Any,Int}(),
5051
StickyMessages(stream),
5152
Union{}[],
53+
ReentrantLock()
5254
)
5355
end
5456

55-
shouldlog(logger::TerminalLogger, level, _module, group, id) =
56-
get(logger.message_limits, id, 1) > 0
57+
function shouldlog(logger::TerminalLogger, level, _module, group, id)
58+
lock(logger.lock) do
59+
get(logger.message_limits, id, 1) > 0
60+
end
61+
end
5762

5863
min_enabled_level(logger::TerminalLogger) = logger.min_level
5964

@@ -280,14 +285,19 @@ function handle_message(logger::TerminalLogger, level, message, _module, group,
280285
filepath, line; maxlog=nothing,
281286
sticky=nothing, kwargs...)
282287
if maxlog !== nothing && maxlog isa Integer
283-
remaining = get!(logger.message_limits, id, maxlog)
284-
logger.message_limits[id] = remaining - 1
288+
remaining = 0
289+
lock(logger.lock) do
290+
remaining = get!(logger.message_limits, id, maxlog)
291+
logger.message_limits[id] = remaining - 1
292+
end
285293
remaining > 0 || return
286294
end
287295

288296
progress = asprogress(level, message, _module, group, id, filepath, line; kwargs...)
289297
if progress !== nothing
290-
handle_progress(logger, progress, kwargs)
298+
lock(logger.lock) do
299+
handle_progress(logger, progress, kwargs)
300+
end
291301
return
292302
end
293303

@@ -343,18 +353,21 @@ function handle_message(logger::TerminalLogger, level, message, _module, group,
343353
end
344354

345355
msg = take!(buf)
346-
if sticky !== nothing
347-
# Ensure we see the last message, even if it's :done
348-
push!(logger.sticky_messages, id=>String(msg))
349-
if sticky == :done
350-
pop!(logger.sticky_messages, id)
356+
357+
lock(logger.lock) do
358+
if sticky !== nothing
359+
# Ensure we see the last message, even if it's :done
360+
push!(logger.sticky_messages, id=>String(msg))
361+
if sticky == :done
362+
pop!(logger.sticky_messages, id)
363+
end
364+
else
365+
write(logger.stream, msg)
366+
end
367+
368+
if logger.always_flush
369+
flush(logger.stream)
351370
end
352-
else
353-
write(logger.stream, msg)
354-
end
355-
356-
if logger.always_flush
357-
flush(logger.stream)
358371
end
359372

360373
nothing

test/TerminalLogger.jl

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using TerminalLoggers: default_metafmt, format_message
22

3+
using ProgressLogging
4+
35
@noinline func1() = backtrace()
46

57
function dummy_metafmt(level, _module, group, id, file, line)
@@ -192,8 +194,8 @@ end
192194
┌ PREFIX msg
193195
│ exception =
194196
│ DivideError: integer division error
195-
│ Stacktrace:
196-
[1] func1() at""")
197+
│ Stacktrace:""")
198+
@test occursin("[1] func1", genmsg("msg", exception=(DivideError(),bt)))
197199

198200
# Exception stacks
199201
if VERSION >= v"1.2"
@@ -211,19 +213,21 @@ end
211213
end
212214

213215
@testset "Limiting large data structures" begin
214-
@test genmsg("msg", a=fill(1.00001, 100,100), b=fill(2.00002, 10,10)) ==
216+
a = fill(1.00001, 10,10)
217+
b = fill(2.00002, 10,10)
218+
@test genmsg("msg", a=a, b=b) ==
215219
replace("""
216220
┌ PREFIX msg
217221
│ a =
218-
100×100 Array{Float64,2}:
222+
$(summary(a)):
219223
│ 1.00001 1.00001 1.00001 1.00001 … 1.00001 1.00001 1.00001
220224
│ 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001
221225
│ 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001
222226
│ ⋮ ⋱ EOL
223227
│ 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001
224228
│ 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001
225229
│ b =
226-
10×10 Array{Float64,2}:
230+
$(summary(b)):
227231
│ 2.00002 2.00002 2.00002 2.00002 … 2.00002 2.00002 2.00002
228232
│ 2.00002 2.00002 2.00002 2.00002 2.00002 2.00002 2.00002
229233
│ 2.00002 2.00002 2.00002 2.00002 2.00002 2.00002 2.00002
@@ -237,11 +241,11 @@ end
237241
(VERSION < v"1.4-" ? "EOL" : " EOL")=>""
238242
)
239243
# Limiting the amount which is printed
240-
@test genmsg("msg", a=fill(1.00001, 10,10), show_limited=false) ==
244+
@test genmsg("msg", a=a, show_limited=false) ==
241245
"""
242246
┌ PREFIX msg
243247
│ a =
244-
10×10 Array{Float64,2}:
248+
$(summary(a)):
245249
│ 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001
246250
│ 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001
247251
│ 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001 1.00001
@@ -300,9 +304,8 @@ end
300304

301305
# For non-strings a blank line is added so that any formatting for
302306
# vertical alignment isn't broken
303-
@test format_message([1 2; 3 4], 6, io_ctx) ==
307+
@test format_message(Text(" 1 2\n 3 4"), 6, io_ctx) ==
304308
["",
305-
"2×2 Array{Int64,2}:",
306309
" 1 2",
307310
" 3 4"]
308311
end
@@ -393,4 +396,40 @@ end
393396
Outer 100%\|█+\| Time: .*
394397
"""
395398
end
399+
400+
@static if VERSION >= v"1.3.0"
401+
@testset "Parallel progress" begin
402+
buf = IOBuffer()
403+
io = IOContext(buf, :displaysize=>(30,75), :color=>false)
404+
logger = TerminalLogger(io, Debug)
405+
# Crude multithreading test: generate some contention.
406+
#
407+
# Generate some contention in multi-threaded cases
408+
ntasks = 8
409+
@sync begin
410+
with_logger(logger) do
411+
for i=1:ntasks
412+
Threads.@spawn for j=1:100
413+
@info "XXXX <$i,$j>" maxlog=100
414+
#sleep(0.001)
415+
end
416+
end
417+
end
418+
end
419+
log_str = String(take!(buf))
420+
@test length(findall("XXXX", log_str)) == 100
421+
422+
# Fun test of parallel progress logging to watch interactively:
423+
#=
424+
using ProgressLogging
425+
@sync begin
426+
for i=1:8
427+
Threads.@spawn @progress name="task $i" threshold=0.00005 for j=1:10000
428+
#sleep(0.001)
429+
end
430+
end
431+
end
432+
=#
433+
end
434+
end
396435
end

test/runtests.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ using Test
33

44
using Logging:
55
LogLevel, BelowMinLevel, Debug, Info, Warn, Error, AboveMaxLevel,
6-
shouldlog, handle_message, min_enabled_level, catch_exceptions
6+
shouldlog, handle_message, min_enabled_level, catch_exceptions,
7+
with_logger
78

89
using ProgressLogging: Progress
910
using UUIDs: UUID

0 commit comments

Comments
 (0)