View Source Sentry.Test (Sentry v13.0.1)

Utilities for testing Sentry reports.

Usage

This module provides helpers that set up a local HTTP server (via Bypass) so that Sentry SDK calls in your tests hit a local endpoint instead of the real Sentry API. Events are captured via the existing before_send and before_send_log callbacks and stored in an isolated ETS table per test, preserving the full struct data.

Bypass Required

This module requires bypass as a test dependency:

{:bypass, "~> 2.0", only: [:test]}

Examples

The simplest way to use this module is with the setup_sentry/1 function:

defmodule MyApp.ErrorReportingTest do
  use ExUnit.Case, async: true

  setup do
    Sentry.Test.setup_sentry()
  end

  test "reports exceptions to Sentry" do
    try do
      raise "boom"
    rescue
      e -> Sentry.capture_exception(e)
    end

    assert [%Sentry.Event{} = event] = Sentry.Test.pop_sentry_reports()
    assert event.original_exception == %RuntimeError{message: "boom"}
  end
end

You can also use start_collecting_sentry_reports/0 as an ExUnit setup callback for backwards compatibility:

setup :start_collecting_sentry_reports

Assertion Helpers

See Sentry.Test.Assertions for convenient assertion functions that reduce boilerplate when validating captured events, transactions, and logs.

Summary

Functions

Allows pid_to_allow to collect events back to the root process via owner_pid.

cleanup(owner_pid) deprecated

Cleans up test resources associated with owner_pid.

Collects decoded envelopes sent to a Bypass collector.

Collects check-in payloads sent through a Bypass envelope collector.

Collects events sent through a Bypass envelope collector.

Collects log items sent through a Bypass envelope collector.

Collects metric batch payloads sent through a Bypass envelope collector.

Collects transactions sent through a Bypass envelope collector.

Decodes a raw envelope binary into a list of {header, item} tuples.

Extracts check-in payloads from decoded envelope item lists.

Extracts event payloads from decoded envelope item lists.

Extracts log item payloads from decoded envelope item lists.

Extracts metric batch payloads from decoded envelope item lists.

Extracts transaction payloads from decoded envelope item lists.

Pops all the collected log events from the current process.

Pops all the collected metrics from the current process.

Pops all the collected events from the current process.

Pops all the collected transactions from the current process.

Sets up a Bypass envelope collector that forwards envelope bodies to the test process as messages.

Sets up a Bypass instance and configures Sentry for testing.

Starts an isolated, per-test Sentry.TelemetryProcessor and wires it into the current test's config scope.

Starts collecting events.

Starts collecting events from the current process.

Functions

Link to this function

allow_sentry_reports(owner_pid, pid_to_allow)

View Source (since 10.2.0)
This function is deprecated. Child processes are now automatically tracked via $callers.
@spec allow_sentry_reports(pid(), pid() | (() -> pid())) :: :ok

Allows pid_to_allow to collect events back to the root process via owner_pid.

Deprecated

This function is deprecated and will be removed in v13.0.0. Child processes are automatically tracked via the $callers mechanism. There is no need to explicitly allow processes.

Link to this function

cleanup(owner_pid)

View Source (since 10.2.0)
This function is deprecated. Cleanup is now automatic via on_exit callbacks.
@spec cleanup(pid()) :: :ok

Cleans up test resources associated with owner_pid.

Deprecated

This function is deprecated and will be removed in v13.0.0. Cleanup is now handled automatically via on_exit callbacks.

Link to this function

collect_envelopes(ref, expected_count, opts \\ [])

View Source (since 13.0.0)
@spec collect_envelopes(reference(), pos_integer(), keyword()) :: [[{map(), map()}]]

Collects decoded envelopes sent to a Bypass collector.

Returns a list of decoded envelope item lists. Each element is the result of decode_envelope!/1 for one HTTP request.

Options

  • :timeout - timeout in ms to wait for each envelope (default: 1000)
Link to this function

collect_sentry_check_ins(ref, expected_count, opts \\ [])

View Source (since 13.0.0)
@spec collect_sentry_check_ins(reference(), pos_integer(), keyword()) :: [map()]

Collects check-in payloads sent through a Bypass envelope collector.

This is a high-level helper combining collect_envelopes/3 and extract_check_ins/1. Use this instead of manually destructuring [[{header, body}]] from collect_envelopes/3.

Options

  • :timeout - timeout in ms to wait for each envelope (default: 1000)

Examples

ref = setup_bypass_envelope_collector(bypass, type: "check_in")
Sentry.capture_check_in(status: :ok, monitor_slug: "my-job")
[check_in] = collect_sentry_check_ins(ref, 1)
assert check_in["status"] == "ok"
Link to this function

collect_sentry_events(ref, expected_count, opts \\ [])

View Source (since 13.0.0)
@spec collect_sentry_events(reference(), pos_integer(), keyword()) :: [map()]

Collects events sent through a Bypass envelope collector.

