diff --git a/instrumentation/opentelemetry_phoenix/lib/opentelemetry_phoenix.ex b/instrumentation/opentelemetry_phoenix/lib/opentelemetry_phoenix.ex index 2138f51..23867d6 100644 --- a/instrumentation/opentelemetry_phoenix/lib/opentelemetry_phoenix.ex +++ b/instrumentation/opentelemetry_phoenix/lib/opentelemetry_phoenix.ex @@ -10,6 +10,11 @@ defmodule OpentelemetryPhoenix do default: nil, doc: "The phoenix server adapter being used.", type_doc: ":atom" + ], + liveview: [ + type: :boolean, + default: true, + doc: "Whether LiveView traces will be instrumented." ] ) @@ -78,6 +83,10 @@ defmodule OpentelemetryPhoenix do attach_router_start_handler() attach_router_dispatch_exception_handler() + if opts[:liveview] do + attach_liveview_handlers() + end + :ok end @@ -121,6 +130,30 @@ defmodule OpentelemetryPhoenix do ) end + def attach_liveview_handlers do + :telemetry.attach_many( + {__MODULE__, :live_view}, + [ + [:phoenix, :live_view, :mount, :start], + [:phoenix, :live_view, :mount, :stop], + [:phoenix, :live_view, :mount, :exception], + [:phoenix, :live_view, :handle_params, :start], + [:phoenix, :live_view, :handle_params, :stop], + [:phoenix, :live_view, :handle_params, :exception], + [:phoenix, :live_view, :handle_event, :start], + [:phoenix, :live_view, :handle_event, :stop], + [:phoenix, :live_view, :handle_event, :exception], + [:phoenix, :live_component, :handle_event, :start], + [:phoenix, :live_component, :handle_event, :stop], + [:phoenix, :live_component, :handle_event, :exception] + ], + &__MODULE__.handle_liveview_event/4, + %{} + ) + + :ok + end + @doc false def handle_endpoint_start(_event, _measurements, meta, config) do Process.put({:otel_phoenix, :adapter}, config.adapter) @@ -156,7 +189,8 @@ defmodule OpentelemetryPhoenix do SemanticConventions.Trace.http_target() => conn.request_path, SemanticConventions.Trace.http_user_agent() => user_agent, SemanticConventions.Trace.net_host_name() => conn.host, - SemanticConventions.Trace.net_sock_host_addr() => to_string(:inet_parse.ntoa(conn.remote_ip)), + SemanticConventions.Trace.net_sock_host_addr() => + to_string(:inet_parse.ntoa(conn.remote_ip)), SemanticConventions.Trace.net_host_port() => conn.port, SemanticConventions.Trace.net_sock_peer_addr() => to_string(:inet_parse.ntoa(peer_ip)), SemanticConventions.Trace.net_peer_port() => peer_data.port, @@ -232,6 +266,90 @@ defmodule OpentelemetryPhoenix do end end + def handle_liveview_event( + [:phoenix, _live, :mount, :start], + _measurements, + meta, + _handler_configuration + ) do + %{socket: socket} = meta + %{view: live_view} = socket + + attributes = %{} + + OpentelemetryTelemetry.start_telemetry_span( + @tracer_id, + "#{inspect(live_view)}.mount", + meta, + %{kind: :server} + ) + |> OpenTelemetry.Span.set_attributes(attributes) + end + + def handle_liveview_event( + [:phoenix, _live, :handle_params, :start], + _measurements, + meta, + _handler_configuration + ) do + %{socket: socket} = meta + %{view: live_view} = socket + + attributes = %{} + + OpentelemetryTelemetry.start_telemetry_span( + @tracer_id, + "#{inspect(live_view)}.handle_params", + meta, + %{kind: :server} + ) + |> OpenTelemetry.Span.set_attributes(attributes) + end + + def handle_liveview_event( + [:phoenix, _live, :handle_event, :start], + _measurements, + meta, + _handler_configuration + ) do + %{socket: socket, event: event, params: _params} = meta + %{view: live_view} = socket + + attributes = %{} + + OpentelemetryTelemetry.start_telemetry_span( + @tracer_id, + "#{inspect(live_view)}.handle_event##{event}", + meta, + %{kind: :server} + ) + |> OpenTelemetry.Span.set_attributes(attributes) + end + + def handle_liveview_event( + [:phoenix, _live, _event, :stop], + _measurements, + meta, + _handler_configuration + ) do + OpentelemetryTelemetry.end_telemetry_span(@tracer_id, meta) + end + + def handle_liveview_event( + [:phoenix, _live, _action, :exception], + _, + %{kind: kind, reason: reason, stacktrace: stacktrace} = meta, + _ + ) do + ctx = OpentelemetryTelemetry.set_current_telemetry_span(@tracer_id, meta) + + exception = Exception.normalize(kind, reason, stacktrace) + + OpenTelemetry.Span.record_exception(ctx, exception, stacktrace, []) + OpenTelemetry.Span.set_status(ctx, OpenTelemetry.status(:error, "")) + OpentelemetryTelemetry.end_telemetry_span(@tracer_id, meta) + end + defp http_flavor({_adapter_name, meta}) do case Map.get(meta, :version) do :"HTTP/1.0" -> :"1.0"