mirror of
https://github.com/plausible/analytics.git
synced 2024-10-26 18:32:25 +03:00
Sentry context in live views (#3672)
* Add common LiveView macro to PlausibleWeb * Keep peer data, URI and UA in /live websocket metadata * Use new PlausibleWeb macro in existing LiveViews * Implement adding some basic Sentry context `on_mount` * Format * Use macro in Live.FunnelSettings * Update FunnelSettings.Form
This commit is contained in:
parent
aa139a73b8
commit
9bb2dc00d0
@ -2,9 +2,8 @@ defmodule PlausibleWeb.Live.FunnelSettings do
|
||||
@moduledoc """
|
||||
LiveView allowing listing, creating and deleting funnels.
|
||||
"""
|
||||
use Phoenix.LiveView
|
||||
use PlausibleWeb, :live_view
|
||||
use Phoenix.HTML
|
||||
use PlausibleWeb.Live.Flash
|
||||
|
||||
use Plausible.Funnel
|
||||
|
||||
|
@ -5,7 +5,7 @@ defmodule PlausibleWeb.Live.FunnelSettings.Form do
|
||||
to allow building searchable funnel definitions out of list of goals available.
|
||||
"""
|
||||
|
||||
use Phoenix.LiveView
|
||||
use PlausibleWeb, :live_view
|
||||
use Plausible.Funnel
|
||||
|
||||
import PlausibleWeb.Live.Components.Form
|
||||
|
@ -1,4 +1,19 @@
|
||||
defmodule PlausibleWeb do
|
||||
def live_view(opts \\ []) do
|
||||
quote do
|
||||
use Plausible
|
||||
use Phoenix.LiveView, global_prefixes: ~w(x-)
|
||||
use PlausibleWeb.Live.Flash
|
||||
|
||||
unless :no_sentry_context in unquote(opts) do
|
||||
use PlausibleWeb.Live.SentryContext
|
||||
end
|
||||
|
||||
alias PlausibleWeb.Router.Helpers, as: Routes
|
||||
alias Phoenix.LiveView.JS
|
||||
end
|
||||
end
|
||||
|
||||
def controller do
|
||||
quote do
|
||||
use Phoenix.Controller, namespace: PlausibleWeb
|
||||
@ -86,4 +101,8 @@ defmodule PlausibleWeb do
|
||||
defmacro __using__(which) when is_atom(which) do
|
||||
apply(__MODULE__, which, [])
|
||||
end
|
||||
|
||||
defmacro __using__([{which, opts}]) when is_atom(which) do
|
||||
apply(__MODULE__, which, [List.wrap(opts)])
|
||||
end
|
||||
end
|
||||
|
@ -17,7 +17,12 @@ defmodule PlausibleWeb.Endpoint do
|
||||
socket("/live", Phoenix.LiveView.Socket,
|
||||
websocket: [
|
||||
check_origin: true,
|
||||
connect_info: [session: {__MODULE__, :runtime_session_opts, []}]
|
||||
connect_info: [
|
||||
:peer_data,
|
||||
:uri,
|
||||
:user_agent,
|
||||
session: {__MODULE__, :runtime_session_opts, []}
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
|
@ -2,7 +2,7 @@ defmodule PlausibleWeb.Live.ChoosePlan do
|
||||
@moduledoc """
|
||||
LiveView for upgrading to a plan, or changing an existing plan.
|
||||
"""
|
||||
use Phoenix.LiveView
|
||||
use PlausibleWeb, :live_view
|
||||
use Phoenix.HTML
|
||||
|
||||
require Plausible.Billing.Subscription.Status
|
||||
|
@ -2,9 +2,8 @@ defmodule PlausibleWeb.Live.GoalSettings do
|
||||
@moduledoc """
|
||||
LiveView allowing listing, creating and deleting goals.
|
||||
"""
|
||||
use Phoenix.LiveView
|
||||
use PlausibleWeb, :live_view
|
||||
use Phoenix.HTML
|
||||
use PlausibleWeb.Live.Flash
|
||||
|
||||
alias Plausible.{Sites, Goals}
|
||||
|
||||
|
@ -2,8 +2,7 @@ defmodule PlausibleWeb.Live.GoalSettings.Form do
|
||||
@moduledoc """
|
||||
Live view for the goal creation form
|
||||
"""
|
||||
use Phoenix.LiveView
|
||||
use Plausible
|
||||
use PlausibleWeb, :live_view
|
||||
import PlausibleWeb.Live.Components.Form
|
||||
alias PlausibleWeb.Live.Components.ComboBox
|
||||
|
||||
|
@ -2,9 +2,9 @@ defmodule PlausibleWeb.Live.Plugins.API.Settings do
|
||||
@moduledoc """
|
||||
LiveView allowing listing, creating and revoking Plugins API tokens.
|
||||
"""
|
||||
use Phoenix.LiveView
|
||||
|
||||
use PlausibleWeb, :live_view
|
||||
use Phoenix.HTML
|
||||
use PlausibleWeb.Live.Flash
|
||||
|
||||
alias Plausible.Sites
|
||||
alias Plausible.Plugins.API.Tokens
|
||||
|
@ -2,7 +2,7 @@ defmodule PlausibleWeb.Live.Plugins.API.TokenForm do
|
||||
@moduledoc """
|
||||
Live view for the goal creation form
|
||||
"""
|
||||
use Phoenix.LiveView
|
||||
use PlausibleWeb, live_view: :no_sentry_context
|
||||
import PlausibleWeb.Live.Components.Form
|
||||
|
||||
alias Plausible.Repo
|
||||
|
@ -3,9 +3,8 @@ defmodule PlausibleWeb.Live.PropsSettings do
|
||||
LiveView allowing listing, allowing and disallowing custom event properties.
|
||||
"""
|
||||
|
||||
use Phoenix.LiveView
|
||||
use PlausibleWeb, :live_view
|
||||
use Phoenix.HTML
|
||||
use PlausibleWeb.Live.Flash
|
||||
|
||||
alias PlausibleWeb.Live.Components.ComboBox
|
||||
|
||||
|
@ -2,7 +2,7 @@ defmodule PlausibleWeb.Live.PropsSettings.Form do
|
||||
@moduledoc """
|
||||
Live view for the custom props creation form
|
||||
"""
|
||||
use Phoenix.LiveView
|
||||
use PlausibleWeb, :live_view
|
||||
import PlausibleWeb.Live.Components.Form
|
||||
alias PlausibleWeb.Live.Components.ComboBox
|
||||
|
||||
|
@ -3,17 +3,13 @@ defmodule PlausibleWeb.Live.RegisterForm do
|
||||
LiveView for registration form.
|
||||
"""
|
||||
|
||||
use Phoenix.LiveView
|
||||
use PlausibleWeb, :live_view
|
||||
use Phoenix.HTML
|
||||
use Plausible
|
||||
|
||||
import PlausibleWeb.Live.Components.Form
|
||||
|
||||
alias Plausible.Auth
|
||||
alias Plausible.Repo
|
||||
|
||||
alias PlausibleWeb.Router.Helpers, as: Routes
|
||||
|
||||
def mount(params, _session, socket) do
|
||||
socket =
|
||||
assign_new(socket, :invitation, fn ->
|
||||
|
@ -3,7 +3,7 @@ defmodule PlausibleWeb.Live.ResetPasswordForm do
|
||||
LiveView for password reset form.
|
||||
"""
|
||||
|
||||
use Phoenix.LiveView
|
||||
use PlausibleWeb, :live_view
|
||||
use Phoenix.HTML
|
||||
|
||||
import PlausibleWeb.Live.Components.Form
|
||||
|
76
lib/plausible_web/live/sentry_context.ex
Normal file
76
lib/plausible_web/live/sentry_context.ex
Normal file
@ -0,0 +1,76 @@
|
||||
defmodule PlausibleWeb.Live.SentryContext do
|
||||
@moduledoc """
|
||||
This module tries to supply LiveViews with some common Sentry context
|
||||
(without it, there is practically none).
|
||||
|
||||
Use via `use PlausibleWeb.Live.SentryContext` in your LiveView module,
|
||||
or preferably via `use PlausibleWeb, :live_view`.
|
||||
|
||||
In case you have multiple LiveViews, there is `use PlausibleWeb, live_view: :no_sentry_context`
|
||||
exposed that allows you to skip using this module. This is because
|
||||
only the root LiveView has access to `connect_info` and an exception will be
|
||||
thrown otherwise.
|
||||
"""
|
||||
|
||||
defmacro __using__(_) do
|
||||
quote do
|
||||
on_mount PlausibleWeb.Live.SentryContext
|
||||
end
|
||||
end
|
||||
|
||||
def on_mount(:default, _params, session, socket) do
|
||||
peer = Phoenix.LiveView.get_connect_info(socket, :peer_data)
|
||||
uri = Phoenix.LiveView.get_connect_info(socket, :uri)
|
||||
|
||||
user_agent =
|
||||
Phoenix.LiveView.get_connect_info(socket, :user_agent)
|
||||
|
||||
socket_host =
|
||||
case socket.host_uri do
|
||||
:not_mounted_at_router -> :not_mounted_at_router
|
||||
%URI{host: host} -> host
|
||||
end
|
||||
|
||||
request_context =
|
||||
%{
|
||||
host: socket_host,
|
||||
env: %{
|
||||
"REMOTE_ADDR" => get_ip(peer),
|
||||
"REMOTE_PORT" => peer && peer.port,
|
||||
"SEVER_NAME" => uri && uri.host
|
||||
}
|
||||
}
|
||||
|
||||
request_context =
|
||||
if user_agent do
|
||||
Map.merge(request_context, %{
|
||||
headers: %{
|
||||
"User-Agent" => user_agent
|
||||
}
|
||||
})
|
||||
else
|
||||
request_context
|
||||
end
|
||||
|
||||
Sentry.Context.set_request_context(request_context)
|
||||
|
||||
user_id = session["current_user_id"]
|
||||
|
||||
if user_id do
|
||||
Sentry.Context.set_user_context(%{
|
||||
id: user_id
|
||||
})
|
||||
end
|
||||
|
||||
{:cont, socket}
|
||||
end
|
||||
|
||||
defp get_ip(%{address: addr}) do
|
||||
case :inet.ntoa(addr) do
|
||||
{:error, _} -> ""
|
||||
address -> to_string(address)
|
||||
end
|
||||
end
|
||||
|
||||
defp get_ip(_), do: ""
|
||||
end
|
@ -3,11 +3,7 @@ defmodule PlausibleWeb.Live.Sites do
|
||||
LiveView for sites index.
|
||||
"""
|
||||
|
||||
use Phoenix.LiveView, global_prefixes: ~w(x-)
|
||||
use PlausibleWeb.Live.Flash
|
||||
use Plausible
|
||||
|
||||
alias Phoenix.LiveView.JS
|
||||
use PlausibleWeb, :live_view
|
||||
use Phoenix.HTML
|
||||
|
||||
import PlausibleWeb.Components.Generic
|
||||
@ -18,7 +14,6 @@ defmodule PlausibleWeb.Live.Sites do
|
||||
alias Plausible.Site
|
||||
alias Plausible.Sites
|
||||
alias Plausible.Site.Memberships.Invitations
|
||||
alias PlausibleWeb.Router.Helpers, as: Routes
|
||||
|
||||
def mount(params, %{"current_user_id" => user_id}, socket) do
|
||||
uri =
|
||||
|
78
test/plausible_web/live/sentry_context_test.exs
Normal file
78
test/plausible_web/live/sentry_context_test.exs
Normal file
@ -0,0 +1,78 @@
|
||||
defmodule PlausibleWeb.Live.SentryContextTest do
|
||||
use PlausibleWeb.ConnCase, async: true
|
||||
import Phoenix.LiveViewTest
|
||||
|
||||
defmodule SampleLV do
|
||||
use PlausibleWeb, :live_view
|
||||
|
||||
def mount(_params, %{"test" => test_pid}, socket) do
|
||||
socket = assign(socket, test_pid: test_pid)
|
||||
{:ok, socket}
|
||||
end
|
||||
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
ok computer
|
||||
"""
|
||||
end
|
||||
|
||||
def handle_event("get_sentry_context", _params, socket) do
|
||||
context = Sentry.Context.get_all()
|
||||
send(socket.assigns.test_pid, {:context, context})
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
||||
|
||||
describe "sentry context" do
|
||||
test "basic shape", %{conn: conn} do
|
||||
context_hook(conn)
|
||||
assert_receive {:context, context}
|
||||
|
||||
assert %{
|
||||
extra: %{},
|
||||
request: %{
|
||||
env: %{
|
||||
"REMOTE_ADDR" => "127.0.0.1",
|
||||
"REMOTE_PORT" => port,
|
||||
"SEVER_NAME" => "www.example.com"
|
||||
},
|
||||
host: :not_mounted_at_router
|
||||
},
|
||||
user: %{},
|
||||
tags: %{},
|
||||
breadcrumbs: []
|
||||
} = context
|
||||
|
||||
assert is_integer(port)
|
||||
end
|
||||
|
||||
test "user-agent is included", %{conn: conn} do
|
||||
conn
|
||||
|> put_req_header("user-agent", "Firefox")
|
||||
|> context_hook()
|
||||
|
||||
assert_receive {:context, context}
|
||||
assert context.request.headers["User-Agent"] == "Firefox"
|
||||
end
|
||||
|
||||
test "user_id is included", %{conn: conn} do
|
||||
context_hook(conn, %{"current_user_id" => 172})
|
||||
|
||||
assert_receive {:context, context}
|
||||
assert context.user.id == 172
|
||||
end
|
||||
end
|
||||
|
||||
defp context_hook(conn, extra_session \\ %{}) do
|
||||
lv = get_liveview(conn, extra_session)
|
||||
assert render(lv) =~ "ok computer"
|
||||
render_hook(lv, :get_sentry_context, %{})
|
||||
end
|
||||
|
||||
defp get_liveview(conn, extra_session) do
|
||||
{:ok, lv, _html} =
|
||||
live_isolated(conn, SampleLV, session: Map.merge(%{"test" => self()}, extra_session))
|
||||
|
||||
lv
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user