Skip to content

Commit 6827431

Browse files
author
José Valim
committed
Merge pull request #2712 from fishcakez/logger_rc
Fix logger watcher race condition
2 parents 88f84f8 + c0a0757 commit 6827431

File tree

3 files changed

+29
-23
lines changed

3 files changed

+29
-23
lines changed

lib/logger/lib/logger/watcher.ex

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ defmodule Logger.Watcher do
99
Starts the watcher supervisor.
1010
"""
1111
def start_link(m, f, a) do
12-
options = [strategy: :one_for_one, name: @name]
13-
case Supervisor.start_link([], options) do
12+
import Supervisor.Spec
13+
child = worker(__MODULE__, [],
14+
[function: :watcher, restart: :transient])
15+
options = [strategy: :simple_one_for_one, name: @name]
16+
case Supervisor.start_link([child], options) do
1417
{:ok, _} = ok ->
1518
_ = for {mod, handler, args} <- apply(m, f, a) do
1619
{:ok, _} = watch(mod, handler, args)
@@ -32,16 +35,9 @@ defmodule Logger.Watcher do
3235
Watches the given handler as part of the watcher supervision tree.
3336
"""
3437
def watch(mod, handler, args) do
35-
import Supervisor.Spec
36-
id = {mod, handler}
37-
child = worker(__MODULE__, [mod, handler, args],
38-
[id: id, function: :watcher, restart: :transient])
39-
case Supervisor.start_child(@name, child) do
38+
case Supervisor.start_child(@name, [mod, handler, args]) do
4039
{:ok, _pid} = result ->
4140
result
42-
{:error, :already_present} ->
43-
_ = Supervisor.delete_child(@name, id)
44-
watch(mod, handler, args)
4541
{:error, _reason} = error ->
4642
error
4743
end
@@ -64,17 +60,28 @@ defmodule Logger.Watcher do
6460
ref = Process.monitor(mod)
6561

6662
case GenEvent.add_handler(mod, handler, args, monitor: true) do
67-
:ok -> {:ok, {mod, handler, ref}}
68-
{:error, :ignore} -> :ignore
69-
{:error, reason} -> {:stop, reason}
63+
:ok ->
64+
{:ok, {mod, handler, ref}}
65+
{:error, :ignore} ->
66+
# Can't return :ignore as a transient child under a simple_one_for_one.
67+
# Instead return ok and then immediately exit normally - using a fake
68+
# message.
69+
send(self(), {:gen_event_EXIT, handler, :normal})
70+
{:ok, {mod, handler, ref}}
71+
{:error, reason} ->
72+
{:stop, reason}
7073
end
7174
end
7275

7376
def init({mod, handler, args, :link}) do
7477
case :gen_event.add_sup_handler(mod, handler, args) do
75-
:ok -> {:ok, {mod, handler, nil}}
76-
{:error, :ignore} -> :ignore
77-
{:error, reason} -> {:stop, reason}
78+
:ok ->
79+
{:ok, {mod, handler, nil}}
80+
{:error, :ignore} ->
81+
send(self(), {:gen_event_EXIT, handler, :normal})
82+
{:ok, {mod, handler, nil}}
83+
{:error, reason} ->
84+
{:stop, reason}
7885
end
7986
end
8087

lib/logger/test/logger/backends/console_test.exs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ defmodule Logger.Backends.ConsoleTest do
1010
end
1111

1212
test "does not start when there is no user" do
13-
Logger.remove_backend(:console)
13+
:ok = Logger.remove_backend(:console)
1414
user = Process.whereis(:user)
1515

1616
try do
@@ -21,7 +21,7 @@ defmodule Logger.Backends.ConsoleTest do
2121
Process.register(user, :user)
2222
end
2323
after
24-
Logger.add_backend(:console)
24+
{:ok, _} = Logger.add_backend(:console)
2525
end
2626

2727
test "can configure format" do

lib/logger/test/logger_test.exs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,9 @@ defmodule LoggerTest do
4040
assert Logger.debug("hello", []) == :ok
4141
end) == ""
4242

43-
assert {:ok, pid} = Logger.add_backend(:console)
43+
assert {:ok, _pid} = Logger.add_backend(:console)
4444
assert Application.get_env(:logger, :backends) == [:console]
45-
assert Logger.add_backend(:console) ==
46-
{:error, {:already_started, pid}}
45+
assert Logger.add_backend(:console) == {:error, :already_added}
4746
assert Application.get_env(:logger, :backends) == [:console]
4847
end
4948

@@ -57,7 +56,7 @@ defmodule LoggerTest do
5756
end
5857

5958
assert {:ok, _} = Logger.add_backend({MyBackend, :hello})
60-
assert {:error, {:already_started, _}} = Logger.add_backend({MyBackend, :hello})
59+
assert {:error, :already_added} = Logger.add_backend({MyBackend, :hello})
6160
assert :ok = Logger.remove_backend({MyBackend, :hello})
6261
end
6362

@@ -178,7 +177,7 @@ defmodule LoggerTest do
178177

179178
assert {:ok, pid} = Logger.add_backend(:console)
180179
assert Logger.add_backend(:console) ==
181-
{:error, {:already_started, pid}}
180+
{:error, :already_added}
182181
after
183182
Application.put_env(:logger, :backends, [:console])
184183
Logger.App.stop()

0 commit comments

Comments
 (0)