diff --git a/stdlib/Distributed/Project.toml b/stdlib/Distributed/Project.toml index ecec870290041..832f3ec1640b6 100644 --- a/stdlib/Distributed/Project.toml +++ b/stdlib/Distributed/Project.toml @@ -2,6 +2,7 @@ name = "Distributed" uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" [deps] +Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b" Sockets = "6462fe0b-24de-5631-8697-dd941f90decc" diff --git a/stdlib/Distributed/src/Distributed.jl b/stdlib/Distributed/src/Distributed.jl index 28933e32e8bb8..a9e8362f4c27e 100644 --- a/stdlib/Distributed/src/Distributed.jl +++ b/stdlib/Distributed/src/Distributed.jl @@ -99,6 +99,7 @@ hash(r::RRID, h::UInt) = hash(r.whence, hash(r.id, h)) ==(r::RRID, s::RRID) = (r.whence==s.whence && r.id==s.id) include("clusterserialize.jl") +include("logger.jl") include("cluster.jl") # cluster setup and management, addprocs include("messages.jl") include("process_messages.jl") # process incoming messages diff --git a/stdlib/Distributed/src/cluster.jl b/stdlib/Distributed/src/cluster.jl index d2cbe55e63270..0899463a68b12 100644 --- a/stdlib/Distributed/src/cluster.jl +++ b/stdlib/Distributed/src/cluster.jl @@ -268,6 +268,7 @@ function start_worker(out::IO, cookie::AbstractString=readline(stdin); close_std # To prevent hanging processes on remote machines, newly launched workers exit if the # master process does not connect in time. check_master_connect() + Logging.global_logger(RemoteLogger(1, Logging.Info)) while true; wait(); end catch err print(stderr, "unhandled exception on $(myid()): $(err)\nexiting.\n") diff --git a/stdlib/Distributed/src/logger.jl b/stdlib/Distributed/src/logger.jl new file mode 100644 index 0000000000000..bf7d0ecf7c48c --- /dev/null +++ b/stdlib/Distributed/src/logger.jl @@ -0,0 +1,23 @@ +import Logging + +struct RemoteLogger <: Logging.AbstractLogger + pid::Int + min_level::Logging.LogLevel +end +function RemoteLogger(pid=1) + RemoteLogger(pid, Logging.Info) +end + +Logging.min_enabled_level(logger::RemoteLogger) = logger.min_level +Logging.shouldlog(logger::RemoteLogger, level, _module, group, id) = true + +# TODO: probably should live in base/logging.jl? +function logmsg(level::Logging.LogLevel, message, _module, _group, _id, _file, _line; kwargs...) + Logging.@logmsg level message _module=_module _group=_group _id=_id _file=_file _line=_line kwargs... +end + +function Logging.handle_message(logger::RemoteLogger, level::Logging.LogLevel, message, _module, _group, _id, + _file, _line; kwargs...) + @nospecialize + remote_do(logmsg, logger.pid, level, message, _module, _group, _id, _file, _line; pid=myid(), kwargs...) +end diff --git a/stdlib/Distributed/test/distributed_exec.jl b/stdlib/Distributed/test/distributed_exec.jl index 43e02c92b5a81..a264a01a17126 100644 --- a/stdlib/Distributed/test/distributed_exec.jl +++ b/stdlib/Distributed/test/distributed_exec.jl @@ -1,6 +1,6 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -using Test, Distributed, Random, Serialization, Sockets +using Test, Distributed, Random, Serialization, Sockets, Logging import Distributed: launch, manage @test cluster_cookie() isa String @@ -1915,6 +1915,18 @@ begin end end +# test logging +w = only(addprocs(1)) +@test_logs (:info, "from pid $w") begin + prev_logger = global_logger(current_logger()) + try + wait(@spawnat w @info("from pid $(myid())")) + finally + global_logger(prev_logger) + end +end +wait(rmprocs([w])) + # Run topology tests last after removing all workers, since a given # cluster at any time only supports a single topology. rmprocs(workers())