Skip to content

Commit baf6932

Browse files
committed
WIP: support for check-ins in Telemetry Processor
1 parent a6940b1 commit baf6932

8 files changed

Lines changed: 142 additions & 36 deletions

File tree

lib/sentry/client.ex

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,22 @@ defmodule Sentry.Client do
2929
@spec send_check_in(CheckIn.t(), keyword()) ::
3030
{:ok, check_in_id :: String.t()} | {:error, ClientError.t()}
3131
def send_check_in(%CheckIn{} = check_in, opts) when is_list(opts) do
32-
client = Keyword.get_lazy(opts, :client, &Config.client/0)
32+
if Config.telemetry_processor_category?(:check_in) do
33+
:ok = TelemetryProcessor.add(check_in)
34+
{:ok, check_in.check_in_id}
35+
else
36+
client = Keyword.get_lazy(opts, :client, &Config.client/0)
3337

34-
# This is a "private" option, only really used in testing.
35-
request_retries =
36-
Keyword.get_lazy(opts, :request_retries, fn ->
37-
Application.get_env(:sentry, :request_retries, Transport.default_retries())
38-
end)
38+
# This is a "private" option, only really used in testing.
39+
request_retries =
40+
Keyword.get_lazy(opts, :request_retries, fn ->
41+
Application.get_env(:sentry, :request_retries, Transport.default_retries())
42+
end)
3943

40-
send_result =
4144
check_in
4245
|> Envelope.from_check_in()
4346
|> Transport.encode_and_post_envelope(client, request_retries)
44-
45-
send_result
47+
end
4648
end
4749

4850
# This is what executes the "Event Pipeline".

lib/sentry/config.ex

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -495,26 +495,24 @@ defmodule Sentry.Config do
495495
"""
496496
],
497497
telemetry_buffer_capacities: [
498-
type: {:map, {:in, [:log]}, :pos_integer},
498+
type: {:map, {:in, [:error, :check_in, :log]}, :pos_integer},
499499
default: %{},
500500
type_doc: "`%{category => pos_integer()}`",
501501
doc: """
502502
Overrides for the maximum number of items each telemetry buffer can hold.
503503
When a buffer reaches capacity, oldest items are dropped to make room.
504-
Currently only the `:log` category is managed by the TelemetryProcessor.
505-
Default: log=1000.
504+
Default: error=100, check_in=100, log=1000.
506505
*Available since v12.0.0*.
507506
"""
508507
],
509508
telemetry_scheduler_weights: [
510-
type: {:map, {:in, [:low]}, :pos_integer},
509+
type: {:map, {:in, [:critical, :high, :low]}, :pos_integer},
511510
default: %{},
512511
type_doc: "`%{priority => pos_integer()}`",
513512
doc: """
514513
Overrides for the weighted round-robin scheduler priority weights.
515514
Higher weights mean more sending slots for that priority level.
516-
Currently only the `:low` priority (logs) is managed by the TelemetryProcessor.
517-
Default: low=2.
515+
Default: critical=5, high=4, low=2.
518516
*Available since v12.0.0*.
519517
"""
520518
],

lib/sentry/telemetry/category.ex

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,23 @@ defmodule Sentry.Telemetry.Category do
88
## Categories
99
1010
* `:error` - Error events (critical priority)
11+
* `:check_in` - Cron check-ins (high priority)
1112
* `:log` - Log entries (low priority)
1213
1314
## Priorities and Weights
1415
1516
* `:critical` - weight 5 (errors)
17+
* `:high` - weight 4 (check-ins)
1618
* `:low` - weight 2 (logs)
1719
1820
"""
1921
@moduledoc since: "12.0.0"
2022

2123
@typedoc "Telemetry category types."
22-
@type t :: :error | :log
24+
@type t :: :error | :check_in | :log
2325

2426
@typedoc "Priority levels for categories."
25-
@type priority :: :critical | :low
27+
@type priority :: :critical | :high | :low
2628

2729
@typedoc "Buffer configuration for a category."
2830
@type config :: %{
@@ -31,16 +33,18 @@ defmodule Sentry.Telemetry.Category do
3133
timeout: pos_integer() | nil
3234
}
3335

