diff --git a/lib/live_debugger_web/components/traces.ex b/lib/live_debugger_web/components/traces.ex
index e81c3c03f..fcfd74477 100644
--- a/lib/live_debugger_web/components/traces.ex
+++ b/lib/live_debugger_web/components/traces.ex
@@ -199,4 +199,49 @@ defmodule LiveDebuggerWeb.Components.Traces do
true -> ""
end
end
+
+ attr(:traces_continuation, :any, required: true)
+ attr(:tracing_helper, :any, required: true)
+
+ def load_more_button(assigns) do
+ ~H"""
+
+ <.load_more_button_content
+ traces_continuation={@traces_continuation}
+ tracing_helper={@tracing_helper}
+ />
+
+ """
+ end
+
+ defp load_more_button_content(%{traces_continuation: nil} = assigns), do: ~H""
+ defp load_more_button_content(%{traces_continuation: :end_of_table} = assigns), do: ~H""
+ defp load_more_button_content(%{tracing_helper: %{tracing_started?: true}} = assigns), do: ~H""
+
+ defp load_more_button_content(%{traces_continuation: :loading} = assigns) do
+ ~H"""
+ <.spinner size="sm" class="mb-4" />
+ """
+ end
+
+ defp load_more_button_content(%{traces_continuation: :error} = assigns) do
+ ~H"""
+ <.alert
+ variant="danger"
+ with_icon={true}
+ heading="Error while loading more traces"
+ class="w-full mb-4"
+ >
+ Check logs for more details.
+
+ """
+ end
+
+ defp load_more_button_content(%{traces_continuation: cont} = assigns) when is_tuple(cont) do
+ ~H"""
+ <.button phx-click="load-more" class="w-4 mb-4" variant="secondary">
+ Load more
+
+ """
+ end
end
diff --git a/lib/live_debugger_web/helpers/traces_live_helper.ex b/lib/live_debugger_web/helpers/traces_live_helper.ex
new file mode 100644
index 000000000..ca98a4db3
--- /dev/null
+++ b/lib/live_debugger_web/helpers/traces_live_helper.ex
@@ -0,0 +1,76 @@
+defmodule LiveDebuggerWeb.Helpers.TracesLiveHelper do
+ @moduledoc """
+ This module provides helpers for the TracesLive and especially its hooks.
+ Since these hooks get more complex and they touch different assigns and streams,
+ this module was created to check if the assigns and streams are present in the socket.
+
+ This way we can catch errors early and not have to debug them in the hooks.
+ """
+
+ alias LiveDebugger.Utils.Callbacks, as: UtilsCallbacks
+ alias LiveDebugger.Structs.TreeNode
+
+ @doc """
+ Checks if the assign is present in the socket.
+ If not, it raises an error.
+ """
+ def check_assign!(socket, assign_name) do
+ if Map.has_key?(socket.assigns, assign_name) do
+ socket
+ else
+ raise "Assign #{assign_name} is required."
+ end
+ end
+
+ @doc """
+ Checks if the stream is present in the socket.
+ If not, it raises an error.
+ """
+ def check_stream!(socket, stream_name) do
+ if Map.has_key?(socket.assigns.streams, stream_name) do
+ socket
+ else
+ raise "Stream #{stream_name} is required."
+ end
+ end
+
+ @doc """
+ Returns the default filters for the traces.
+ """
+ def default_filters(node_id) do
+ functions =
+ node_id
+ |> TreeNode.type()
+ |> case do
+ :live_view -> UtilsCallbacks.live_view_callbacks()
+ :live_component -> UtilsCallbacks.live_component_callbacks()
+ end
+ |> Enum.map(fn {function, _} -> {function, true} end)
+
+ %{
+ functions: functions,
+ execution_time: [
+ {:exec_time_max, ""},
+ {:exec_time_min, ""}
+ ]
+ }
+ end
+
+ @doc """
+ Returns the execution times for the traces.
+ """
+ def get_execution_times(socket) do
+ socket.assigns.current_filters.execution_time
+ |> Enum.filter(fn {_, value} -> value != "" end)
+ |> Enum.map(fn {filter, value} -> {filter, String.to_integer(value)} end)
+ end
+
+ @doc """
+ Returns the active functions for the traces.
+ """
+ def get_active_functions(socket) do
+ socket.assigns.current_filters.functions
+ |> Enum.filter(fn {_, active?} -> active? end)
+ |> Enum.map(fn {function, _} -> function end)
+ end
+end
diff --git a/lib/live_debugger_web/hooks/traces_live/existing_traces.ex b/lib/live_debugger_web/hooks/traces_live/existing_traces.ex
new file mode 100644
index 000000000..a092a4afe
--- /dev/null
+++ b/lib/live_debugger_web/hooks/traces_live/existing_traces.ex
@@ -0,0 +1,151 @@
+defmodule LiveDebuggerWeb.Hooks.TracesLive.ExistingTraces do
+ @moduledoc """
+ This hook is responsible for fetching the existing traces and displaying them in the LiveView.
+ It encapsulates logic for async fetching of traces.
+ It attaches a hook to the `:existing_traces` stream to handle the async fetching.
+
+ Required assigns (that are used somehow in the hook):
+ - `:lv_process` - the LiveView process
+ - `:current_filters` - the current filters
+ - `:node_id` - the node ID
+ - `:traces_empty?` - whether the existing traces are empty, possible values: `true`, `false`
+
+ Required stream:
+ - `:existing_traces` - the stream of existing traces.
+
+ Assigns introduced by this hook (they can be used outside of the hook):
+ - `:traces_continuation` - the continuation token for the existing traces, possible values: `nil`, `:end_of_table`, `ets_continuation()`
+ - `:existing_traces_status` - the status of the existing traces, possible values: `:loading`, `:ok`, `:error`
+ """
+
+ require Logger
+
+ import Phoenix.LiveView
+ import Phoenix.Component
+ import LiveDebuggerWeb.Helpers
+ import LiveDebuggerWeb.Helpers.TracesLiveHelper
+
+ alias LiveDebugger.Services.TraceService
+ alias LiveDebugger.Structs.TraceDisplay
+
+ def init_hook(socket, page_size) do
+ socket
+ |> check_assign!(:lv_process)
+ |> check_assign!(:node_id)
+ |> check_assign!(:current_filters)
+ |> check_assign!(:traces_empty?)
+ |> check_stream!(:existing_traces)
+ |> assign(:traces_continuation, nil)
+ |> put_private(:page_size, page_size)
+ |> attach_hook(:existing_traces, :handle_async, &handle_async/3)
+ end
+
+ @doc """
+ It loads asynchronously the existing traces and assigns them to the `:existing_traces` stream.
+ """
+ @spec assign_async_existing_traces(Phoenix.LiveView.Socket.t()) :: Phoenix.LiveView.Socket.t()
+ def assign_async_existing_traces(socket) do
+ pid = socket.assigns.lv_process.pid
+ node_id = socket.assigns.node_id
+ page_size = socket.private.page_size
+ active_functions = get_active_functions(socket)
+ execution_times = get_execution_times(socket)
+
+ socket
+ |> assign(:existing_traces_status, :loading)
+ |> stream(:existing_traces, [], reset: true)
+ |> start_async(:fetch_existing_traces, fn ->
+ TraceService.existing_traces(pid,
+ node_id: node_id,
+ limit: page_size,
+ functions: active_functions,
+ execution_times: execution_times
+ )
+ end)
+ end
+
+ @doc """
+ It loads asynchronously more existing traces and assigns them to the `:existing_traces` stream.
+ """
+ @spec assign_async_more_existing_traces(Phoenix.LiveView.Socket.t()) ::
+ Phoenix.LiveView.Socket.t()
+ def assign_async_more_existing_traces(socket) do
+ pid = socket.assigns.lv_process.pid
+ node_id = socket.assigns.node_id
+ cont = socket.assigns.traces_continuation
+ page_size = socket.private.page_size
+ active_functions = get_active_functions(socket)
+ execution_times = get_execution_times(socket)
+
+ socket
+ |> assign(:traces_continuation, :loading)
+ |> start_async(:load_more_existing_traces, fn ->
+ TraceService.existing_traces(pid,
+ node_id: node_id,
+ limit: page_size,
+ cont: cont,
+ functions: active_functions,
+ execution_times: execution_times
+ )
+ end)
+ end
+
+ defp handle_async(:fetch_existing_traces, {:ok, {trace_list, cont}}, socket) do
+ trace_list = Enum.map(trace_list, &TraceDisplay.from_trace/1)
+
+ socket
+ |> assign(:existing_traces_status, :ok)
+ |> assign(:traces_empty?, false)
+ |> assign(:traces_continuation, cont)
+ |> stream(:existing_traces, trace_list)
+ |> halt()
+ end
+
+ defp handle_async(:fetch_existing_traces, {:ok, :end_of_table}, socket) do
+ socket
+ |> assign(:existing_traces_status, :ok)
+ |> assign(:traces_continuation, :end_of_table)
+ |> halt()
+ end
+
+ defp handle_async(:fetch_existing_traces, {:exit, reason}, socket) do
+ log_async_error("fetching existing traces", reason)
+
+ socket
+ |> assign(:existing_traces_status, :error)
+ |> halt()
+ end
+
+ defp handle_async(:load_more_existing_traces, {:ok, {trace_list, cont}}, socket) do
+ trace_list = Enum.map(trace_list, &TraceDisplay.from_trace/1)
+
+ socket
+ |> assign(:traces_continuation, cont)
+ |> stream(:existing_traces, trace_list)
+ |> halt()
+ end
+
+ defp handle_async(:load_more_existing_traces, {:ok, :end_of_table}, socket) do
+ socket
+ |> assign(:traces_continuation, :end_of_table)
+ |> halt()
+ end
+
+ defp handle_async(:load_more_existing_traces, {:exit, reason}, socket) do
+ log_async_error("loading more existing traces", reason)
+
+ socket
+ |> assign(:traces_continuation, :error)
+ |> halt()
+ end
+
+ defp handle_async(_, _, socket) do
+ {:cont, socket}
+ end
+
+ defp log_async_error(operation, reason) do
+ Logger.error(
+ "LiveDebugger encountered unexpected error while #{operation}: #{inspect(reason)}"
+ )
+ end
+end
diff --git a/lib/live_debugger_web/hooks/traces_live/incoming_traces.ex b/lib/live_debugger_web/hooks/traces_live/incoming_traces.ex
new file mode 100644
index 000000000..f7421c663
--- /dev/null
+++ b/lib/live_debugger_web/hooks/traces_live/incoming_traces.ex
@@ -0,0 +1,73 @@
+defmodule LiveDebuggerWeb.Hooks.TracesLive.IncomingTraces do
+ @moduledoc """
+ This hook is responsible for handling incoming traces
+ It is responsible for inserting new traces into the `:existing_traces` stream.
+ It also handles the case when the trace callback is running
+
+ This hook has to be added after TracingFuse hook - they're both handling `:new_trace` and `:updated_trace` messages.
+ TracingFuse has to be added first because it's responsible for stopping the trace callback.
+
+ Required assigns (that are used somehow in the hook):
+ - `:current_filters` - the current filters
+ - `:traces_empty?` - whether the existing traces are empty, possible values: `true`, `false`
+ - `:trace_callback_running?` - whether the trace callback is running
+
+ Required stream:
+ - `:existing_traces` - the stream of existing traces.
+ """
+
+ import Phoenix.LiveView
+ import Phoenix.Component
+ import LiveDebuggerWeb.Helpers
+ import LiveDebuggerWeb.Helpers.TracesLiveHelper
+
+ alias LiveDebugger.Structs.TraceDisplay
+
+ @live_stream_limit 128
+
+ def init_hook(socket) do
+ socket
+ |> check_assign!(:current_filters)
+ |> check_assign!(:traces_empty?)
+ |> check_stream!(:existing_traces)
+ |> check_assign!(:trace_callback_running?)
+ |> attach_hook(:incoming_traces, :handle_info, &handle_info/2)
+ end
+
+ defp handle_info({:new_trace, trace}, socket) do
+ trace_display = TraceDisplay.from_trace(trace, true)
+
+ socket
+ |> stream_insert(:existing_traces, trace_display, at: 0, limit: @live_stream_limit)
+ |> assign(traces_empty?: false)
+ |> assign(trace_callback_running?: true)
+ |> halt()
+ end
+
+ defp handle_info({:updated_trace, trace}, socket) when socket.assigns.trace_callback_running? do
+ trace_display = TraceDisplay.from_trace(trace, true)
+
+ execution_time = get_execution_times(socket)
+ min_time = Keyword.get(execution_time, :exec_time_min, 0)
+ max_time = Keyword.get(execution_time, :exec_time_max, :infinity)
+
+ if trace.execution_time >= min_time and trace.execution_time <= max_time do
+ socket
+ |> stream_insert(:existing_traces, trace_display, at: 0, limit: @live_stream_limit)
+ else
+ socket
+ |> stream_delete(:existing_traces, trace_display)
+ end
+ |> assign(trace_callback_running?: false)
+ |> push_event("stop-timer", %{})
+ |> halt()
+ end
+
+ defp handle_info({:updated_trace, _trace}, socket) do
+ {:halt, socket}
+ end
+
+ defp handle_info(_, socket) do
+ {:cont, socket}
+ end
+end
diff --git a/lib/live_debugger_web/helpers/tracing_helper.ex b/lib/live_debugger_web/hooks/traces_live/tracing_fuse.ex
similarity index 62%
rename from lib/live_debugger_web/helpers/tracing_helper.ex
rename to lib/live_debugger_web/hooks/traces_live/tracing_fuse.ex
index d7a43a67c..bd125b580 100644
--- a/lib/live_debugger_web/helpers/tracing_helper.ex
+++ b/lib/live_debugger_web/hooks/traces_live/tracing_fuse.ex
@@ -1,26 +1,44 @@
-defmodule LiveDebuggerWeb.Helpers.TracingHelper do
+defmodule LiveDebuggerWeb.Hooks.TracesLive.TracingFuse do
@moduledoc """
- This module provides a helper to manage tracing.
+ This hook is responsible for managing the tracing fuse.
It is responsible for determining if the tracing should be stopped.
It introduces a fuse mechanism to prevent LiveView from being overloaded with traces.
+ It also handles the case when the trace callback is running.
+ This hook has to be added before IncomingTraces hook.
+
+ Required assigns (that are used somehow in the hook):
+ - `:lv_process` - the LiveView process
+ - `:node_id` - the node ID
+ - `:current_filters` - the current filters
+ - `:root_pid` - the root PID
+ - `:trace_callback_running?` - whether the trace callback is running
"""
import Phoenix.Component, only: [assign: 3]
+ import LiveDebuggerWeb.Helpers
+ import Phoenix.LiveView
+ import LiveDebuggerWeb.Helpers.TracesLiveHelper
alias Phoenix.LiveView.Socket
alias LiveDebugger.Utils.PubSub, as: PubSubUtils
+ alias LiveDebuggerWeb.Hooks.Flash
+ alias LiveDebugger.Utils.Parsers
@assign_name :tracing_helper
@time_period 1_000_000
@trace_limit_per_period 100
- def trace_limit_per_period(), do: @trace_limit_per_period
- def time_period(), do: @time_period
-
- @spec init(Socket.t()) :: Socket.t()
- def init(socket) do
- clear_tracing(socket)
+ @spec init_hook(Socket.t()) :: Socket.t()
+ def init_hook(socket) do
+ socket
+ |> check_assign!(:lv_process)
+ |> check_assign!(:node_id)
+ |> check_assign!(:current_filters)
+ |> check_assign!(:trace_callback_running?)
+ |> check_assign!(:root_pid)
+ |> attach_hook(:tracing_helper, :handle_info, &handle_info/2)
+ |> clear_tracing()
end
@spec switch_tracing(Socket.t()) :: Socket.t()
@@ -37,8 +55,40 @@ defmodule LiveDebuggerWeb.Helpers.TracingHelper do
clear_tracing(socket)
end
- @spec maybe_disable_tracing_after_update(Socket.t()) :: Socket.t()
- def maybe_disable_tracing_after_update(socket) do
+ defp handle_info({:new_trace, _}, socket) do
+ socket
+ |> check_fuse()
+ |> case do
+ {:ok, socket} ->
+ {:cont, socket}
+
+ {:stopped, socket} ->
+ limit = @trace_limit_per_period
+ period = @time_period |> Parsers.parse_elapsed_time()
+
+ socket.assigns.root_pid
+ |> Flash.push_flash(
+ socket,
+ "Callback tracer stopped: Too many callbacks in a short time. Current limit is #{limit} callbacks in #{period}."
+ )
+ |> halt()
+
+ {_, socket} ->
+ {:halt, socket}
+ end
+ end
+
+ defp handle_info({:updated_trace, _}, socket) when socket.assigns.trace_callback_running? do
+ socket
+ |> maybe_disable_tracing_after_update()
+ |> cont()
+ end
+
+ defp handle_info(_, socket) do
+ {:cont, socket}
+ end
+
+ defp maybe_disable_tracing_after_update(socket) do
if socket.assigns[@assign_name].tracing_started? do
socket
else
@@ -46,17 +96,11 @@ defmodule LiveDebuggerWeb.Helpers.TracingHelper do
end
end
- @doc """
- Checks if the fuse is blown and stops tracing if it is.
- It uses the `#{@assign_name}` assign to store information.
- When tracing is not started returns `{:noop, socket}`.
- """
- @spec check_fuse(Socket.t()) :: {:ok | :stopped | :noop, Socket.t()}
- def check_fuse(%{assigns: %{@assign_name => %{tracing_started?: false}}} = socket) do
+ defp check_fuse(%{assigns: %{@assign_name => %{tracing_started?: false}}} = socket) do
{:noop, socket}
end
- def check_fuse(%{assigns: %{@assign_name => %{tracing_started?: true}}} = socket) do
+ defp check_fuse(%{assigns: %{@assign_name => %{tracing_started?: true}}} = socket) do
fuse = socket.assigns[@assign_name].fuse
cond do
diff --git a/lib/live_debugger_web/live/global_traces_live.ex b/lib/live_debugger_web/live/global_traces_live.ex
index 5ede0e3c6..ce13531ad 100644
--- a/lib/live_debugger_web/live/global_traces_live.ex
+++ b/lib/live_debugger_web/live/global_traces_live.ex
@@ -21,7 +21,6 @@ defmodule LiveDebuggerWeb.GlobalTracesLive do
class="sm:hidden"
/>
-
diff --git a/lib/live_debugger_web/live/traces_live.ex b/lib/live_debugger_web/live/traces_live.ex
index 5c3332563..dffdee161 100644
--- a/lib/live_debugger_web/live/traces_live.ex
+++ b/lib/live_debugger_web/live/traces_live.ex
@@ -7,16 +7,17 @@ defmodule LiveDebuggerWeb.TracesLive do
require Logger
- alias LiveDebuggerWeb.Helpers.TracingHelper
alias LiveDebugger.Services.TraceService
alias LiveDebugger.Structs.TraceDisplay
alias LiveDebugger.Utils.PubSub, as: PubSubUtils
- alias LiveDebugger.Utils.Callbacks, as: UtilsCallbacks
- alias LiveDebugger.Utils.Parsers
- alias LiveDebugger.Structs.TreeNode
alias LiveDebuggerWeb.Components.Traces
- @live_stream_limit 128
+ alias LiveDebuggerWeb.Hooks.TracesLive.ExistingTraces
+ alias LiveDebuggerWeb.Hooks.TracesLive.IncomingTraces
+ alias LiveDebuggerWeb.Hooks.TracesLive.TracingFuse
+
+ import LiveDebuggerWeb.Helpers.TracesLiveHelper
+
@page_size 25
@separator %{id: "separator"}
@@ -61,18 +62,20 @@ defmodule LiveDebuggerWeb.TracesLive do
default_filters = default_filters(node_id)
socket
- |> assign(:displayed_trace, nil)
- |> assign(:traces_continuation, nil)
|> assign(current_filters: default_filters)
- |> assign(default_filters: default_filters)
+ |> assign(lv_process: lv_process)
+ |> assign(node_id: node_id)
|> assign(traces_empty?: true)
|> assign(trace_callback_running?: false)
- |> assign(node_id: node_id)
- |> assign(id: session["id"])
+ |> stream(:existing_traces, [])
|> assign(root_pid: session["root_pid"])
- |> assign(lv_process: lv_process)
- |> TracingHelper.init()
- |> assign_async_existing_traces()
+ |> TracingFuse.init_hook()
+ |> ExistingTraces.init_hook(@page_size)
+ |> IncomingTraces.init_hook()
+ |> assign(:displayed_trace, nil)
+ |> assign(default_filters: default_filters)
+ |> assign(id: session["id"])
+ |> ExistingTraces.assign_async_existing_traces()
|> ok()
end
@@ -140,20 +143,10 @@ defmodule LiveDebuggerWeb.TracesLive do
<% end %>
<% end %>
-
- <%= if @traces_continuation != :loading do %>
- <.button
- :if={not @tracing_helper.tracing_started? && @traces_continuation != :end_of_table}
- phx-click="load-more"
- class="w-4 mb-4"
- variant="secondary"
- >
- Load more
-
- <% else %>
- <.spinner size="sm" class="mb-4" />
- <% end %>
-
+
@@ -161,124 +154,16 @@ defmodule LiveDebuggerWeb.TracesLive do
"""
end
- @impl true
- def handle_async(:fetch_existing_traces, {:ok, {trace_list, cont}}, socket) do
- trace_list = Enum.map(trace_list, &TraceDisplay.from_trace/1)
-
- socket
- |> assign(existing_traces_status: :ok)
- |> assign(:traces_empty?, false)
- |> assign(:traces_continuation, cont)
- |> stream(:existing_traces, trace_list)
- |> noreply()
- end
-
- @impl true
- def handle_async(:fetch_existing_traces, {:ok, :end_of_table}, socket) do
- socket
- |> assign(existing_traces_status: :ok)
- |> assign(traces_continuation: :end_of_table)
- |> noreply()
- end
-
- @impl true
- def handle_async(:fetch_existing_traces, {:exit, reason}, socket) do
- log_async_error("fetching existing traces", reason)
-
- socket
- |> assign(existing_traces_status: :error)
- |> noreply()
- end
-
- @impl true
- def handle_async(:load_more_existing_traces, {:ok, {trace_list, cont}}, socket) do
- trace_list = Enum.map(trace_list, &TraceDisplay.from_trace/1)
-
- socket
- |> assign(:traces_continuation, cont)
- |> stream(:existing_traces, trace_list)
- |> noreply()
- end
-
- @impl true
- def handle_async(:load_more_existing_traces, {:ok, :end_of_table}, socket) do
- socket
- |> assign(:traces_continuation, :end_of_table)
- |> noreply()
- end
-
- @impl true
- def handle_async(:load_more_existing_traces, {:exit, reason}, socket) do
- log_async_error("loading more existing traces", reason)
- socket
- end
-
- @impl true
- def handle_info({:new_trace, trace}, socket) do
- socket
- |> TracingHelper.check_fuse()
- |> case do
- {:ok, socket} ->
- trace_display = TraceDisplay.from_trace(trace, true)
-
- socket
- |> stream_insert(:existing_traces, trace_display, at: 0, limit: @live_stream_limit)
- |> assign(traces_empty?: false)
- |> assign(trace_callback_running?: true)
-
- {:stopped, socket} ->
- limit = TracingHelper.trace_limit_per_period()
- period = TracingHelper.time_period() |> Parsers.parse_elapsed_time()
-
- socket.assigns.root_pid
- |> push_flash(
- socket,
- "Callback tracer stopped: Too many callbacks in a short time. Current limit is #{limit} callbacks in #{period}."
- )
-
- {_, socket} ->
- socket
- end
- |> noreply()
- end
-
- @impl true
- def handle_info({:updated_trace, trace}, socket) when socket.assigns.trace_callback_running? do
- trace_display = TraceDisplay.from_trace(trace, true)
-
- execution_time = get_execution_times(socket)
- min_time = Keyword.get(execution_time, :exec_time_min, 0)
- max_time = Keyword.get(execution_time, :exec_time_max, :infinity)
-
- if trace.execution_time >= min_time and trace.execution_time <= max_time do
- socket
- |> stream_insert(:existing_traces, trace_display, at: 0, limit: @live_stream_limit)
- else
- socket
- |> stream_delete(:existing_traces, trace_display)
- end
- |> assign(trace_callback_running?: false)
- |> TracingHelper.maybe_disable_tracing_after_update()
- |> push_event("stop-timer", %{})
- |> noreply()
- end
-
- @impl true
- def handle_info({:updated_trace, _trace}, socket) do
- socket
- |> noreply()
- end
-
@impl true
def handle_info({:node_changed, node_id}, socket) do
default_filters = default_filters(node_id)
socket
- |> TracingHelper.disable_tracing()
+ |> TracingFuse.disable_tracing()
|> assign(node_id: node_id)
|> assign(current_filters: default_filters)
|> assign(default_filters: default_filters)
- |> assign_async_existing_traces()
+ |> ExistingTraces.assign_async_existing_traces()
|> noreply()
end
@@ -289,13 +174,13 @@ defmodule LiveDebuggerWeb.TracesLive do
socket
|> assign(:current_filters, filters)
|> assign(:traces_empty?, true)
- |> assign_async_existing_traces()
+ |> ExistingTraces.assign_async_existing_traces()
|> noreply()
end
@impl true
def handle_event("switch-tracing", _, socket) do
- socket = TracingHelper.switch_tracing(socket)
+ socket = TracingFuse.switch_tracing(socket)
if socket.assigns.tracing_helper.tracing_started? and !socket.assigns.traces_empty? do
socket
@@ -310,7 +195,7 @@ defmodule LiveDebuggerWeb.TracesLive do
@impl true
def handle_event("load-more", _, socket) do
socket
- |> load_more_existing_traces()
+ |> ExistingTraces.assign_async_more_existing_traces()
|> noreply()
end
@@ -369,93 +254,7 @@ defmodule LiveDebuggerWeb.TracesLive do
@impl true
def handle_event("refresh-history", _, socket) do
socket
- |> assign_async_existing_traces()
+ |> ExistingTraces.assign_async_existing_traces()
|> noreply()
end
-
- defp assign_async_existing_traces(socket) do
- pid = socket.assigns.lv_process.pid
- node_id = socket.assigns.node_id
- active_functions = get_active_functions(socket)
- execution_times = get_execution_times(socket)
-
- socket
- |> assign(:existing_traces_status, :loading)
- |> stream(:existing_traces, [], reset: true)
- |> start_async(:fetch_existing_traces, fn ->
- TraceService.existing_traces(pid,
- node_id: node_id,
- limit: @page_size,
- functions: active_functions,
- execution_times: execution_times
- )
- end)
- end
-
- defp load_more_existing_traces(socket) do
- pid = socket.assigns.lv_process.pid
- node_id = socket.assigns.node_id
- cont = socket.assigns.traces_continuation
- active_functions = get_active_functions(socket)
- execution_times = get_execution_times(socket)
-
- socket
- |> assign(:traces_continuation, :loading)
- |> start_async(:load_more_existing_traces, fn ->
- TraceService.existing_traces(pid,
- node_id: node_id,
- limit: @page_size,
- cont: cont,
- functions: active_functions,
- execution_times: execution_times
- )
- end)
- end
-
- defp default_filters(node_id) do
- functions =
- node_id
- |> TreeNode.type()
- |> case do
- :live_view -> UtilsCallbacks.live_view_callbacks()
- :live_component -> UtilsCallbacks.live_component_callbacks()
- end
- |> Enum.map(fn {function, _} -> {function, true} end)
-
- %{
- functions: functions,
- execution_time: [
- {:exec_time_max, ""},
- {:exec_time_min, ""},
- {:min_unit, ""},
- {:max_unit, ""}
- ]
- }
- end
-
- defp get_active_functions(socket) do
- socket.assigns.current_filters.functions
- |> Enum.filter(fn {_, active?} -> active? end)
- |> Enum.map(fn {function, _} -> function end)
- end
-
- defp get_execution_times(socket) do
- execution_time = socket.assigns.current_filters.execution_time
-
- execution_time
- |> Enum.filter(fn {_, value} -> value not in ["" | Parsers.time_units()] end)
- |> Enum.map(fn {filter, value} -> {filter, String.to_integer(value)} end)
- |> Enum.map(fn {filter, value} ->
- case filter do
- :exec_time_min -> {filter, Parsers.time_to_microseconds(value, execution_time[:min_unit])}
- :exec_time_max -> {filter, Parsers.time_to_microseconds(value, execution_time[:max_unit])}
- end
- end)
- end
-
- defp log_async_error(operation, reason) do
- Logger.error(
- "LiveDebugger encountered unexpected error while #{operation}: #{inspect(reason)}"
- )
- end
end