Skip to content

Commit b460537

Browse files
committed
Do not deadlock Logger if handler crashes on sync mode, closes #10420
1 parent 36ec08e commit b460537

File tree

2 files changed

+38
-3
lines changed

2 files changed

+38
-3
lines changed

lib/logger/lib/logger/handler.ex

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,17 @@ defmodule Logger.Handler do
147147
end
148148
end
149149

150-
defp notify(:sync, msg), do: :gen_event.sync_notify(Logger, msg)
151-
defp notify(:async, msg), do: :gen_event.notify(Logger, msg)
150+
defp notify(:sync, msg) do
151+
pid = Process.whereis(Logger)
152+
153+
# If we are within the logger process itself,
154+
# we cannot use sync notify as that will deadlock.
155+
if pid == self(), do: :gen_event.notify(pid, msg), else: :gen_event.sync_notify(pid, msg)
156+
end
157+
158+
defp notify(:async, msg) do
159+
:gen_event.notify(Logger, msg)
160+
end
152161

153162
defp truncate(data, n) when is_list(data) do
154163
Logger.Utils.truncate(data, n)

lib/logger/test/logger_test.exs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ defmodule LoggerTest do
6262
Logger.add_backend({UnknownBackend, :hello})
6363
end
6464

65-
test "logs or writes to stderr on failed backends" do
65+
test "logs or writes to stderr on failed call on async mode" do
6666
assert {:ok, _} = Logger.add_backend({MyBackend, :hello})
6767

6868
assert capture_log(fn ->
@@ -86,6 +86,32 @@ defmodule LoggerTest do
8686
Logger.add_backend(:console)
8787
end
8888

89+
test "logs or writes to stderr on failed call on sync mode" do
90+
Logger.configure(sync_threshold: 0)
91+
assert {:ok, _} = Logger.add_backend({MyBackend, :hello})
92+
93+
assert capture_log(fn ->
94+
:gen_event.call(Logger, {MyBackend, :hello}, :error)
95+
wait_for_handler(Logger, {MyBackend, :hello})
96+
end) =~
97+
":gen_event handler {LoggerTest.MyBackend, :hello} installed in Logger terminating"
98+
99+
assert :ok = Logger.remove_backend(:console)
100+
101+
assert ExUnit.CaptureIO.capture_io(:stderr, fn ->
102+
:gen_event.call(Logger, {MyBackend, :hello}, :error)
103+
wait_for_handler(Logger, {MyBackend, :hello})
104+
end) =~
105+
":gen_event handler {LoggerTest.MyBackend, :hello} installed in Logger terminating"
106+
107+
# Flush logs before reattaching to avoid OTP reports
108+
Logger.flush()
109+
after
110+
Logger.configure(sync_threshold: 20)
111+
Logger.remove_backend({MyBackend, :hello})
112+
Logger.add_backend(:console)
113+
end
114+
89115
test "level/0" do
90116
assert Logger.level() == :debug
91117

0 commit comments

Comments
 (0)