34-
@priorities [:critical, :low]
35-
@categories [:error, :log]
36+
@priorities [:critical, :high, :low]
37+
@categories [:error, :check_in, :log]
3638

3739
@weights %{
3840
critical: 5,
41+
high: 4,
3942
low: 2
4043
}
4144

4245
@default_configs %{
4346
error: %{capacity: 100, batch_size: 1, timeout: nil},
47+
check_in: %{capacity: 100, batch_size: 1, timeout: nil},
4448
log: %{capacity: 1000, batch_size: 100, timeout: 5000}
4549
}
4650

@@ -52,12 +56,16 @@ defmodule Sentry.Telemetry.Category do
5256
iex> Sentry.Telemetry.Category.priority(:error)
5357
:critical
5458
59+
iex> Sentry.Telemetry.Category.priority(:check_in)
60+
:high
61+
5562
iex> Sentry.Telemetry.Category.priority(:log)
5663
:low
5764
5865
"""
5966
@spec priority(t()) :: priority()
6067
def priority(:error), do: :critical
68+
def priority(:check_in), do: :high
6169
def priority(:log), do: :low
6270

6371
@doc """
@@ -67,6 +75,9 @@ defmodule Sentry.Telemetry.Category do
6775
6876
## Examples
6977
78+
iex> Sentry.Telemetry.Category.weight(:high)
79+
4
80+
7081
iex> Sentry.Telemetry.Category.weight(:low)
7182
2
7283
@@ -90,6 +101,9 @@ defmodule Sentry.Telemetry.Category do
90101
iex> Sentry.Telemetry.Category.default_config(:error)
91102
%{capacity: 100, batch_size: 1, timeout: nil}
92103
104+
iex> Sentry.Telemetry.Category.default_config(:check_in)
105+
%{capacity: 100, batch_size: 1, timeout: nil}
106+
93107
iex> Sentry.Telemetry.Category.default_config(:log)
94108
%{capacity: 1000, batch_size: 100, timeout: 5000}
95109
@@ -105,7 +119,7 @@ defmodule Sentry.Telemetry.Category do
105119
## Examples
106120
107121
iex> Sentry.Telemetry.Category.all()
108-
[:error, :log]
122+
[:error, :check_in, :log]
109123
110124
"""
111125
@spec all() :: [t()]
@@ -117,7 +131,7 @@ defmodule Sentry.Telemetry.Category do
117131
## Examples
118132
119133
iex> Sentry.Telemetry.Category.priorities()
120-
[:critical, :low]
134+
[:critical, :high, :low]
121135
122136
"""
123137
@spec priorities() :: [priority()]

lib/sentry/telemetry/scheduler.ex

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ defmodule Sentry.Telemetry.Scheduler do
88
## Weights
99
1010
* `:critical` - weight 5 (errors)
11+
* `:high` - weight 4 (check-ins)
1112
* `:low` - weight 2 (logs)
1213
1314
## Signal-Based Wake
@@ -33,12 +34,13 @@ defmodule Sentry.Telemetry.Scheduler do
3334
alias __MODULE__
3435

3536
alias Sentry.Telemetry.{Buffer, Category}
36-
alias Sentry.{ClientReport, Config, Envelope, Event, LogEvent, Transport}
37+
alias Sentry.{CheckIn, ClientReport, Config, Envelope, Event, LogEvent, Transport}
3738

3839
@default_capacity 1000
3940

4041
@type buffers :: %{
4142
error: GenServer.server(),
43+
check_in: GenServer.server(),
4244
log: GenServer.server()
4345
}
4446

