From c1ceb850301327cc59be8f74540e1fc5677cd110 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Fri, 12 Dec 2025 12:28:56 -0500 Subject: [PATCH 1/3] add ability to customize worker prefix --- src/Distributed.jl | 1 + src/cluster.jl | 42 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/Distributed.jl b/src/Distributed.jl index bb7f123..05f2b4a 100644 --- a/src/Distributed.jl +++ b/src/Distributed.jl @@ -68,6 +68,7 @@ export worker_id_from_socket, cluster_cookie, start_worker, + worker_output_hook, # Used only by shared arrays. check_same_host diff --git a/src/cluster.jl b/src/cluster.jl index b899c1c..6f67389 100644 --- a/src/cluster.jl +++ b/src/cluster.jl @@ -283,15 +283,53 @@ function start_worker(out::IO, cookie::AbstractString=readline(stdin); close_std end +""" + worker_output_hook + +A `Ref` holding an optional callback function for customizing worker output display. +When set to a function `f(ident::AbstractString, line::AbstractString) -> Bool`, +it will be called for each line of worker output. If the function returns `true`, +the line is considered handled and will not be printed with the default prefix. +If the function returns `false` or if `worker_output_hook[]` is `nothing`, +the default `"From worker \$ident: "` prefix is used. + +This allows test harnesses or other callers to provide richer context about +what each worker is doing (e.g., which test is running) instead of just the worker id. + +# Example +```julia +Distributed.worker_output_hook[] = (ident, line) -> begin + test_name = get_current_test_for_worker(parse(Int, ident)) + if test_name !== nothing + println("[", test_name, "] (worker ", ident, "): ", line) + return true + end + return false +end +``` +""" +const worker_output_hook = Ref{Union{Nothing, Function}}(nothing) + function redirect_worker_output(ident, stream) t = @async while !eof(stream) line = readline(stream) - if startswith(line, " From worker ") + if startswith(line, "From worker ") # stdout's of "additional" workers started from an initial worker on a host are not available # on the master directly - they are routed via the initial worker's stdout. println(line) else - println(" From worker $(ident):\t$line") + handled = false + hook = worker_output_hook[] + if hook !== nothing + try + handled = hook(ident, line)::Bool + catch + handled = false + end + end + if !handled + println("From worker $(ident): $line") + end end end errormonitor(t) From d45eda66cfc632a6bbd4c82e708e6a42b127f217 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Fri, 12 Dec 2025 13:32:30 -0500 Subject: [PATCH 2/3] managers: pass ident as string to redirect_worker_output The worker_output_hook API documents that ident is passed as AbstractString, but the connect function in managers.jl was passing the pid as an Int. This caused hooks that expected strings (e.g., using tryparse(Int, ident)) to fail silently. Match the behavior in cluster.jl which already passes "$pid". --- src/managers.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers.jl b/src/managers.jl index a71f166..5fa1a04 100644 --- a/src/managers.jl +++ b/src/managers.jl @@ -631,7 +631,7 @@ function connect(manager::ClusterManager, pid::Int, config::WorkerConfig) if config.io !== nothing let pid = pid - redirect_worker_output(pid, notnothing(config.io)) + redirect_worker_output("$pid", notnothing(config.io)) end end From 94777c0ef77990ee7e1a775653c8bb34237ae35a Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Thu, 18 Dec 2025 09:22:13 -0500 Subject: [PATCH 3/3] fix --- src/cluster.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cluster.jl b/src/cluster.jl index 6f67389..7051e88 100644 --- a/src/cluster.jl +++ b/src/cluster.jl @@ -328,7 +328,7 @@ function redirect_worker_output(ident, stream) end end if !handled - println("From worker $(ident): $line") + println(" From worker $(ident):\t$line") end end end