Skip to content

Commit ad012d7

Browse files
authored
Task: Add mockable wrapper for :dbg (#318)
* Add :dbg service wrapper * Refactor typespecs
1 parent 49ea4a8 commit ad012d7

2 files changed

Lines changed: 87 additions & 4 deletions

File tree

lib/live_debugger/gen_servers/callback_tracing_server.ex

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ defmodule LiveDebugger.GenServers.CallbackTracingServer do
77

88
require Logger
99

10+
alias LiveDebugger.Services.System.DbgService, as: Dbg
1011
alias LiveDebugger.Services.ModuleDiscoveryService
1112
alias LiveDebugger.Services.ChannelService
1213
alias LiveDebugger.Services.TraceService
@@ -63,8 +64,8 @@ defmodule LiveDebugger.GenServers.CallbackTracingServer do
6364

6465
@impl true
6566
def handle_info(:setup_tracing, table_refs) do
66-
:dbg.tracer(:process, {&handle_trace/2, 0})
67-
:dbg.p(:all, :c)
67+
Dbg.tracer(:process, {&handle_trace/2, 0})
68+
Dbg.p(:all, :c)
6869

6970
all_modules = ModuleDiscoveryService.all_modules()
7071

@@ -77,11 +78,11 @@ defmodule LiveDebugger.GenServers.CallbackTracingServer do
7778
|> ModuleDiscoveryService.live_component_modules()
7879
|> CallbackUtils.live_component_callbacks()
7980
|> Enum.concat(callbacks)
80-
|> Enum.each(fn mfa -> :dbg.tp(mfa, []) end)
81+
|> Enum.each(fn mfa -> Dbg.tp(mfa, []) end)
8182

8283
# This is not a callback created by user
8384
# We trace it to refresh the components tree
84-
:dbg.tp({Phoenix.LiveView.Diff, :delete_component, 2}, [])
85+
Dbg.tp({Phoenix.LiveView.Diff, :delete_component, 2}, [])
8586

8687
{:noreply, table_refs}
8788
end
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
defmodule LiveDebugger.Services.System.DbgService do
2+
@moduledoc """
3+
This module provides wrappers for system functions that are used for debugging.
4+
"""
5+
6+
@type port_generator() :: (-> port())
7+
@type handler_spec() :: {handler_fun(), initial_data :: term()}
8+
@type handler_fun() :: (event :: term(), data :: term() -> new_data :: term())
9+
@type module_spec() ::
10+
(-> {tracer_module :: atom(), tracer_state :: term()})
11+
| {tracer_module :: atom(), tracer_state :: term()}
12+
13+
@callback tracer(:port, port_generator()) :: {:ok, pid()} | {:error, term()}
14+
@callback tracer(:process, handler_spec()) :: {:ok, pid()} | {:error, term()}
15+
@callback tracer(:module, module_spec()) :: {:ok, pid()} | {:error, term()}
16+
@callback tracer(:file, filename :: :file.name_all()) :: {:ok, pid()} | {:error, term()}
17+
18+
@type match_desc() :: [match_num()]
19+
@type match_num() :: {:matched, node(), integer()} | {:matched, node(), 0, rPCError :: term()}
20+
21+
@callback p(item :: term(), flags :: term()) :: {:ok, match_desc()} | {:error, term()}
22+
23+
@callback tp(module() | mfa(), match_spec :: term()) :: {:ok, match_desc()} | {:error, term()}
24+
25+
@doc """
26+
Wrapper for `:dbg.tracer/2` that starts a tracer for the given type and handler specification.
27+
"""
28+
@spec tracer(:port, port_generator()) :: {:ok, pid()} | {:error, term()}
29+
@spec tracer(:process, handler_spec()) :: {:ok, pid()} | {:error, term()}
30+
@spec tracer(:module, module_spec()) :: {:ok, pid()} | {:error, term()}
31+
@spec tracer(:file, filename :: :file.name_all()) :: {:ok, pid()} | {:error, term()}
32+
def tracer(type, handler_spec) do
33+
impl().tracer(type, handler_spec)
34+
end
35+
36+
@doc """
37+
Wrapper for `:dbg.p/2`.
38+
Traces `Item` in accordance to the value specified by `Flags`.
39+
`p` stands for **p**rocess.
40+
"""
41+
@spec p(item :: term(), flags :: term()) :: {:ok, match_desc()} | {:error, term()}
42+
def p(item, flags) do
43+
impl().p(item, flags)
44+
end
45+
46+
@doc """
47+
Wrapper for `:dbg.tp/2` that sets up a trace pattern.
48+
Enables call trace for one or more exported functions specified by `ModuleOrMFA`.
49+
"""
50+
@spec tp(module() | mfa(), match_spec :: term()) :: {:ok, match_desc()} | {:error, term()}
51+
def tp(module, match_spec) do
52+
impl().tp(module, match_spec)
53+
end
54+
55+
defp impl() do
56+
Application.get_env(
57+
:live_debugger,
58+
:dbg_service,
59+
__MODULE__.Impl
60+
)
61+
end
62+
63+
defmodule Impl do
64+
@moduledoc false
65+
@behaviour LiveDebugger.Services.System.DbgService
66+
67+
@impl true
68+
def tracer(type, handler_spec) do
69+
:dbg.tracer(type, handler_spec)
70+
end
71+
72+
@impl true
73+
def p(item, flags) do
74+
:dbg.p(item, flags)
75+
end
76+
77+
@impl true
78+
def tp(module, match_spec) do
79+
:dbg.tp(module, match_spec)
80+
end
81+
end
82+
end

0 commit comments

Comments
 (0)