@@ -77,7 +79,7 @@ defmodule Sentry.Telemetry.Scheduler do
7779
## Examples
7880
7981
iex> Sentry.Telemetry.Scheduler.build_priority_cycle()
80-
[:error, :error, :error, :error, :error, :log, :log]
82+
[:error, :error, :error, :error, :error, :check_in, :check_in, :check_in, :check_in, :log, :log]
8183
8284
"""
8385
@spec build_priority_cycle(map() | nil) :: [Category.t()]
@@ -237,6 +239,10 @@ defmodule Sentry.Telemetry.Scheduler do
237239
process_and_send_event(state, event, &send_envelope/2)
238240
end
239241

242+
defp send_items(state, :check_in, [%CheckIn{} = check_in]) do
243+
process_and_send_check_in(state, check_in, &send_envelope/2)
244+
end
245+
240246
defp send_items(state, :log, log_events) do
241247
process_and_send_logs(state, log_events, &send_envelope/2)
242248
end
@@ -252,6 +258,11 @@ defmodule Sentry.Telemetry.Scheduler do
252258
process_and_send_event(state, event, &send_envelope_direct/2)
253259
end)
254260

261+
:check_in ->
262+
Enum.each(items, fn check_in ->
263+
process_and_send_check_in(state, check_in, &send_envelope_direct/2)
264+
end)
265+
255266
:log ->
256267
process_and_send_logs(state, items, &send_envelope_direct/2)
257268
end
@@ -278,6 +289,11 @@ defmodule Sentry.Telemetry.Scheduler do
278289
end
279290
end
280291

292+
defp process_and_send_check_in(state, %CheckIn{} = check_in, send_fn) do
293+
envelope = Envelope.from_check_in(check_in)
294+
send_fn.(state, envelope)
295+
end
296+
281297
defp process_and_send_logs(%{on_envelope: on_envelope} = state, log_events, send_fn) do
282298
processed_logs = apply_before_send_log_callbacks(log_events)
283299

@@ -452,13 +468,15 @@ defmodule Sentry.Telemetry.Scheduler do
452468
defp default_weights do
453469
%{
454470
critical: Category.weight(:critical),
471+
high: Category.weight(:high),
455472
low: Category.weight(:low)
456473
}
457474
end
458475

459476
defp category_priority_mapping do
460477
[
461478
{:error, :critical},
479+
{:check_in, :high},
462480
{:log, :low}
463481
]
464482
end

lib/sentry/telemetry_processor.ex

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ defmodule Sentry.TelemetryProcessor do
1111
The processor starts as a supervisor with the following children:
1212
1313
* Error Buffer - for error events (critical priority)
14+
* Check-in Buffer - for cron check-ins (high priority)
1415
* Log Buffer - for log entries (low priority)
1516
* Scheduler - weighted round-robin scheduler with integrated transport queue
1617
@@ -19,6 +20,9 @@ defmodule Sentry.TelemetryProcessor do
1920
# Add error events to the buffer
2021
TelemetryProcessor.add(processor, %Sentry.Event{...})
2122
23+
# Add check-ins to the buffer
24+
TelemetryProcessor.add(processor, %Sentry.CheckIn{...})
25+
2226
# Add log events to the buffer
2327
TelemetryProcessor.add(processor, %Sentry.LogEvent{...})
2428
@@ -31,7 +35,7 @@ defmodule Sentry.TelemetryProcessor do
3135
use Supervisor
3236

3337
alias Sentry.Telemetry.{Buffer, Category, Scheduler}
34-
alias Sentry.{Event, LogEvent}
38+
alias Sentry.{CheckIn, Event, LogEvent}
3539

3640
@default_name __MODULE__
3741

@@ -87,11 +91,15 @@ defmodule Sentry.TelemetryProcessor do
8791
8892
Returns `:ok`.
8993
"""
90-
@spec add(Event.t() | LogEvent.t()) :: :ok
94+
@spec add(Event.t() | CheckIn.t() | LogEvent.t()) :: :ok
9195
def add(%Event{} = item) do
9296
add(processor_name(), item)
9397
end
9498

