Current section

Files

Jump to
live_debugger lib live_debugger services callback_tracer actions function_trace.ex
Raw

lib/live_debugger/services/callback_tracer/actions/function_trace.ex

defmodule LiveDebugger.Services.CallbackTracer.Actions.FunctionTrace do
@moduledoc """
This module provides actions for traces.
"""
alias LiveDebugger.Utils.Versions
alias LiveDebugger.Structs.Trace.FunctionTrace
alias LiveDebugger.API.TracesStorage
alias LiveDebugger.Bus
alias LiveDebugger.Services.CallbackTracer.Events.TraceCalled
alias LiveDebugger.Services.CallbackTracer.Events.TraceReturned
alias LiveDebugger.Services.CallbackTracer.Events.TraceErrored
alias LiveDebugger.Services.CallbackTracer.Events.TraceExceptionUpdated
@spec create_trace(
n :: non_neg_integer(),
module :: module(),
fun :: atom(),
args :: list(),
pid :: pid(),
timestamp :: :erlang.timestamp()
) :: {:ok, FunctionTrace.t()} | {:error, term()}
def create_trace(n, module, fun, args, pid, timestamp) do
trace = FunctionTrace.new(n, module, fun, args, pid, timestamp)
case trace.transport_pid do
nil ->
{:error, "Transport PID is nil"}
_ ->
{:ok, trace}
end
end
if not Versions.live_component_destroyed_telemetry_supported?() do
@spec create_delete_component_trace(
n :: non_neg_integer(),
args :: list(),
pid :: pid(),
cid :: String.t(),
timestamp :: :erlang.timestamp()
) :: {:ok, FunctionTrace.t()} | :live_debugger_trace | {:error, term()}
def create_delete_component_trace(n, args, pid, cid, timestamp) do
pid
|> LiveDebugger.API.LiveViewDebug.socket()
|> case do
{:ok, %{id: socket_id, transport_pid: t_pid, view: view}} when is_pid(t_pid) ->
if LiveDebugger.Utils.Modules.debugger_module?(view) do
:live_debugger_trace
else
trace =
FunctionTrace.new(
n,
Phoenix.LiveView.Diff,
:delete_component,
args,
pid,
timestamp,
socket_id: socket_id,
transport_pid: t_pid,
cid: %Phoenix.LiveComponent.CID{cid: cid}
)
{:ok, trace}
end
_ ->
{:error, "Could not get socket"}
end
end
end
@spec update_trace(FunctionTrace.t(), map()) :: {:ok, FunctionTrace.t()}
def update_trace(%FunctionTrace{} = trace, params) do
{:ok, Map.merge(trace, params)}
end
@spec persist_trace(FunctionTrace.t()) :: {:ok, reference()} | {:error, term()}
def persist_trace(%FunctionTrace{pid: pid} = trace) do
with ref when is_reference(ref) <- TracesStorage.get_table(pid),
true <- TracesStorage.insert!(ref, trace) do
{:ok, ref}
else
_ ->
{:error, "Could not persist trace"}
end
end
@spec persist_trace(FunctionTrace.t(), reference()) :: {:ok, reference()}
def persist_trace(%FunctionTrace{} = trace, ref) do
TracesStorage.insert!(ref, trace)
{:ok, ref}
end
@spec publish_trace(FunctionTrace.t(), reference() | nil) :: :ok | {:error, term()}
def publish_trace(%FunctionTrace{pid: pid} = trace, ref \\ nil) do
trace
|> get_event(ref)
|> Bus.broadcast_trace!(pid)
rescue
err ->
{:error, err}
end
@spec publish_trace_exception(FunctionTrace.t(), reference() | nil) :: :ok | {:error, term()}
def publish_trace_exception(%FunctionTrace{pid: pid} = trace, ref \\ nil) do
trace
|> get_exception_event(ref)
|> Bus.broadcast_event!(pid)
rescue
err ->
{:error, err}
end
defp get_event(%FunctionTrace{type: :call} = trace, ref) do
%TraceCalled{
trace_id: trace.id,
ets_ref: ref,
module: trace.module,
function: trace.function,
arity: trace.arity,
pid: trace.pid,
cid: trace.cid,
transport_pid: trace.transport_pid
}
end
defp get_event(%FunctionTrace{type: :return_from} = trace, ref) do
%TraceReturned{
trace_id: trace.id,
ets_ref: ref,
module: trace.module,
function: trace.function,
arity: trace.arity,
pid: trace.pid,
cid: trace.cid,
transport_pid: trace.transport_pid
}
end
defp get_event(%FunctionTrace{type: :exception_from} = trace, ref) do
%TraceErrored{
trace_id: trace.id,
ets_ref: ref,
module: trace.module,
function: trace.function,
arity: trace.arity,
pid: trace.pid,
cid: trace.cid,
transport_pid: trace.transport_pid
}
end
defp get_exception_event(%FunctionTrace{type: :exception_from} = trace, ref) do
%TraceExceptionUpdated{
trace_id: trace.id,
ets_ref: ref,
module: trace.module,
function: trace.function,
arity: trace.arity,
pid: trace.pid,
cid: trace.cid,
transport_pid: trace.transport_pid
}
end
end