This is a high-level helper combining collect_envelopes/3 and extract_events/1. Use this instead of collect_envelopes(ref, count) |> extract_events().

Options

  • :timeout - timeout in ms to wait for each envelope (default: 1000)

Examples

ref = setup_bypass_envelope_collector(bypass)
trigger_event()
[event] = collect_sentry_events(ref, 1)
Link to this function

collect_sentry_logs(ref, expected_count, opts \\ [])

View Source (since 13.0.0)
@spec collect_sentry_logs(reference(), pos_integer(), keyword()) :: [map()]

Collects log items sent through a Bypass envelope collector.

This is a high-level helper combining collect_envelopes/3 and extract_log_items/1. Use this instead of collect_envelopes(ref, count) |> extract_log_items().

Options

  • :timeout - timeout in ms to wait for each envelope (default: 1000)

Examples

ref = setup_bypass_envelope_collector(bypass)
Logger.info("something happened")
[log] = collect_sentry_logs(ref, 1)
Link to this function

collect_sentry_metric_items(ref, expected_count, opts \\ [])

View Source (since 13.0.0)
@spec collect_sentry_metric_items(reference(), pos_integer(), keyword()) :: [map()]

Collects metric batch payloads sent through a Bypass envelope collector.

This is a high-level helper combining collect_envelopes/3 and extract_metric_items/1. Use this instead of collect_envelopes(ref, count) |> extract_metric_items().

Each returned map has an "items" key containing the individual metric maps.

Options

  • :timeout - timeout in ms to wait for each envelope (default: 1000)

Examples

ref = setup_bypass_envelope_collector(bypass, type: "trace_metric")
Sentry.Metrics.count("button.clicks", 1)
[batch] = collect_sentry_metric_items(ref, 1)
[metric] = batch["items"]
assert metric["name"] == "button.clicks"
Link to this function

collect_sentry_transactions(ref, expected_count, opts \\ [])

View Source (since 13.0.0)
@spec collect_sentry_transactions(reference(), pos_integer(), keyword()) :: [map()]

Collects transactions sent through a Bypass envelope collector.

This is a high-level helper combining collect_envelopes/3 and extract_transactions/1. Use this instead of collect_envelopes(ref, count) |> extract_transactions().

Options

  • :timeout - timeout in ms to wait for each envelope (default: 1000)

Examples

ref = setup_bypass_envelope_collector(bypass)
run_traced_job()
[tx] = collect_sentry_transactions(ref, 1)
Link to this function

decode_envelope!(binary)

View Source (since 13.0.0)
@spec decode_envelope!(binary()) :: [{header :: map(), item :: map()}]

Decodes a raw envelope binary into a list of {header, item} tuples.

Link to this function

extract_check_ins(envelope_items_list)

View Source (since 13.0.0)
@spec extract_check_ins([[{map(), map()}]]) :: [map()]

Extracts check-in payloads from decoded envelope item lists.

Link to this function

extract_events(envelope_items_list)

View Source (since 13.0.0)
@spec extract_events([[{map(), map()}]]) :: [map()]

Extracts event payloads from decoded envelope item lists.

Link to this function

extract_log_items(envelope_items_list)

View Source (since 13.0.0)
@spec extract_log_items([[{map(), map()}]]) :: [map()]

Extracts log item payloads from decoded envelope item lists.

Link to this function

extract_metric_items(envelope_items_list)

View Source (since 13.0.0)
@spec extract_metric_items([[{map(), map()}]]) :: [map()]

Extracts metric batch payloads from decoded envelope item lists.

Each returned map has an "items" key containing the individual metric maps for that batch. This mirrors the structure of extract_log_items/1.

Link to this function

extract_transactions(envelope_items_list)

View Source (since 13.0.0)
@spec extract_transactions([[{map(), map()}]]) :: [map()]

Extracts transaction payloads from decoded envelope item lists.

Link to this function

pop_sentry_logs(owner_pid \\ self())

View Source (since 11.0.0)
@spec pop_sentry_logs(pid()) :: [Sentry.LogEvent.t()]

Pops all the collected log events from the current process.

Returns a list of all Sentry.LogEvent structs that have been collected. After this function returns, the collected log events are cleared but collection continues.

Logs are Asynchronous

Log events flow through the TelemetryProcessor pipeline asynchronously. You may need to add a small delay before calling this function to ensure all log events have been processed by the before_send_log callback.

Link to this function

pop_sentry_metrics(owner_pid \\ self())

View Source (since 13.0.0)
@spec pop_sentry_metrics(pid()) :: [Sentry.Metric.t()]

Pops all the collected metrics from the current process.

Returns a list of all Sentry.Metric structs that have been collected. After this function returns, the collected metrics are cleared but collection continues.

Metrics are Asynchronous

Metric events flow through the TelemetryProcessor pipeline asynchronously. You may need to add a small delay before calling this function to ensure all metrics have been processed by the before_send_metric callback.

Link to this function

pop_sentry_reports(owner_pid \\ self())

