-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathtrace.ex
More file actions
126 lines (108 loc) · 3.52 KB
/
Copy pathtrace.ex
File metadata and controls
126 lines (108 loc) · 3.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
defmodule LiveDebugger.Structs.Trace do
@moduledoc """
This module provides a struct to represent a trace.
ID is number generated by :dbg tracer.
PID is always present.
CID is optional - it is filled when trace comes from LiveComponent.
When trace has PID and CID it means that it comes from LiveComponent.
When trace has only PID it means that it comes from LiveView.
There cannot be a trace with CID and without PID.
"""
alias LiveDebugger.CommonTypes
defstruct [
:id,
:module,
:function,
:arity,
:args,
:socket_id,
:transport_pid,
:pid,
:cid,
:timestamp,
:execution_time
]
@type timestamp() :: {non_neg_integer(), non_neg_integer(), non_neg_integer()}
@type t() :: %__MODULE__{
id: integer(),
module: module(),
function: atom(),
arity: non_neg_integer(),
args: list(),
socket_id: String.t(),
transport_pid: pid() | nil,
pid: pid(),
cid: struct() | nil,
timestamp: integer(),
execution_time: non_neg_integer() | nil
}
@doc """
Creates a new trace struct.
"""
@spec new(integer(), module(), atom(), list(), pid(), timestamp(), Keyword.t()) :: t()
def new(id, module, function, args, pid, timestamp, opts \\ []) do
socket_id = Keyword.get(opts, :socket_id, get_socket_id_from_args(args))
transport_pid = Keyword.get(opts, :transport_pid, get_transport_pid_from_args(args))
cid = Keyword.get(opts, :cid, get_cid_from_args(args))
%__MODULE__{
id: id,
module: module,
function: function,
arity: length(args),
args: args,
socket_id: socket_id,
transport_pid: transport_pid,
pid: pid,
cid: cid,
timestamp: :timer.now_diff(timestamp, {0, 0, 0}),
execution_time: nil
}
end
@doc """
Returns the node id from the trace.
It is PID if trace comes from a LiveView, CID if trace comes from a LiveComponent.
"""
@spec node_id(t()) :: pid() | CommonTypes.cid()
def node_id(%__MODULE__{cid: cid}) when not is_nil(cid), do: cid
def node_id(%__MODULE__{pid: pid}), do: pid
@doc """
Checks if the trace is a delete live component trace.
"""
@spec live_component_delete?(t()) :: boolean()
def live_component_delete?(%__MODULE__{
module: Phoenix.LiveView.Diff,
function: :delete_component,
arity: 2
}) do
true
end
def live_component_delete?(_), do: false
@spec callback_name(t()) :: String.t()
def callback_name(trace) do
"#{trace.function}/#{trace.arity}"
end
defp get_transport_pid_from_args(args) do
args
|> Enum.map(&maybe_get_transport_pid(&1))
|> Enum.find(fn elem -> is_pid(elem) end)
end
defp maybe_get_transport_pid(%{transport_pid: transport}), do: transport
defp maybe_get_transport_pid(%{socket: %{transport_pid: transport}}), do: transport
defp maybe_get_transport_pid(_), do: nil
defp get_socket_id_from_args(args) do
args
|> Enum.map(&maybe_get_socket_id(&1))
|> Enum.find(fn elem -> is_binary(elem) end)
end
defp maybe_get_socket_id(%Phoenix.LiveView.Socket{id: id}), do: id
defp maybe_get_socket_id(%{socket: %Phoenix.LiveView.Socket{id: id}}), do: id
defp maybe_get_socket_id(_), do: nil
defp get_cid_from_args(args) do
args
|> Enum.map(&maybe_get_cid(&1))
|> Enum.find(fn elem -> is_struct(elem, Phoenix.LiveComponent.CID) end)
end
defp maybe_get_cid(%{myself: cid}), do: cid
defp maybe_get_cid(%{assigns: %{myself: cid}}), do: cid
defp maybe_get_cid(_), do: nil
end