Add debug_replay_info context to Sentry Stats reports (#3189)

* Add debug_replay_info context to Sentry Stats reports

* Test limit
This commit is contained in:
hq1 2023-07-26 10:44:04 +02:00 committed by GitHub
parent eb3222f840
commit 82f356f387
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 138 additions and 7 deletions

View File

@ -0,0 +1,51 @@
defmodule Plausible.DebugReplayInfo do
@moduledoc """
Function execution context (with arguments) to Sentry reports.
"""
require Logger
defmacro __using__(_) do
quote do
require Plausible.DebugReplayInfo
import Plausible.DebugReplayInfo, only: [include_sentry_replay_info: 0]
end
end
defmacro include_sentry_replay_info() do
module = __CALLER__.module
{function, arity} = __CALLER__.function
f = Function.capture(module, function, arity)
quote bind_quoted: [f: f] do
replay_info =
{f, binding()}
|> :erlang.term_to_iovec([:compressed])
|> IO.iodata_to_binary()
|> Base.encode64()
payload_size = byte_size(replay_info)
if payload_size <= 10_000 do
Sentry.Context.set_extra_context(%{
debug_replay_info: replay_info,
debug_replay_info_size: payload_size
})
else
Sentry.Context.set_extra_context(%{
debug_replay_info: :too_large,
debug_replay_info_size: payload_size
})
end
:ok
end
end
@spec deserialize(String.t()) :: any()
def deserialize(replay_info) do
replay_info
|> Base.decode64!()
|> :erlang.binary_to_term()
end
end

View File

@ -1,10 +1,42 @@
defmodule Plausible.Stats do
defdelegate breakdown(site, query, prop, metrics, pagination), to: Plausible.Stats.Breakdown
defdelegate aggregate(site, query, metrics), to: Plausible.Stats.Aggregate
defdelegate timeseries(site, query, metrics), to: Plausible.Stats.Timeseries
defdelegate current_visitors(site), to: Plausible.Stats.CurrentVisitors
defdelegate funnel(site, query, funnel), to: Plausible.Stats.Funnel
alias Plausible.Stats.{
Breakdown,
Aggregate,
Timeseries,
CurrentVisitors,
Funnel,
FilterSuggestions
}
defdelegate filter_suggestions(site, query, filter_name, filter_search),
to: Plausible.Stats.FilterSuggestions
use Plausible.DebugReplayInfo
def breakdown(site, query, prop, metrics, pagination) do
include_sentry_replay_info()
Breakdown.breakdown(site, query, prop, metrics, pagination)
end
def aggregate(site, query, metrics) do
include_sentry_replay_info()
Aggregate.aggregate(site, query, metrics)
end
def timeseries(site, query, metrics) do
include_sentry_replay_info()
Timeseries.timeseries(site, query, metrics)
end
def current_visitors(site) do
include_sentry_replay_info()
CurrentVisitors.current_visitors(site)
end
def funnel(site, query, funnel) do
include_sentry_replay_info()
Funnel.funnel(site, query, funnel)
end
def filter_suggestions(site, query, filter_name, filter_search) do
include_sentry_replay_info()
FilterSuggestions.filter_suggestions(site, query, filter_name, filter_search)
end
end

View File

@ -0,0 +1,48 @@
defmodule Plausible.DebugReplayInfoTest do
use Plausible.DataCase, async: true
defmodule SampleModule do
use Plausible.DebugReplayInfo
def task(site, query, report_to) do
include_sentry_replay_info()
send(report_to, {:task_done, Sentry.Context.get_all()})
{:ok, {site, query}}
end
end
test "adds replayable sentry context" do
site = build(:site)
query = Plausible.Stats.Query.from(site, %{"period" => "day"})
{:ok, {^site, ^query}} = SampleModule.task(site, query, self())
assert_receive {:task_done, context}
assert is_integer(context.extra.debug_replay_info_size)
assert info = context.extra.debug_replay_info
{function, input} = Plausible.DebugReplayInfo.deserialize(info)
assert function == (&SampleModule.task/3)
assert input[:site] == site
assert input[:query] == query
assert input[:report_to] == self()
assert apply(function, [input[:site], input[:query], input[:report_to]])
assert_receive {:task_done, ^context}
end
test "won't add replay info, if serialized input too large" do
{:ok, _} =
SampleModule.task(
:crypto.strong_rand_bytes(10_000),
:crypto.strong_rand_bytes(10_000),
self()
)
assert_receive {:task_done, context}
assert context.extra.debug_replay_info == :too_large
assert context.extra.debug_replay_info_size > 10_000
end
end