Enriching AppSignal Error Reports in LiveView
Adding essential context like current path and user info.
AppSignal automatically captures rich context across different parts of your application. For regular Phoenix controllers, Oban jobs, and other background tasks, you get the full context including session data, request data, and job parameters.
However, LiveView's real-time nature presents a unique challenge. While AppSignal provides automatic error tracking for LiveView, the default information is more limited compared to other parts of your application. By default, AppSignal captures for LiveView:
- The error message and stack trace
- The LiveView module name
- The event type (mount, handle_params, handle_event, etc.)
- Event parameters (for handle_event, handle_params, etc.)
However, it misses important contextual information that would automatically be available elsewhere:
- The current user's information (session data)
- The path the user was on
- Other LiveView state (assigns)
In this post, we'll explore how to enhance AppSignal errors in LiveView. We'll attach a telemetry handler much like AppSignal does to enrich the span data.
Setting Up the Extension
First, let's create a module that will attach telemetry handlers to LiveView events. This mirrors the Appsignal.Phoenix.LiveView module:
defmodule YourApp.Appsignal.LiveView do
@tracer Application.compile_env(:appsignal, :appsignal_tracer, Appsignal.Tracer)
@span Application.compile_env(:appsignal, :appsignal_span, Appsignal.Span)
def attach do
Enum.each(
[
[:phoenix, :live_view, :mount],
[:phoenix, :live_view, :handle_params],
[:phoenix, :live_view, :handle_event],
[:phoenix, :live_view, :render],
[:phoenix, :live_component, :handle_event],
[:phoenix, :live_component, :update]
],
fn event ->
name = Enum.join(event, ".")
:telemetry.attach(
{__MODULE__, event ++ [:start]},
event ++ [:start],
&__MODULE__.handle_event_start/4,
name
)
end
)
end
end
Adding Custom Data to Spans
We'll create a handler that adds user and path information to the AppSignal span:
def handle_event_start([:phoenix, _type, _name, :start], _, metadata, _event_name) do
assigns = if metadata[:socket], do: metadata.socket.assigns
@tracer.current_span()
|> @span.set_sample_data("environment", %{path_info: assigns[:active_path]})
|> @span.set_sample_data("custom_data", %{
user_id: assigns[:user] && assigns.user.id,
tenant_id: assigns[:tenant] && assigns.tenant.id
})
end
Creating a LiveView Path Tracker Hook
We can use LiveView's attach_hook
to track the current path in handle_params
. Create a LiveView hook module:
defmodule YourAppWeb.Hooks.Assigns do
import Phoenix.Component
import Phoenix.LiveView
def on_mount(:default, _params, _session, socket) do
socket =
socket
|> attach_hook(:active_path, :handle_params, fn _params, uri, socket ->
{:cont, assign(socket, :active_path, URI.parse(uri).path)}
end)
{:cont, socket}
end
end
Then use it in your router:
live_session :default do
on_mount YourAppWeb.Hooks.Assigns
# your live routes...
end
Preparing the LiveView Data
In your LiveView, assign user information during mount:
defmodule YourApp.SomeLiveView do
use Phoenix.LiveView
def mount(_params, session, socket) do
socket =
socket
|> assign(:user, get_user_from_session(session))
|> assign(:tenant, get_tenant_from_session(session))
{:ok, socket}
end
end
Initializing the Extension
Finally, start the telemetry handlers in your application:
# In your application.ex
def start(_type, _args) do
Appsignal.Phoenix.LiveView.attach()
YourApp.Appsignal.LiveView.attach()
Extensions.Appsignal.LiveView.attach()
# ...
What Does This Give Us?
Now, when errors occur in your LiveView application, AppSignal errors will include:
- The current user's ID
- The active tenant ID (if applicable)
- The current path (updated automatically during navigation)
- The event parameters (included by default by AppSignal)
This additional context makes it much easier to debug issues and understand the state of your application when errors occur.
Remember that you can add any other relevant data to the spans by modifying the handle_event_start/4
function. Common additions might include:
- Current locale
- User roles
- Feature flags
- Application state
Conclusion
By enriching AppSignal spans with additional context and implementing automatic path tracking, we've made our error tracking more powerful and useful. This approach helps us quickly identify and fix issues in our LiveView applications by providing the context we need right where we need it.
When you encounter an error in AppSignal, you'll now be able to see not just what went wrong, but also:
- Who experienced the error (user context)
- Where exactly they were in the application (current path)
- What context they were working in (tenant)
- What parameters were passed to the event (default AppSignal behavior)
Remember to only include non-sensitive information in your error tracking, and be mindful of data privacy considerations when deciding what information to track.
The combination of telemetry handlers and LiveView hooks provides a robust solution for comprehensive error tracking that will make debugging and issue resolution much more efficient.