View Source (since 10.2.0)
@spec pop_sentry_reports(pid()) :: [Sentry.Event.t()]

Pops all the collected events from the current process.

Returns a list of all Sentry.Event structs that have been collected from the current process and all child processes spawned from it. After this function returns, the collected events are cleared but collection continues.

Examples

iex> Sentry.Test.start_collecting_sentry_reports()
:ok
iex> Sentry.capture_message("Oops")
{:ok, ""}
iex> [%Sentry.Event{} = event] = Sentry.Test.pop_sentry_reports()
iex> event.message.formatted
"Oops"
Link to this function

pop_sentry_transactions(owner_pid \\ self())

View Source (since 10.2.0)
@spec pop_sentry_transactions(pid()) :: [Sentry.Transaction.t()]

Pops all the collected transactions from the current process.

Returns a list of all Sentry.Transaction structs that have been collected. After this function returns, the collected transactions are cleared but collection continues.

Examples

iex> Sentry.Test.start_collecting_sentry_reports()
:ok
iex> Sentry.send_transaction(Sentry.Transaction.new(%{span_id: "123", start_timestamp: "2024-10-12T13:21:13", timestamp: "2024-10-12T13:21:13", spans: []}))
{:ok, ""}
iex> [%Sentry.Transaction{}] = Sentry.Test.pop_sentry_transactions()
Link to this function

setup_bypass_envelope_collector(bypass, opts \\ [])

View Source (since 13.0.0)
@spec setup_bypass_envelope_collector(
  term(),
  keyword()
) :: reference()

Sets up a Bypass envelope collector that forwards envelope bodies to the test process as messages.

Uses Bypass.stub (not Bypass.expect) to be resilient to stray requests from background processes (e.g., OpenTelemetry span processor).

Use with collect_envelopes/3 to retrieve the decoded envelopes.

Options

  • :type - when set, only envelopes containing an item of this type (e.g., "event", "transaction", "log") are forwarded to the test process. Envelopes not matching the type are silently dropped.
Link to this function

setup_sentry(extra_config \\ [])

View Source (since 13.0.0)
@spec setup_sentry(keyword()) :: %{bypass: term(), telemetry_processor: atom()}

Sets up a Bypass instance and configures Sentry for testing.

Opens a Bypass on a random port, configures the DSN to point to it, wires up before_send / before_send_log callbacks to capture structs in an isolated ETS table, and starts a per-test Sentry.TelemetryProcessor (via setup_telemetry_processor/0) so that assertions work for events that travel through the TelemetryProcessor pipeline (logs, metrics, or send_result: :none).

Returns a map with :bypass and :telemetry_processor for use in test context. The :telemetry_processor value is the atom name of the per-test processor and can be used to stop_supervised!/1 and start a custom-configured one when needed.

Options

Any extra Sentry config options (e.g., dedup_events: false, traces_sample_rate: 1.0) will be forwarded to the test config.

Examples

setup do
  Sentry.Test.setup_sentry()
end

setup do
  Sentry.Test.setup_sentry(dedup_events: false)
end

Replacing the auto-started processor with a custom-configured one:

setup do
  %{telemetry_processor: name} = ctx = Sentry.Test.setup_sentry()
  stop_supervised!(name)

  start_supervised!(
    {Sentry.TelemetryProcessor,
     name: name, buffer_configs: %{log: %{batch_size: 1}}},
    id: name
  )

  ctx
end
Link to this function

setup_telemetry_processor()

View Source (since 13.0.0)
@spec setup_telemetry_processor() :: atom()

Starts an isolated, per-test Sentry.TelemetryProcessor and wires it into the current test's config scope.

This is called automatically by setup_sentry/1 and start_collecting_sentry_reports/0, so most users do not need to invoke it directly. It is exposed for tests that want to perform the setup without opening a Bypass.

The helper:

Returns the processor name (an atom).

Must be called from within an ExUnit test because it uses ExUnit.Callbacks.start_supervised!/2 for automatic cleanup.

If a per-test processor is already registered for this test (for example when using Sentry.Case), this function is idempotent and returns the existing processor name instead of starting a new one.

Link to this function

start_collecting(options \\ [])

View Source (since 10.2.0)
This function is deprecated. Use setup_sentry/1 or start_collecting_sentry_reports/0 instead.
@spec start_collecting(keyword()) :: :ok

Starts collecting events.

Deprecated

This function is deprecated and will be removed in v13.0.0. Use setup_sentry/1 or start_collecting_sentry_reports/0 instead.

The :owner, :cleanup, and :key options are no longer supported and are ignored.

Link to this function

start_collecting_sentry_reports(context \\ %{})

View Source (since 10.2.0)
@spec start_collecting_sentry_reports(map()) :: :ok

Starts collecting events from the current process.

This function configures Sentry for testing using the default Bypass instance (started at application boot). It can be used as an ExUnit setup callback:

setup :start_collecting_sentry_reports

The context parameter is ignored — it exists so this function can be used as an ExUnit setup callback.