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.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
@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