Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions lib/zexbox/metrics/context.ex
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ defmodule Zexbox.Metrics.Context do
"""
@spec metrics_disabled?() :: boolean()
def metrics_disabled? do
pids_to_check = [self()] ++ callers() ++ ancestors()
Enum.any?(pids_to_check, &ContextRegistry.disabled?/1)
([self()] ++ callers() ++ ancestors())
|> List.flatten()
|> Enum.filter(&(is_pid(&1) or is_atom(&1)))
|> Enum.any?(&ContextRegistry.disabled?/1)
end

defp callers do
Expand Down
6 changes: 4 additions & 2 deletions lib/zexbox/metrics/context_registry.ex
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,16 @@ defmodule Zexbox.Metrics.ContextRegistry do
@doc """
Returns true if the given pid is in the disabled set.
"""
@spec disabled?(pid()) :: boolean()
def disabled?(pid) when is_pid(pid) do
@spec disabled?(pid() | atom() | nil) :: boolean()
def disabled?(pid) when is_pid(pid) or is_atom(pid) do
case :ets.lookup(@table, pid) do
[{^pid, _present}] -> true
[] -> false
end
end

def disabled?(_pid), do: false

@impl GenServer
def init(_opts) do
_table = :ets.new(@table, [:set, :public, :named_table, read_concurrency: true])
Expand Down
6 changes: 6 additions & 0 deletions test/zexbox/metrics/context_registry_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ defmodule Zexbox.Metrics.ContextRegistryTest do
# Wait until the registry processes the :DOWN and removes ETS entry.
eventually(fn -> ContextRegistry.disabled?(pid) == false end)
end

test "disabled?/1 returns false for non-pid values" do
assert ContextRegistry.disabled?(nil) == false
assert ContextRegistry.disabled?({:not, :a, :pid}) == false
assert ContextRegistry.disabled?([self()]) == false
end
end

defp eventually(predicate, attempts \\ 50)
Expand Down
38 changes: 38 additions & 0 deletions test/zexbox/metrics/context_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ defmodule Zexbox.Metrics.ContextTest do
describe "disable_for_process/0 and enable_for_process/0" do
setup do
start_supervised!(ContextRegistry)

old_callers = Process.get(:"$callers")
old_ancestors = Process.get(:"$ancestors")

on_exit(fn ->
Process.put(:"$callers", old_callers)
Process.put(:"$ancestors", old_ancestors)
end)

:ok
end

Expand Down Expand Up @@ -33,5 +42,34 @@ defmodule Zexbox.Metrics.ContextTest do

:ok = Zexbox.Metrics.enable_for_process()
end

test "metrics_disabled?/0 tolerates nested $callers and non-pid terms" do
parent = self()

pid =
spawn(fn ->
send(parent, :ready)

receive do
:stop -> :ok
end
end)

on_exit(fn -> send(pid, :stop) end)
assert_receive :ready

:ok = ContextRegistry.register(pid)

# Simulate unexpected shapes (nested lists, tuples, etc.) in the process dictionary.
Process.put(:"$callers", [[pid], {:not_a_pid, 123}])
Process.put(:"$ancestors", [[:some_name], [pid]])

assert Context.metrics_disabled?() == true
end

test "metrics_disabled?/0 tolerates atom ancestors" do
Process.put(:"$ancestors", [:some_registered_name])
assert Context.metrics_disabled?() == false
end
end
end