Packages
new_relic_agent
1.37.0
1.40.3
1.40.2
1.40.1
1.40.0
1.39.0
1.38.0
1.37.0
1.36.0
1.35.0
1.34.0
1.33.0
1.32.0
1.31.1
1.31.0
1.30.0
1.29.0
1.28.0
1.27.8
1.27.7
1.27.6
1.27.5
1.27.4
1.27.3
1.27.2
1.27.1
1.27.0
1.26.0
1.25.3
1.25.2
1.25.1
1.25.0
1.24.5
1.24.4
1.24.3
1.24.2
1.24.1
1.24.0
1.24.0-rc.10
1.24.0-rc.9
1.24.0-rc.8
1.24.0-rc.7
1.23.6
1.23.5
1.23.4
1.23.3
1.23.2
1.23.1
1.23.0
1.23.0-rc.6
1.23.0-rc.5
1.23.0-rc.4
1.23.0-rc.3
1.23.0-rc.2
1.23.0-rc.1
1.22.6
1.22.5
1.22.4
1.22.3
1.22.2
1.22.1
1.22.0
1.21.2
1.21.1
1.21.0
1.21.0-rc.3
1.21.0-rc.1
1.20.0
1.20.0-rc.1
1.19.7
1.19.6
1.19.5
1.19.4
1.19.3
1.19.2
1.19.1
1.19.0
1.18.5
1.18.4
1.18.3
1.18.2
1.18.1
1.18.0
1.18.0-rc.5
1.18.0-rc.4
1.18.0-rc.2
1.18.0-rc.1
1.17.1
1.17.0
1.17.0-rc.4
1.17.0-rc.3
1.17.0-rc.2
1.17.0-rc.1
1.17.0-rc.0
1.16.7
1.16.6
1.16.5
1.16.4
1.16.3
1.16.2
1.16.1
1.16.0
1.16.0-rc.2
1.16.0-rc.1
1.16.0-rc.0
1.15.0
1.15.0-rc.3
1.15.0-rc.2
1.15.0-rc.1
1.14.0
1.13.1
1.13.0
1.12.0
1.11.0
1.10.2
1.10.1
1.10.0
1.9.12
1.9.11
1.9.10
1.9.9
1.9.8
1.9.7
1.9.6
1.9.5
1.9.4
1.9.3
1.9.2
1.9.1
1.9.0
1.8.0
1.7.0
1.6.2
1.6.1
1.6.0
1.5.0
1.4.0
1.3.2
1.3.1
1.3.0
1.2.1
1.2.0
1.1.0
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
New Relic's Open-Source Elixir Agent
Current section
Files
Jump to
Current section
Files
lib/new_relic/telemetry/phoenix_live_view.ex
defmodule NewRelic.Telemetry.PhoenixLiveView do
use GenServer
alias NewRelic.Transaction
alias NewRelic.Tracer
@moduledoc """
Provides Phoenix `LiveView` instrumentation via `telemetry`.
This instrumentation collects Transactions for the initial LiveView lifecycle events
that occur inside the WebSocket process, as well as metrics for subsequent instances
of lifecycle events.
You can opt-out of this instrumentation as a whole with `:phoenix_live_view_instrumentation_enabled`,
and specifically out of params collection with `:function_argument_collection_enabled` via configuration.
See `NewRelic.Config` for details.
"""
def start_link(_) do
config = %{
handler_id: {:new_relic, :phoenix_live_view},
enabled?: NewRelic.Config.feature?(:phoenix_live_view_instrumentation),
collect_args?: NewRelic.Config.feature?(:function_argument_collection)
}
GenServer.start_link(__MODULE__, config, name: __MODULE__)
end
@live_view_mount_start [:phoenix, :live_view, :mount, :start]
@live_view_mount_stop [:phoenix, :live_view, :mount, :stop]
@live_view_mount_exception [:phoenix, :live_view, :mount, :exception]
@live_view_handle_params_start [:phoenix, :live_view, :handle_params, :start]
@live_view_handle_params_stop [:phoenix, :live_view, :handle_params, :stop]
@live_view_handle_params_exception [:phoenix, :live_view, :handle_params, :exception]
@live_view_handle_event_start [:phoenix, :live_view, :handle_event, :start]
@live_view_handle_event_stop [:phoenix, :live_view, :handle_event, :stop]
@live_view_handle_event_exception [:phoenix, :live_view, :handle_event, :exception]
@live_view_render_start [:phoenix, :live_view, :render, :start]
@live_view_render_stop [:phoenix, :live_view, :render, :stop]
@live_view_render_exception [:phoenix, :live_view, :render, :exception]
@live_view_events [
@live_view_mount_start,
@live_view_mount_stop,
@live_view_mount_exception,
@live_view_handle_params_start,
@live_view_handle_params_stop,
@live_view_handle_params_exception,
@live_view_handle_event_start,
@live_view_handle_event_stop,
@live_view_handle_event_exception,
@live_view_render_start,
@live_view_render_stop,
@live_view_render_exception
]
@doc false
def init(%{enabled?: false}), do: :ignore
def init(%{enabled?: true} = config) do
:telemetry.attach_many(
config.handler_id,
@live_view_events,
&__MODULE__.handle_event/4,
config
)
{:ok, config}
end
@doc false
def terminate(_reason, %{handler_id: handler_id}) do
:telemetry.detach(handler_id)
end
def handle_event(@live_view_mount_start, meas, meta, config) do
if meta.socket.transport_pid do
{host, path} = parse_uri(meta.uri)
# We're in the LiveView WebSocket process, collect a Transaction
with :collect <- Transaction.Reporter.start_transaction(:web, path) do
NewRelic.DistributedTrace.start(:other)
framework_name = "/Phoenix.LiveView/Live/#{inspect(meta.socket.view)}/#{meta.socket.assigns.live_action}"
NewRelic.add_attributes(
pid: inspect(self()),
start_time: meas.system_time,
framework_name: framework_name,
host: host,
path: path,
"live_view.router": inspect(meta.socket.router),
"live_view.endpoint": inspect(meta.socket.endpoint),
"live_view.action": meta.socket.assigns[:live_action],
"live_view.socket_id": meta.socket.id
)
end
end
Tracer.Direct.start_span(
meta.telemetry_span_context,
"#{inspect(meta.socket.view)}:#{meta.socket.assigns.live_action}.mount",
system_time: meas.system_time,
attributes: [
"live_view.params": config.collect_args? && meta[:params] && inspect(meta[:params])
]
)
end
def handle_event([_, _, type, _] = event, meas, meta, config)
when event in [
@live_view_handle_params_start,
@live_view_handle_event_start,
@live_view_render_start
] do
Tracer.Direct.start_span(
meta.telemetry_span_context,
"#{inspect(meta.socket.view)}:#{meta.socket.assigns.live_action}.#{type}",
system_time: meas.system_time,
attributes: [
event: meta[:event],
params: config.collect_args? && meta[:params] && inspect(meta[:params]),
"live_view.render.changed?": meta[:changed?],
"live_view.render.force?": meta[:force?]
]
)
end
def handle_event(event, meas, meta, _config)
when event in [
@live_view_mount_stop,
@live_view_handle_params_stop,
@live_view_handle_event_stop
] do
Tracer.Direct.stop_span(meta.telemetry_span_context, duration: meas.duration)
end
def handle_event(event, meas, meta, _config)
when event in [
@live_view_mount_exception,
@live_view_handle_params_exception,
@live_view_handle_event_exception
] do
Tracer.Direct.stop_span(
meta.telemetry_span_context,
duration: meas.duration,
attributes: [error: true, "error.kind": meta.kind, "error.reason": inspect(meta.reason)]
)
end
def handle_event(@live_view_render_stop, meas, meta, _config) do
Tracer.Direct.stop_span(meta.telemetry_span_context, duration: meas.duration)
if meta.socket.transport_pid do
Transaction.Reporter.stop_transaction(:web)
end
end
def handle_event(@live_view_render_exception, meas, meta, _config) do
Tracer.Direct.stop_span(
meta.telemetry_span_context,
duration: meas.duration,
attributes: [error: true, "error.kind": meta.kind, "error.reason": inspect(meta.reason)]
)
if meta.socket.transport_pid do
Transaction.Reporter.stop_transaction(:web)
end
end
def handle_event(_event, _meas, _meta, _config) do
:ignore
end
defp parse_uri(nil),
do: {"unknown", "unknown"}
defp parse_uri(uri) do
uri = URI.parse(uri)
{uri.host, uri.path}
end
end