Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/sentry-handler-opts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@core/sync-service': patch
---

`Electric.Telemetry.Sentry.add_logger_handler/1` now accepts an optional second argument — a keyword list whose entries are merged into the `Sentry.LoggerHandler` config map — so downstream apps can tune handler settings like `:discard_threshold` and `:sync_threshold` without reaching into `:logger` after the fact. The existing single-arg `add_logger_handler(id)` form is preserved.
24 changes: 17 additions & 7 deletions packages/sync-service/lib/electric/telemetry/sentry.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,29 @@ defmodule Electric.Telemetry.Sentry do
use Electric.Telemetry

@default_handler_id :electric_sentry_handler
@default_config %{metadata: :all, capture_log_messages: true, level: :error}

@spec add_logger_handler(handler_id :: atom()) :: :ok | {:error, term()}
@typedoc """
Extra entries for the `Sentry.LoggerHandler` config map (e.g.
`:discard_threshold`, `:sync_threshold`). Merged over the defaults at
install time.
"""
@type handler_opts :: [{atom(), term()}]

def default_handler_id, do: @default_handler_id

@spec add_logger_handler(atom(), handler_opts()) :: :ok | {:error, term()}
@spec add_logger_handler(atom()) :: :ok | {:error, term()}
@spec add_logger_handler() :: :ok | {:error, term()}
def add_logger_handler(id \\ @default_handler_id)
def add_logger_handler(id \\ @default_handler_id, opts \\ [])

with_telemetry Sentry.LoggerHandler do
def add_logger_handler(id) do
:logger.add_handler(id, Sentry.LoggerHandler, %{
config: %{metadata: :all, capture_log_messages: true, level: :error}
})
def add_logger_handler(id, opts) do
config = Map.merge(@default_config, Map.new(opts))
:logger.add_handler(id, Sentry.LoggerHandler, %{config: config})
end
else
def add_logger_handler(_id), do: :ok
def add_logger_handler(_id, _opts), do: :ok
end

@spec set_tags_context(keyword()) :: :ok
Expand Down
66 changes: 66 additions & 0 deletions packages/sync-service/test/electric/telemetry/sentry_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
if Electric.telemetry_enabled?() and Code.ensure_loaded?(Sentry.LoggerHandler) do
defmodule Electric.Telemetry.SentryTest do
# async: false because :logger handler state is VM-global — unique ids per
# test avoid name collisions but not the add/remove race across processes.
use ExUnit.Case, async: false

alias Electric.Telemetry.Sentry, as: ElectricSentry

setup do
id = :"sentry_test_#{System.unique_integer([:positive])}"
on_exit(fn -> _ = :logger.remove_handler(id) end)
{:ok, handler_id: id}
end

defp handler_config!(id) do
{:ok, %{config: config}} = :logger.get_handler_config(id)
config
end

describe "add_logger_handler/2" do
test "installs Sentry.LoggerHandler with default config", %{handler_id: id} do
assert :ok = ElectricSentry.add_logger_handler(id)

{:ok, handler} = :logger.get_handler_config(id)
assert handler.module == Sentry.LoggerHandler

assert %{metadata: :all, capture_log_messages: true, level: :error} =
handler_config!(id)
end

test "merges caller-supplied options into the handler config",
%{handler_id: id} do
assert :ok =
ElectricSentry.add_logger_handler(id,
discard_threshold: 2000,
sync_threshold: nil
)

assert %{
metadata: :all,
capture_log_messages: true,
level: :error,
discard_threshold: 2000,
sync_threshold: nil
} = handler_config!(id)
end

test "caller-supplied options override defaults", %{handler_id: id} do
assert :ok = ElectricSentry.add_logger_handler(id, level: :warning)

assert %{level: :warning} = handler_config!(id)
end

test "uses the default handler id when called with no arguments" do
default_id = ElectricSentry.default_handler_id()
_ = :logger.remove_handler(default_id)
on_exit(fn -> _ = :logger.remove_handler(default_id) end)

assert :ok = ElectricSentry.add_logger_handler()

{:ok, handler} = :logger.get_handler_config(default_id)
assert handler.module == Sentry.LoggerHandler
end
end
end
end
Loading