99+
def add(%CheckIn{} = item) do
100+
add(processor_name(), item)
101+
end
102+
95103
def add(%LogEvent{} = item) do
96104
add(processor_name(), item)
97105
end
@@ -103,7 +111,7 @@ defmodule Sentry.TelemetryProcessor do
103111
104112
Returns `:ok`.
105113
"""
106-
@spec add(Supervisor.supervisor(), Event.t() | LogEvent.t()) :: :ok
114+
@spec add(Supervisor.supervisor(), Event.t() | CheckIn.t() | LogEvent.t()) :: :ok
107115
def add(processor, %Event{} = item) when is_atom(processor) do
108116
Buffer.add(buffer_name(processor, :error), item)
109117
Scheduler.signal(scheduler_name(processor))
@@ -118,6 +126,20 @@ defmodule Sentry.TelemetryProcessor do
118126
:ok
119127
end
120128

129+
def add(processor, %CheckIn{} = item) when is_atom(processor) do
130+
Buffer.add(buffer_name(processor, :check_in), item)
131+
Scheduler.signal(scheduler_name(processor))
132+
:ok
133+
end
134+
135+
def add(processor, %CheckIn{} = item) do
136+
buffer = get_buffer(processor, :check_in)
137+
Buffer.add(buffer, item)
138+
scheduler = get_scheduler(processor)
139+
Scheduler.signal(scheduler)
140+
:ok
141+
end
142+
121143
def add(processor, %LogEvent{} = item) when is_atom(processor) do
122144
Buffer.add(buffer_name(processor, :log), item)
123145
Scheduler.signal(scheduler_name(processor))
@@ -165,7 +187,7 @@ defmodule Sentry.TelemetryProcessor do
165187
Returns the buffer pid for a given category.
166188
"""
167189
@spec get_buffer(Supervisor.supervisor(), Category.t()) :: pid()
168-
def get_buffer(processor, category) when category in [:error, :log] do
190+
def get_buffer(processor, category) when category in [:error, :check_in, :log] do
169191
children = Supervisor.which_children(processor)
170192
buffer_id = buffer_id(category)
171193

@@ -195,7 +217,7 @@ defmodule Sentry.TelemetryProcessor do
195217
Returns 0 if the processor is not running.
196218
"""
197219
@spec buffer_size(Category.t()) :: non_neg_integer()
198-
def buffer_size(category) when category in [:error, :log] do
220+
def buffer_size(category) when category in [:error, :check_in, :log] do
199221
buffer_size(processor_name(), category)
200222
end
201223

@@ -205,7 +227,7 @@ defmodule Sentry.TelemetryProcessor do
205227
Returns 0 if the processor is not running.
206228
"""
207229
@spec buffer_size(Supervisor.supervisor(), Category.t()) :: non_neg_integer()
208-
def buffer_size(processor, category) when category in [:error, :log] do
230+
def buffer_size(processor, category) when category in [:error, :check_in, :log] do
209231
case safe_get_buffer(processor, category) do
210232
{:ok, buffer} -> Buffer.size(buffer)
211233
:error -> 0
@@ -267,6 +289,7 @@ defmodule Sentry.TelemetryProcessor do
267289
[
268290
buffers: %{
269291
error: Map.fetch!(buffer_names, :error),
292+
check_in: Map.fetch!(buffer_names, :check_in),
270293
log: Map.fetch!(buffer_names, :log)
271294
},
272295
name: scheduler_name(processor_name),
@@ -286,6 +309,7 @@ defmodule Sentry.TelemetryProcessor do
286309
end
287310

288311
defp buffer_id(:error), do: :error_buffer
312+
defp buffer_id(:check_in), do: :check_in_buffer
289313
defp buffer_id(:log), do: :log_buffer
290314

291315
@doc false

test/sentry/telemetry/scheduler_test.exs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,17 @@ defmodule Sentry.Telemetry.SchedulerTest do
1919
test "builds cycle with correct weights for all categories" do
2020
cycle = Scheduler.build_priority_cycle()
2121

22-
# Default weights: critical=5, low=2
23-
assert length(cycle) == 7
24-
assert Enum.frequencies(cycle) == %{error: 5, log: 2}
22+
# Default weights: critical=5, high=4, low=2
23+
assert length(cycle) == 11
24+
assert Enum.frequencies(cycle) == %{error: 5, check_in: 4, log: 2}
2525
end
2626

2727
test "builds cycle with custom weights" do
2828
custom_weights = %{low: 5}
2929
cycle = Scheduler.build_priority_cycle(custom_weights)
3030

31-
assert length(cycle) == 10
32-
assert Enum.frequencies(cycle) == %{error: 5, log: 5}
31+
assert length(cycle) == 14
32+
assert Enum.frequencies(cycle) == %{error: 5, check_in: 4, log: 5}
3333
end
3434
end
3535

0 commit comments

Comments
 (0)