diff --git a/docs/platforms/elixir/configuration/options.mdx b/docs/platforms/elixir/configuration/options.mdx index 50f4a58392bf18..1296f54faf8ba6 100644 --- a/docs/platforms/elixir/configuration/options.mdx +++ b/docs/platforms/elixir/configuration/options.mdx @@ -68,18 +68,24 @@ The level the SDK logs at when it fails to send data to Sentry, such as an API f These options can be used to hook the SDK in various ways to customize the reporting of events. +If a hook raises, throws, or exits, the SDK catches the failure and logs it at the `:error` level instead of letting it reach your code. Each option below describes what happens to the event in that case. See SDK Diagnostics for how these messages are logged. + -This function is called with an SDK-specific message or error event object, and can return a modified event object, or `null` to skip reporting the event. This can be used, for instance, for manual PII stripping before sending. +This function is called with an SDK-specific message or error event object, and can return a modified event object, or `nil` or `false` to skip reporting the event. This can be used, for instance, for manual PII stripping before sending. By the time is executed, all scope data has already been applied to the event. Further modification of the scope won't have any effect. +If the function crashes, the event isn't sent, as if it had returned `false`. + This function is called with an event and the result of sending that event. This is useful to log send results, instrument Sentry calls, and so on. +With the default buffered delivery, this function runs after the event is queued and doesn't wait for delivery to complete. Its return value is ignored, so a crash doesn't change the send result. + ## Transport Options @@ -151,26 +157,34 @@ config :sentry, If both `:traces_sampler` and `:traces_sample_rate` are configured, `:traces_sampler` takes precedence. - +If the function crashes, sampling falls back to `:traces_sample_rate`. If `:traces_sample_rate` isn't set either, the trace is dropped. If the function returns something other than a boolean or a float between `0.0` and `1.0`, the SDK logs a warning and drops the trace. -## Telemetry Processor Options + -The Telemetry Processor is a buffered, priority-based event delivery mechanism. It batches events and sends them to Sentry using a weighted scheduler that prioritizes critical events (like errors) over lower-priority ones (like logs). Logs are routed through the Telemetry Processor by default. You can opt in to route other event types through the processor as well. In a future major release, the Telemetry Processor will become the default delivery mechanism for all event types. + - +HTTP response statuses to keep out of tracing. An incoming request answered with one of these statuses isn't reported as a transaction. Accepts status codes and ranges. Outgoing requests aren't affected. -A list of event categories to route through the Telemetry Processor. By default, only `:log` events use the processor. You can opt in to route additional event types through it. +The default is `[404]`, so _404 Not Found_ requests aren't traced. Set it to `[]` to trace them again: -Valid categories: +```elixir +config :sentry, + traces_ignore_http_status_codes: [] +``` -- `:error` — error events (critical priority) -- `:check_in` — cron check-in events (high priority) -- `:transaction` — transaction events (medium priority) -- `:log` — log events (low priority) +To ignore more statuses, list them as codes or ranges: ```elixir config :sentry, - telemetry_processor_categories: [:error, :check_in, :transaction, :log] + traces_ignore_http_status_codes: [404, 500..599] ``` +The SDK drops the transaction only once the response status is known, after the request has been handled. For sampled requests, the trace has already been propagated as sampled. Downstream services can still report spans, which appear in Sentry without their root transaction. + + +## Telemetry Processor Options + +The Telemetry Processor batches events and sends them to Sentry, prioritizing errors over lower-priority events such as logs. It buffers logs and metrics, as well as errors, check-ins, and transactions by default. + +When your application shuts down gracefully, the SDK flushes buffered telemetry before it stops, waiting up to five seconds. To flush earlier or with a different timeout, call `Sentry.flush/1`. diff --git a/docs/platforms/elixir/data-management/data-collected.mdx b/docs/platforms/elixir/data-management/data-collected.mdx index 4bfc948e5e511a..5bb1b27f31bad8 100644 --- a/docs/platforms/elixir/data-management/data-collected.mdx +++ b/docs/platforms/elixir/data-management/data-collected.mdx @@ -8,85 +8,115 @@ Sentry takes data privacy very seriously and has default settings in place that The category types and amount of data collected vary, depending on the integrations you've enabled in the Sentry SDK. Here's a list of data categories the Sentry Elixir SDK collects: -## HTTP Headers +## Request Data Scrubbing + +When using the Plug or Phoenix integrations, `Sentry.PlugContext` adds request data to error reports and scrubs it first. Starting with SDK version 14.0.0, scrubbed values are replaced with `"[Filtered]"`. Earlier versions use `"*********"`. + +A parameter is considered sensitive when its name contains one of the following terms, compared case-insensitively. For example, `auth` matches both `Authorization` and `user_auth_code`: + +`auth`, `token`, `secret`, `password`, `passwd`, `pwd`, `key`, `jwt`, `bearer`, `sso`, `saml`, `csrf`, `xsrf`, `credentials`, `session`, `sid`, `identity` -When using the Plug or Phoenix integrations, HTTP headers from requests are included in error reports with built-in filtering for security: +Values that look like credit card numbers (13 to 16 digits, optionally separated by spaces or dashes) are also replaced with `"[Filtered]"`, regardless of their parameter name. + +The `:header_scrubber`, `:cookie_scrubber`, `:remote_address_reader`, `:url_scrubber`, and `:body_scrubber` options below are passed to `Sentry.PlugContext` in your endpoint or router, not set with `config :sentry`. If one of these callbacks raises an exception, the SDK logs the failure at the `:error` level and uses its default for that field instead. This means that data only your custom scrubber was removing is sent to Sentry for as long as the scrubber keeps failing. + +## HTTP Headers **Default Behavior:** -- Most request headers are included by default -- Sensitive headers are automatically scrubbed, including: - - `authorization` - - `authentication` - - `cookie` +- Request headers are included +- The `authorization`, `authentication`, and `cookie` headers are removed +- The `referer` header is kept, but sensitive query parameters in its URL are replaced with `"[Filtered]"` **Configuration:** ```elixir -# Custom header filtering -config :sentry, - header_scrubber: &MyApp.CustomHeaderScrubber.scrub/1 +plug Sentry.PlugContext, header_scrubber: &MyApp.SentryScrubber.scrub_headers/1 ``` ## Cookies **Default Behavior:** -- **All cookies are scrubbed by default** for privacy protection -- No cookie data is sent to Sentry unless explicitly configured + +- **All cookies are removed by default** for privacy protection +- No cookie data is sent to Sentry unless you configure a custom cookie scrubber **Configuration:** ```elixir -# Enable cookie collection with custom scrubbing -config :sentry, - cookie_scrubber: &MyApp.CustomCookieScrubber.scrub/1 +plug Sentry.PlugContext, cookie_scrubber: &MyApp.SentryScrubber.scrub_cookies/1 ``` ## Users' IP Address **Default Behavior:** + - Client IP addresses are collected from HTTP requests -- Prioritizes `x-forwarded-for` header, falls back to `conn.remote_ip` +- The SDK reads the `x-forwarded-for` header first and falls back to `conn.remote_ip` **Configuration:** ```elixir -# Custom IP address extraction -config :sentry, - remote_address_reader: {MyModule, :get_ip_address} +plug Sentry.PlugContext, remote_address_reader: {MyApp.RemoteIp, :read} ``` ## Request URL **Default Behavior:** -- Full request URLs are always sent, including query strings -- URLs may contain PII depending on your application's routing structure + +- The full request URL is sent, including the query string +- Values of sensitive query parameters are replaced with `"[Filtered]"`, for example, `/search?token=abc123&page=2` is sent as `/search?token=[Filtered]&page=2` +- All other query parameters are sent exactly as the client sent them +- The URL path isn't scrubbed, so a secret in a path segment, such as `/reset/`, is sent unless you add a custom URL scrubber **Configuration:** ```elixir -# Custom URL scrubbing -config :sentry, - url_scrubber: &MyApp.UrlScrubber.scrub/1 +# Use a custom URL scrubber +plug Sentry.PlugContext, url_scrubber: &MyApp.SentryScrubber.scrub_url/1 + +# Or turn off URL scrubbing entirely +plug Sentry.PlugContext, url_scrubber: nil ``` -## Request Body +## Request Parameters **Default Behavior:** -- Request body parameters are included with automatic scrubbing -- Sensitive parameters are filtered by default: - - `password` - - `passwd` - - `secret` - - Credit card numbers (detected via regex pattern) + +- Request body and query parameters are included, and so are path parameters when `Sentry.PlugContext` runs after routing, such as in your router +- Values of sensitive parameters are replaced with `"[Filtered]"`, including in nested maps and lists **Configuration:** + +```elixir +# Use a custom body scrubber +plug Sentry.PlugContext, body_scrubber: &MyApp.SentryScrubber.scrub_params/1 + +# Or don't send any request parameters +plug Sentry.PlugContext, body_scrubber: nil +``` + +## Adding Sensitive Parameter Names + + + +To redact more parameters, add terms to the `:param_keys` list of the `:scrubber` option: + ```elixir -# Custom body parameter filtering config :sentry, - body_scrubber: &MyApp.BodyScrubber.scrub/1 + scrubber: [param_keys: ["internal_ref"]] ``` +The terms extend the default list and can't remove terms from it. They're matched the same way as the default terms, as case-insensitive substrings, so `"internal_ref"` also redacts `"INTERNAL_REF_ID"`. The additional terms apply everywhere the SDK scrubs parameters: + +- Request parameters and the query string of the request URL +- The query string of the `referer` header URL +- `Sentry.LiveViewHook` breadcrumb data +- Oban job arguments +- Function arguments captured in stack traces + +They don't change which headers are removed. + ## Source Context **Default Behavior:** @@ -107,8 +137,10 @@ config :sentry, ## Local Variables In Stack Trace **Default Behavior:** + - Local variables are not included in stack traces - Stack traces contain function names, function variables, modules, file paths, and line numbers only +- Values of sensitive keys in captured function arguments are replaced with `"[Filtered]"` **Note:** Unlike some other SDKs, the Elixir SDK does not currently support capturing local variables due to the nature of the Erlang VM. @@ -138,7 +170,9 @@ config :logger, :sentry, ``` + There's always risk that PII will leak into Sentry via Logger integration. It is recommended to review your log metadata and scrub any sensitive information before logging. + ## Application Dependencies @@ -161,11 +195,13 @@ config :sentry, When using the Oban integration for background jobs: **Job Information:** + - Job arguments, attempt count, queue name - Worker class name - Job metadata and tags - Max attempts and current state +Values of sensitive keys in job arguments are replaced with `"[Filtered]"`. ## More information diff --git a/docs/platforms/elixir/migration.mdx b/docs/platforms/elixir/migration.mdx index 62270f495cb341..66fb5ce70ea204 100644 --- a/docs/platforms/elixir/migration.mdx +++ b/docs/platforms/elixir/migration.mdx @@ -10,3 +10,4 @@ The migration guides for older versions of the Elixir SDK are available over on - [Upgrade to Sentry 8.x](https://hexdocs.pm/sentry/upgrade-8-x.html) - [Upgrade to Sentry 9.x](https://hexdocs.pm/sentry/upgrade-9-x.html) - [Upgrade to Sentry 10.x](https://hexdocs.pm/sentry/upgrade-10-x.html) +- [Upgrade to Sentry 14.x](https://hexdocs.pm/sentry/upgrade-14-x.html) diff --git a/docs/platforms/elixir/testing/index.mdx b/docs/platforms/elixir/testing/index.mdx index 8536bab5f4ed06..864c167a770790 100644 --- a/docs/platforms/elixir/testing/index.mdx +++ b/docs/platforms/elixir/testing/index.mdx @@ -21,13 +21,19 @@ Add `bypass` as a test dependency in `mix.exs`: ```elixir {filename:mix.exs} defp deps do [ - {:sentry, "~> 13.0"}, + {:sentry, "~> 14.0"}, {:bypass, "~> 2.0", only: [:test]}, # ... ] end ``` +Turn on test mode in your test configuration. It starts the registry the test helpers depend on and isolates Sentry configuration per test: + +```elixir {filename:config/test.exs} +config :sentry, test_mode: true +``` + Call `Sentry.Test.setup_sentry/1` in your ExUnit `setup` block. It opens a local HTTP server scoped to the current test, points Sentry's DSN at it, and wires up event collection: ```elixir @@ -50,6 +56,12 @@ setup do end ``` +`setup_sentry/1` returns a map that ExUnit merges into the test context. It contains: + +- `:bypass` — the local HTTP server that receives this test's envelopes +- `:telemetry_processor` — the name of this test's telemetry processor +- `:client_report_sender` — the name of this test's client report sender, so counts of discarded events don't leak between tests (SDK 14.0.0 and later) + ## Errors Use `assert_sentry_report(:event, criteria)` to assert on captured errors and messages. It fails if any criterion doesn't match or if not exactly one event was captured. @@ -272,7 +284,9 @@ end ## Check-ins -Cron check-ins are delivered directly over the network, not through the ETS collector. Use `setup_bypass_envelope_collector/2` to intercept them, then assert with `assert_sentry_report/2`. Given an Oban worker that wraps its job in a check-in: +Cron check-ins aren't stored in the per-test collector that the other helpers read from. The SDK sends them to the test's local HTTP server, the same way it sends them to Sentry. + +Use `setup_bypass_envelope_collector/2` to intercept them, then assert with `assert_sentry_report/2`. Given an Oban worker that wraps its job in a check-in: ```elixir {filename:lib/my_app/workers/nightly_report_worker.ex} defmodule MyApp.Workers.NightlyReportWorker do @@ -320,7 +334,76 @@ defmodule MyApp.Workers.NightlyReportWorkerTest do end ``` -The `%{bypass: bypass}` map is returned by `setup_sentry/1` and merged into the test context automatically. +### Collecting Several Envelope Types + + + +The `:type` option also accepts a list. Use it when one action sends several kinds of envelopes that you want to assert on together. Given a job that reports its own failures: + +```elixir {filename:lib/my_app/reports.ex} +def generate_nightly(date) do + {:ok, check_in_id} = + Sentry.capture_check_in(status: :in_progress, monitor_slug: "nightly-report") + + try do + build_report!(date) + Sentry.capture_check_in(status: :ok, monitor_slug: "nightly-report", check_in_id: check_in_id) + rescue + exception -> + Sentry.capture_exception(exception, stacktrace: __STACKTRACE__) + Sentry.capture_check_in(status: :error, monitor_slug: "nightly-report", check_in_id: check_in_id) + end +end +``` + +The test collects the error and both check-ins, then splits them by type with `extract_events/1` and `extract_check_ins/1`: + +```elixir {filename:test/my_app/reports_test.exs} +test "reports the exception and an error check-in", %{bypass: bypass} do + ref = Sentry.Test.setup_bypass_envelope_collector(bypass, type: ["event", "check_in"]) + + Reports.generate_nightly(:invalid_date) + + envelopes = Sentry.Test.collect_envelopes(ref, 3) + + [event] = Sentry.Test.extract_events(envelopes) + assert_sentry_report(event, level: "error") + + [_started, finished] = Sentry.Test.extract_check_ins(envelopes) + assert_sentry_report(finished, status: "error", monitor_slug: "nightly-report") +end +``` + +## Failed Deliveries + + + +By default, the collector answers every envelope with a successful response. Pass a `:response` function to `setup_bypass_envelope_collector/2` to simulate a failed response from Sentry instead. + +The function receives the `Plug.Conn` and the raw envelope body, and must return the response connection. The collector still records the envelope before the function runs. + +This test simulates Sentry rejecting the envelope and checks that a synchronous capture returns an error: + +```elixir {filename:test/my_app/error_reporting_test.exs} +test "returns an error when Sentry rejects the event", %{bypass: bypass} do + ref = + Sentry.Test.setup_bypass_envelope_collector(bypass, + response: fn conn, _body -> Plug.Conn.resp(conn, 413, "") end + ) + + assert {:error, %Sentry.ClientError{reason: :envelope_too_large}} = + Sentry.capture_message("Payment failed", result: :sync) + + [event] = Sentry.Test.collect_sentry_events(ref, 1) + assert_sentry_report(event, message: %{formatted: "Payment failed"}) +end +``` + + + +**Don't simulate a `429` response.** The SDK treats it as a rate limit that applies to the whole test run, not only the current test. It stops sending data for 60 seconds, or for the `Retry-After` duration, so later tests stop receiving envelopes. The SDK retries most other error statuses, such as `503`, and waits between attempts, which makes each of those tests take about 15 seconds. + + ## Structured Assertions diff --git a/docs/platforms/elixir/tracing/index.mdx b/docs/platforms/elixir/tracing/index.mdx index 5d98602d037b2a..ea7be859c29304 100644 --- a/docs/platforms/elixir/tracing/index.mdx +++ b/docs/platforms/elixir/tracing/index.mdx @@ -22,7 +22,7 @@ Sentry's Elixir SDK uses OpenTelemetry for tracing. Add the required dependencie def deps do [ # Sentry SDK - {:sentry, "~> 12.0"}, + {:sentry, "~> 14.0"}, # OpenTelemetry core packages {:opentelemetry, "~> 1.7"}, @@ -51,6 +51,8 @@ config :sentry, traces_sample_rate: 1.0 # Adjust for production ``` +Incoming requests answered with _404 Not Found_ aren't reported as transactions. To trace them, or to ignore other statuses, set `traces_ignore_http_status_codes`. + ## Configure OpenTelemetry Set up OpenTelemetry to send traces to Sentry: @@ -74,7 +76,6 @@ config :opentelemetry, In your `application.ex`, set up the OpenTelemetry instrumentation. - `OpentelemetryPhoenix` requires your Phoenix endpoint to include `Plug.Telemetry` in order to correctly trace endpoint calls. Make sure your endpoint contains: @@ -157,7 +158,6 @@ To set up both features together, enable logs and tracing in your Sentry configu config :sentry, dsn: "___PUBLIC_DSN___", traces_sample_rate: 1.0, - enable_logs: true, logs: [level: :info, metadata: :all] config :opentelemetry, @@ -170,7 +170,7 @@ Then add `opentelemetry_logger_metadata` to your dependencies: ```elixir {filename:mix.exs} defp deps do [ - {:sentry, "~> 12.0"}, + {:sentry, "~> 14.0"}, {:opentelemetry, "~> 1.7"}, {:opentelemetry_api, "~> 1.5"}, {:opentelemetry_exporter, "~> 1.10"}, diff --git a/platform-includes/configuration/before-send-log/elixir.mdx b/platform-includes/configuration/before-send-log/elixir.mdx index 166371228470a1..9143f9a342d289 100644 --- a/platform-includes/configuration/before-send-log/elixir.mdx +++ b/platform-includes/configuration/before-send-log/elixir.mdx @@ -1,7 +1,7 @@ ```elixir config :sentry, dsn: "___PUBLIC_DSN___", - enable_logs: true, + logs: [level: :info], before_send_log: fn log_event -> # Skip info logs if log_event.level == :info do @@ -17,13 +17,13 @@ You can also use a module/function tuple: ```elixir config :sentry, dsn: "___PUBLIC_DSN___", - enable_logs: true, + logs: [level: :info], before_send_log: {MyApp.Sentry, :before_send_log} # In lib/my_app/sentry.ex defmodule MyApp.Sentry do def before_send_log(%Sentry.LogEvent{} = log_event) do - # Filter out logs from specific domains or modify attributes + # Skip logs whose message mentions sensitive data if String.contains?(log_event.body, "sensitive") do false else diff --git a/platform-includes/logs/integrations/elixir.mdx b/platform-includes/logs/integrations/elixir.mdx index 8c39706ee21d26..1ca532579b7305 100644 --- a/platform-includes/logs/integrations/elixir.mdx +++ b/platform-includes/logs/integrations/elixir.mdx @@ -1,10 +1,9 @@ -Logs are sent to Sentry through Erlang's `:logger` system via `Sentry.LoggerHandler`. When `enable_logs: true` is set in your Sentry configuration, the SDK automatically attaches the handler — no manual setup is needed. Any logs from your application or libraries that use Elixir's `Logger` or Erlang's `:logger` will be captured and sent to Sentry at or above the configured level. +Logs are sent to Sentry through Erlang's `:logger` system via `Sentry.LoggerHandler`. When `:logs` is set in your Sentry configuration, the SDK automatically attaches the handler — no manual setup is needed. Any logs from your application or libraries that use Elixir's `Logger` or Erlang's `:logger` will be captured and sent to Sentry at or above the configured level. The logs behavior is configured globally via the `:logs` key — not through the handler config map: ```elixir config :sentry, - enable_logs: true, logs: [ level: :info, metadata: [:request_id, :user_id] @@ -28,7 +27,6 @@ You can exclude specific logger domains from being sent to Sentry using the `:ex ```elixir config :sentry, - enable_logs: true, logs: [ level: :info, excluded_domains: [:ecto, :phoenix] @@ -36,8 +34,7 @@ config :sentry, ``` - The logs feature (configured under `:logs`) is separate from error - reporting (configured via `Sentry.LoggerHandler`'s `:level` option). Error reporting captures crash reports and - exceptions, while logs captures structured log events. You can configure both - independently. + +The same handler sends logs and reports errors, and each has its own options under `:logs`. The `:level`, `:excluded_domains`, and `:metadata` options control logs. The `:capture_log_messages`, `:capture_level`, `:capture_metadata`, and `:capture_excluded_domains` options control which crashes and `Logger` messages are reported as errors. You can configure both independently. + diff --git a/platform-includes/logs/options/elixir.mdx b/platform-includes/logs/options/elixir.mdx index 5dfc4ad117be5e..7853bcb26868f3 100644 --- a/platform-includes/logs/options/elixir.mdx +++ b/platform-includes/logs/options/elixir.mdx @@ -1,27 +1,42 @@ ### before_send_log -To filter or modify logs before they are sent to Sentry, use the `before_send_log` callback. Return `false` to skip a log, or return the log event to send it. +To filter or modify logs before they are sent to Sentry, use the `before_send_log` callback. It receives a `Sentry.LogEvent` struct. Return `nil` or `false` to skip a log, or return the log event to send it. +If the callback raises an exception or crashes, the SDK logs the failure at the `:error` level and doesn't send that log. Other logs in the same batch are still sent. + ### Logs Configuration -Logs behavior is configured under the `:logs` key in your Sentry configuration. These options control the auto-attached `Sentry.LoggerHandler`: +Logs behavior is configured under the `:logs` key in your Sentry configuration. Setting `:logs` attaches `Sentry.LoggerHandler` automatically, and these options control it. + +The following options configure logs: -- **`:level`** - The minimum log level to send to Sentry's Logs Protocol. Default: `:info`. Supported values: `:debug`, `:info`, `:notice`, `:warning`, `:error`, `:critical`, `:alert`, `:emergency`. +- **`:level`** - The minimum log level to send to Sentry as logs. Setting it turns on logs. Default: `nil`, which sends no logs. Supported values: `:debug`, `:info`, `:notice`, `:warning`, `:error`, `:critical`, `:alert`, `:emergency`. - **`:excluded_domains`** - A list of logger domains to exclude from logs sent to Sentry. Default: `[]`. - **`:metadata`** - Logger metadata keys to include as attributes in log events. Set to `:all` to include all metadata, or a list of specific keys like `[:request_id, :user_id]`. Default: `[]`. +The following options configure how the same handler reports errors. They're independent of the logs options above: + +- **`:capture_log_messages`** - Set to `true` to also report `Logger` messages at or above `:capture_level` to Sentry as errors. Crashes are reported whether or not this is set. Default: `false`. + +- **`:capture_level`** - The minimum log level for messages and crashes reported as errors. Default: `:error`. + +- **`:capture_metadata`** - Logger metadata keys to include in reported errors. Set to `:all` to include all metadata. Default: `[]`. + +- **`:capture_excluded_domains`** - A list of logger domains to exclude from reported errors. Default: `[:cowboy]`, which avoids reporting errors that `Sentry.PlugCapture` already captures. + ```elixir config :sentry, dsn: "___PUBLIC_DSN___", - enable_logs: true, logs: [ level: :info, excluded_domains: [:ecto], - metadata: [:request_id, :user_id] # or :all + metadata: [:request_id, :user_id], # or :all + capture_log_messages: true, + capture_level: :error ] ``` @@ -29,15 +44,15 @@ config :sentry, These options are set in your Sentry configuration (`config :sentry`): -- **`:enable_logs`** - Set to `true` to enable the logs feature. When enabled, the SDK automatically attaches a `Sentry.LoggerHandler` and routes log events through the SDK's Telemetry Processor. Default is `false`. +- **`:logs`** - The logs configuration described above. Default: `nil`, which doesn't attach the handler. - **`:before_send_log`** - A callback function to filter or modify log events before they are sent. -Log events are buffered by the Telemetry Processor with a capacity of 1000 entries and flushed in batches of 100 or every 5 seconds, whichever comes first. You can customize these defaults through the Telemetry Processor options. +Log events are buffered by the Telemetry Processor with a capacity of 1000 entries and flushed in batches of 100 or every 5 seconds, whichever comes first. See the Telemetry Processor options for how buffered telemetry is sent and flushed on shutdown. ```elixir config :sentry, dsn: "___PUBLIC_DSN___", - enable_logs: true, + logs: [level: :info], before_send_log: {MyApp.Sentry, :before_send_log} ``` diff --git a/platform-includes/logs/requirements/elixir.mdx b/platform-includes/logs/requirements/elixir.mdx index 03888151c0bc21..5de74278a8aa3d 100644 --- a/platform-includes/logs/requirements/elixir.mdx +++ b/platform-includes/logs/requirements/elixir.mdx @@ -1,15 +1,11 @@ -Logs for Elixir are supported in Sentry Elixir SDK version `12.0.0` and above. +Logs for Elixir are supported in Sentry Elixir SDK version `12.0.0` and above. The configuration on this page requires version `14.0.0` or later. -```bash -mix deps.get sentry -``` - -Or add it to your `mix.exs`: +Add `sentry` to your `mix.exs` dependencies: ```elixir defp deps do [ - {:sentry, "~> 12.0"} + {:sentry, "~> 14.0"} ] end ``` diff --git a/platform-includes/logs/setup/elixir.mdx b/platform-includes/logs/setup/elixir.mdx index c28f771cf8f633..0db9d0811fdd87 100644 --- a/platform-includes/logs/setup/elixir.mdx +++ b/platform-includes/logs/setup/elixir.mdx @@ -1,33 +1,38 @@ -To enable logging, set `enable_logs: true` in your Sentry configuration: +To enable logs, set a `:level` under the `:logs` key in your Sentry configuration: ```elixir # In config/config.exs or config/runtime.exs config :sentry, dsn: "___PUBLIC_DSN___", - enable_logs: true + logs: [ + level: :info + ] ``` -When `enable_logs` is `true`, the SDK **automatically attaches** a `Sentry.LoggerHandler` (registered as `:sentry_log_handler`) on application startup. No manual handler setup is required. +When `:logs` is set, the SDK **automatically attaches** a `Sentry.LoggerHandler` (registered as `:sentry_log_handler`) on application startup. No manual handler setup is required. The `:level` option sets the minimum level of log messages sent to Sentry as logs. -If you already have a `Sentry.LoggerHandler` registered (for example, for crash and error reporting), the SDK will not add a second one — your existing handler will also capture logs. + +The `:level` option is what turns on logs. A `:logs` block without `:level` still attaches the handler, so crashes are reported to Sentry as errors, but no logs are sent. + -To configure the minimum log level and other options, use the `:logs` key: +To configure other options, add them under the same `:logs` key: ```elixir config :sentry, dsn: "___PUBLIC_DSN___", - enable_logs: true, logs: [ - level: :info, # minimum log level (default: :info) + level: :info, # minimum log level (default: nil, no logs sent) excluded_domains: [], # logger domains to exclude (default: []) metadata: [] # metadata keys to include as attributes (default: []) ] ``` +If you register a `Sentry.LoggerHandler` yourself, the SDK removes the auto-attached one so messages aren't captured twice. Your handler sends logs when `:logs` has a `:level`, or when you pass `:logs_level` in the handler's config. + -Log events are automatically batched and delivered through the SDK's Telemetry Processor, which buffers log entries and sends them to Sentry efficiently. See the Telemetry Processor options for configuration details. +Log events are automatically batched and delivered through the SDK's Telemetry Processor, which buffers log entries and sends them to Sentry efficiently. See the Telemetry Processor options for how buffered telemetry is sent and flushed on shutdown. diff --git a/platform-includes/logs/usage/elixir.mdx b/platform-includes/logs/usage/elixir.mdx index 4d0ae8b25e4e81..574684dbc476c1 100644 --- a/platform-includes/logs/usage/elixir.mdx +++ b/platform-includes/logs/usage/elixir.mdx @@ -1,6 +1,6 @@ -Once `enable_logs: true` is set in your Sentry configuration, you can send logs using Elixir's standard `Logger` module. +Once `:level` is set under `:logs` in your Sentry configuration, you can send logs using Elixir's standard `Logger` module. -The logs will be sent to Sentry at or above the level configured by the `:level` option under `:logs` (default: `:info`). The supported log levels in Elixir are: `debug`, `info`, `notice`, `warning`, `error`, `critical`, `alert`, and `emergency`. +The logs will be sent to Sentry at or above the level configured by the `:level` option under `:logs`. The supported log levels in Elixir are: `debug`, `info`, `notice`, `warning`, `error`, `critical`, `alert`, and `emergency`. ```elixir require Logger @@ -16,17 +16,17 @@ Logger.error("Failed to process payment", order_id: "or_2342", amount: 99.99) ### Message Templates with Parameters -You can use message templates with positional or named parameters. To use message templates, pass parameters via the `:sentry` metadata key with `:log_parameters`: +You can use message templates with positional or named parameters. To use message templates, pass the values in the `:parameters` metadata key. Use a map for named `%{key}` placeholders or a list for positional `%s` placeholders: ```elixir -# Using named parameters (Elixir format) +# Using named parameters Logger.info("User %{name} logged in", - sentry: [log_parameters: %{name: "Jane Doe"}] + parameters: %{name: "Jane Doe"} ) # Using positional parameters Logger.info("User %s logged in", - sentry: [log_parameters: ["Jane Doe"]] + parameters: ["Jane Doe"] ) ``` @@ -36,7 +36,6 @@ Any metadata passed to `Logger` calls will be included as log attributes if conf ```elixir config :sentry, - enable_logs: true, logs: [ level: :info, metadata: :all # or [:user_id, :request_id] for specific keys diff --git a/platform-includes/metrics/default-attributes/elixir.mdx b/platform-includes/metrics/default-attributes/elixir.mdx index d754c05e2222d8..644425939e9a7d 100644 --- a/platform-includes/metrics/default-attributes/elixir.mdx +++ b/platform-includes/metrics/default-attributes/elixir.mdx @@ -2,4 +2,6 @@ The Elixir SDK automatically sets several default attributes on all metrics to p - +### Server Attributes + +- `server.address`: The value of the `server_name` option. Unlike errors, metrics don't fall back to the host name, so this attribute is only sent when you set `server_name`. diff --git a/platform-includes/metrics/options/elixir.mdx b/platform-includes/metrics/options/elixir.mdx index c6a3d70a73fc0f..84aa2c3cef937d 100644 --- a/platform-includes/metrics/options/elixir.mdx +++ b/platform-includes/metrics/options/elixir.mdx @@ -1,11 +1,3 @@ -#### enable_metrics - -You can disable metrics collection globally by setting `enable_metrics` to `false`. When disabled, calls to `Sentry.Metrics` functions will be no-ops. Metrics are enabled by default. - -```elixir -config :sentry, enable_metrics: false -``` - #### before_send_metric To filter metrics, or update them before they are sent to Sentry, you can use the `before_send_metric` option. If the callback returns `nil`, the metric is not emitted. Attributes can also be updated in the callback function. @@ -37,6 +29,8 @@ config :sentry, The `before_send_metric` callback receives a `Sentry.Metric` struct, and should return a `Sentry.Metric` struct if you want it to be sent to Sentry, or `nil` if you want to discard it. +If the callback raises an exception, throws, or exits, the SDK logs the failure at the `:error` level and drops that metric. Other metrics in the same batch are still processed. + The `Sentry.Metric` struct has the following fields: - `name`: (`String.t()`) The name of the metric. @@ -47,3 +41,10 @@ The `Sentry.Metric` struct has the following fields: - `timestamp`: (`float()`) Timestamp in seconds indicating when the metric was recorded. - `trace_id`: (`String.t() | nil`) The trace ID of the trace this metric belongs to. - `span_id`: (`String.t() | nil`) The span ID of the span that was active when the metric was emitted. + +Metrics are always on, so `before_send_metric` is also how you stop sending them. Return `nil` for every metric to drop all of them: + +```elixir +config :sentry, + before_send_metric: fn _metric -> nil end +``` diff --git a/platform-includes/metrics/requirements/elixir.mdx b/platform-includes/metrics/requirements/elixir.mdx index 32ad26b2c02534..cfa938ac670f70 100644 --- a/platform-includes/metrics/requirements/elixir.mdx +++ b/platform-includes/metrics/requirements/elixir.mdx @@ -5,7 +5,7 @@ Add `sentry` to your `mix.exs` dependencies: ```elixir defp deps do [ - {:sentry, "~> 13.0"} + {:sentry, "~> 14.0"} ] end ``` diff --git a/platform-includes/metrics/usage/elixir.mdx b/platform-includes/metrics/usage/elixir.mdx index 7605d0cf821913..d10448011727b0 100644 --- a/platform-includes/metrics/usage/elixir.mdx +++ b/platform-includes/metrics/usage/elixir.mdx @@ -1,4 +1,4 @@ -Metrics are enabled by default. Once you initialize the SDK, you can send metrics using the `Sentry.Metrics` module. +Metrics are always on. Once you initialize the SDK, you can send metrics using the `Sentry.Metrics` module. The module exposes three functions that you can use to capture different types of metric information: `count`, `gauge`, and `distribution`.