Skip to content

Commit fa43765

Browse files
committed
updated test + third round of feedback
1 parent d639c0b commit fa43765

File tree

8 files changed

+94
-49
lines changed

8 files changed

+94
-49
lines changed

lib/sentry.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ defmodule Sentry do
179179
> with `:source_code_exclude_patterns`.
180180
"""
181181

182-
alias Sentry.{CheckIn, Client, ClientError, Config, Event, LoggerUtils, Options, Transport}
182+
alias Sentry.{CheckIn, Client, ClientError, ClientReport, Config, Event, LoggerUtils, Options}
183183

184184
require Logger
185185

@@ -341,7 +341,7 @@ defmodule Sentry do
341341
cond do
342342
is_nil(event.message) and event.exception == [] ->
343343
LoggerUtils.log("Cannot report event without message or exception: #{inspect(event)}")
344-
Transport.record_discarded_event(:event_processor, event)
344+
ClientReport.record_discarded_events(:event_processor, [event])
345345
:ignored
346346

347347
# If we're in test mode, let's send the event down the pipeline anyway.

lib/sentry/client.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ defmodule Sentry.Client do
88
alias Sentry.{
99
CheckIn,
1010
ClientError,
11+
ClientReport,
1112
Config,
1213
Dedupe,
1314
Envelope,
1415
Event,
1516
Interfaces,
1617
LoggerUtils,
1718
Transport,
18-
Options,
19-
ClientReport
19+
Options
2020
}
2121

2222
require Logger
@@ -82,7 +82,7 @@ defmodule Sentry.Client do
8282
:unsampled ->
8383
# See https://github.com/getsentry/develop/pull/551/files
8484
Sentry.put_last_event_id_and_source(event.event_id, event.source)
85-
Transport.record_discarded_event(:sample_rate, event)
85+
ClientReport.record_discarded_events(:sample_rate, [event])
8686
:unsampled
8787

8888
:excluded ->

lib/sentry/client_report.ex

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ defmodule Sentry.ClientReport do
88
@moduledoc since: "10.8.0"
99

1010
use GenServer
11-
alias Sentry.{Client, Config}
11+
alias Sentry.{Client, Config, Envelope}
1212

1313
@client_report_reasons [
1414
:ratelimit_backoff,
@@ -19,7 +19,9 @@ defmodule Sentry.ClientReport do
1919
:before_send,
2020
:event_processor,
2121
:insufficient_data,
22-
:backpressure
22+
:backpressure,
23+
:send_error,
24+
:internal_sdk_error
2325
]
2426

2527
@typedoc """
@@ -42,16 +44,36 @@ defmodule Sentry.ClientReport do
4244

4345
@doc false
4446
@spec start_link([]) :: GenServer.on_start()
45-
def start_link([]) do
46-
GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
47+
def start_link(opts \\ []) do
48+
GenServer.start_link(__MODULE__, %{}, name: Keyword.get(opts, :name, __MODULE__))
4749
end
4850

49-
@spec add_discarded_event(reason(), String.t()) :: :ok
50-
def add_discarded_event(reason, category) do
51+
@doc false
52+
@spec record_discarded_events(
53+
reason(),
54+
[item]
55+
) :: :ok
56+
when item:
57+
Sentry.Attachment.t()
58+
| Sentry.CheckIn.t()
59+
| Sentry.ClientReport.t()
60+
| Sentry.Event.t()
61+
def record_discarded_events(reason, event_items, genserver \\ __MODULE__)
62+
when is_list(event_items) do
5163
if Enum.member?(@client_report_reasons, reason) do
52-
GenServer.cast(__MODULE__, {:add_discarded_event, reason, category})
64+
_ =
65+
event_items
66+
|> Enum.each(
67+
&GenServer.cast(
68+
genserver,
69+
{:record_discarded_events, reason, Envelope.get_data_category(&1)}
70+
)
71+
)
5372
end
5473

74+
# We silently ignore events whose reasons aren't valid because we have to add it to the allowlist in Snuba
75+
# https://develop.sentry.dev/sdk/client-reports/
76+
5577
:ok
5678
end
5779

@@ -64,7 +86,7 @@ defmodule Sentry.ClientReport do
6486

6587
@doc false
6688
@impl true
67-
def handle_cast({:add_discarded_event, reason, category}, discarded_events) do
89+
def handle_cast({:record_discarded_events, reason, category}, discarded_events) do
6890
{:noreply, Map.update(discarded_events, {reason, category}, 1, &(&1 + 1))}
6991
end
7092

lib/sentry/envelope.ex

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ defmodule Sentry.Envelope do
4848

4949
@spec get_data_category(Attachment.t() | CheckIn.t() | ClientReport.t() | Event.t()) ::
5050
String.t()
51-
def get_data_category(type) do
51+
def get_data_category(%mod{} = type) when mod in [Attachment, CheckIn, ClientReport, Event] do
5252
case type do
5353
%Attachment{} ->
5454
"attachment"
@@ -61,12 +61,6 @@ defmodule Sentry.Envelope do
6161

6262
%Event{} ->
6363
"error"
64-
65-
_ ->
66-
raise ArgumentError, """
67-
data category only accepts defined structs but was passed the invalid:
68-
#{inspect(type)}\
69-
"""
7064
end
7165
end
7266

lib/sentry/transport.ex

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,6 @@ defmodule Sentry.Transport do
3939
result
4040
end
4141

42-
def record_discarded_event(reason, event_item) do
43-
_ =
44-
event_item
45-
|> List.wrap()
46-
|> Enum.each(&ClientReport.add_discarded_event(reason, Envelope.get_data_category(&1)))
47-
48-
# We silently ignore events whose reasons aren't valid because we have to add it to the allowlist in Snuba
49-
# https://develop.sentry.dev/sdk/client-reports/
50-
:ok
51-
end
52-
5342
defp post_envelope_with_retries(
5443
client,
5544
endpoint,
@@ -77,7 +66,7 @@ defmodule Sentry.Transport do
7766
)
7867

7968
{:retry_after, _delay_ms} ->
80-
record_discarded_event(:ratelimit_backoff, envelope_items)
69+
ClientReport.record_discarded_events(:ratelimit_backoff, envelope_items)
8170
{:error, ClientError.new(:too_many_retries)}
8271

8372
{:error, _reason} when retries_left != [] ->
@@ -94,11 +83,11 @@ defmodule Sentry.Transport do
9483
)
9584

9685
{:error, {:http, {status, headers, body}}} ->
97-
record_discarded_event(:send_error, envelope_items)
86+
ClientReport.record_discarded_events(:send_error, envelope_items)
9887
{:error, ClientError.server_error(status, headers, body)}
9988

10089
{:error, reason} ->
101-
record_discarded_event(:send_error, envelope_items)
90+
ClientReport.record_discarded_events(:send_error, envelope_items)
10291
{:error, ClientError.new(reason)}
10392
end
10493
end

test/envelope_test.exs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,7 @@ defmodule Sentry.EnvelopeTest do
145145
timestamp: "2024-10-12T13:21:13"
146146
}) == "error"
147147

148-
assert_raise ArgumentError,
149-
~r/data category only accepts defined structs but was passed the invalid:\n:completely_banana_value/,
148+
assert_raise FunctionClauseError,
150149
fn -> Envelope.get_data_category(:completely_banana_value) end
151150
end
152151
end

test/sentry/client_report_test.exs

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,34 @@
11
defmodule Sentry.ClientReportTest do
2-
use Sentry.Case, async: true
2+
use Sentry.Case, async: false
33

4-
alias Sentry.ClientReport
4+
alias Sentry.{ClientReport, Event}
55

6-
describe "add_discarded_event/1" do
7-
test "records discarded event to state" do
8-
assert :sys.get_state(ClientReport) == %{}
6+
describe "record_discarded_events/2" do
7+
test "succefully records the discarded event to the client report" do
8+
{:ok, _clientreport} = start_supervised({ClientReport, [name: :test_client_report]})
99

10-
ClientReport.add_discarded_event(:event_processor, "error")
10+
events = [
11+
%Event{
12+
event_id: Sentry.UUID.uuid4_hex(),
13+
timestamp: "2024-10-12T13:21:13"
14+
}
15+
]
1116

12-
assert :sys.get_state(ClientReport) == %{{:event_processor, "error"} => 1}
17+
assert ClientReport.record_discarded_events(:before_send, events, :test_client_report) ==
18+
:ok
1319

14-
ClientReport.add_discarded_event(:event_processor, "error")
15-
ClientReport.add_discarded_event(:event_processor, "error")
16-
ClientReport.add_discarded_event(:network_error, "error")
20+
assert :sys.get_state(:test_client_report) == %{{:before_send, "error"} => 1}
1721

18-
# updates quantity when duplcate events are sent
19-
assert :sys.get_state(ClientReport) == %{
20-
{:event_processor, "error"} => 3,
22+
ClientReport.record_discarded_events(:before_send, events, :test_client_report)
23+
24+
assert :sys.get_state(:test_client_report) == %{{:before_send, "error"} => 2}
25+
26+
ClientReport.record_discarded_events(:event_processor, events, :test_client_report)
27+
ClientReport.record_discarded_events(:network_error, events, :test_client_report)
28+
29+
assert :sys.get_state(:test_client_report) == %{
30+
{:before_send, "error"} => 2,
31+
{:event_processor, "error"} => 1,
2132
{:network_error, "error"} => 1
2233
}
2334
end

test/sentry/client_test.exs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,4 +418,34 @@ defmodule Sentry.ClientTest do
418418
end
419419
end
420420
end
421+
422+
describe "send_client_report/1" do
423+
test "succefully sends discarded events to Sentry" do
424+
bypass = Bypass.open()
425+
put_test_config(dsn: "http://public:secret@localhost:#{bypass.port}/1")
426+
427+
client_report =
428+
%Sentry.ClientReport{
429+
timestamp: "2024-10-15T14:22:49",
430+
discarded_events: [
431+
%{reason: :event_processor, category: "error", quantity: 1}
432+
]
433+
}
434+
435+
Bypass.expect_once(bypass, fn conn ->
436+
{:ok, body, conn} = Plug.Conn.read_body(conn)
437+
assert [{_headers, client_report_body}] = decode_envelope!(body)
438+
439+
assert client_report_body["discarded_events"] == [
440+
%{"category" => "error", "quantity" => 1, "reason" => "event_processor"}
441+
]
442+
443+
assert client_report_body["timestamp"] == "2024-10-15T14:22:49"
444+
445+
Plug.Conn.resp(conn, 200, ~s<{"id": "340"}>)
446+
end)
447+
448+
assert {:ok, "340"} = Client.send_client_report(client_report)
449+
end
450+
end
421451
end

0 commit comments

Comments
 (0)