Sentry Elixir 8.0 is a major release containing significant changes, particularly around Elixir's major improvements to the core Logger module. Because of that, the required Elixir version will be Elixir 1.10. There are also a handful of steps to complete the upgrade below. A special thank you goes to José Valim for his help and contributions to this release.
A more detailed explanation of the changes is below, with instructions to upgrade, but the summary of changes is:
-
Enhancements
- Cache environment config in application config (#393)
- Allow configuring LoggerBackend to send all messages, not just exceptions (e.g.
Logger.error("I am an error message")
)
-
Bug Fixes
- Fix request URL port in payloads for HTTPS requests (#391)
-
Breaking Changes
- Change default
included_environments
to only include:prod
by default (#370) - Change default event send type to :none instead of :async (#341)
- Make hackney an optional dependency, and simplify Sentry.HTTPClient behaviour (#400)
- Use Logger.metadata for Sentry.Context, no longer return metadata values on set_* functions, and rename
set_http_context
toset_request_context
(#401) - Move excluded exceptions from Sentry.Plug to Sentry.DefaultEventFilter (#402)
- Remove Sentry.Plug and Sentry.Phoenix.Endpoint in favor of Sentry.PlugContext and Sentry.PlugCapture (#402)
- Remove feedback form rendering and configuration (#402)
- Logger metadata is now specified by key in LoggerBackend instead of enabled/disabled (#403)
- Require Elixir 1.10 and optionally plug_cowboy 2.3 (#403)
Sentry.capture_exception/1
now only accepts exceptions (#403)
- Change default
Update your :sentry
dependency, and add :hackney
. If you are using :plug_cowboy
, update it to be 2.3 or greater.
defp deps do
[
{:sentry, "~> 8.0"},
{:hackney, "~> 1.8"},
{:plug_cowboy, "~> 2.3"},
{:jason, "~> 1.1"},
# ...
]
end
Sentry.Plug
and Sentry.Phoenix.Endpoint
have been combined (and split) into Sentry.PlugCapture
and Sentry.PlugContext
. PlugContext
retrieves information from the request, and sets request context using Sentry.Context
. PlugCapture
is responsible for catching exceptions in the Plug stack and sending it to Sentry with the context that was previously set by PlugContext
.
To upgrade, remove Sentry.Plug
and Sentry.Phoenix.Endpoint
. Plug.ErrorHandler
should also be removed if Sentry was the only user of it. Add plug Sentry.PlugContext
and use Sentry.PlugCapture
. It is important to place Sentry.PlugContext
after Plug.Parsers
and put Sentry.PlugCapture
before use Phoenix.Endpoint
in a Phoenix application.
If you are using any of the :body_scrubber, :header_scrubber, :cookie_scrubber, :request_id_header
options from Sentry.Plug
, they should be passed as options to Sentry.PlugContext
.
Phoenix:
defmodule MyAppWeb.Endpoint do
+ use Sentry.PlugCapture
use Phoenix.Endpoint, otp_app: :my_app
- use Sentry.Phoenix.Endpoint
# ...
plug Plug.Parsers,
parsers: [:urlencoded, :multipart, :json],
pass: ["*/*"],
json_decoder: Phoenix.json_library()
+ plug Sentry.PlugContext
defmodule MyAppWeb.Router do
use SmartfinWeb, :router
- use Plug.ErrorHandler
- use Sentry.Plug
# ...
Plug:
defmodule MyApp.Router do
use Plug.Router
- use Plug.ErrorHandler
- use Sentry.Plug
+ use Sentry.PlugCapture
# ...
plug Plug.Parsers,
parsers: [:urlencoded, :multipart]
+ plug Sentry.PlugContext
Support for Sentry user feedback was recently added to Sentry.Plug
in version 7.2.3, but the rendering could be a bit difficult and brittle, and so was removed. To use it in 8.0.0, your error view renderer can check whether Sentry.PlugCapture
has sent an error, and conditionally render the feedback form. In a Phoenix application, this would be in the ErrorView
:
defmodule MyAppWeb.ErrorView do
# ...
def render("500.html", _assigns) do
case Sentry.get_last_event_id_and_source() do
# Check if an event was sent from Sentry.PlugCapture
{event_id, :plug} when is_binary(event_id) ->
opts =
# can do %{eventId: event_id, title: "My custom title"}
%{eventId: event_id}
|> Jason.encode!()
~E"""
<script src="https://browser.sentry-cdn.com/5.9.1/bundle.min.js" integrity_no="sha384-/x1aHz0nKRd6zVUazsV6CbQvjJvr6zQL2CHbQZf3yoLkezyEtZUpqUNnOLW9Nt3v" crossorigin="anonymous"></script>
<script>
Sentry.init({ dsn: '<%= Sentry.Config.dsn() %>' });
Sentry.showReportDialog(<%= raw opts %>)
</script>
"""
_ ->
"Error"
end
# ...
end
Exceptions from Plug and Phoenix caused by unmatched routes were previously filtered within Sentry.Plug
, and this behavior could not be configured. To enable configuration this functionality was moved to the default event filter Sentry.DefaultEventFilter
. If you are using a custom event filter module and would like to continue ignoring these exceptions, adding the following lines to your module will maintain the current behavior:
defmodule MyApp.SentryEventFilter do
@behaviour Sentry.EventFilter
# ...
# Ignore Phoenix route not found exception
def exclude_exception?(%x{}, :plug) when x in [Phoenix.Router.NoRouteError] do
true
end
# Ignore Plug route not found exception
def exclude_exception?(%FunctionClauseError{function: :do_match, arity: 4}, :plug), do: true
# ...
end
In version 7.x, Sentry.LoggerBackend
supported including any Logger metadata that held a value of number, string or atom by setting :include_logger_metadata
to true
. In 8.0, that option was removed in favor of the :metadata
key. Keys listed will be included as context within any Sentry events reported. This should be more flexible by removing the limitation on types by allowing users to specify protocols for JSON encoding, and allowing more granular specification of the keys/values added.
The :level
option was previously accepted, but had no effect on the behavior of the module. Now, that option is used as the minimum level to potentially send an event.
Two other options were added in 8.0. :capture_log_messages
offers the ability to send non-exception messages to Sentry. If you would like to receive events in Sentry when Logger.error("oops an error")
is called, this option can be set to true. Metadata set with Sentry.Context
will be included in the events reported. The :level
option can be used in combination with this one to receive warning logs as well.
Using Logger metadata also means context can be set directly in a Logger call, though care should be taken as Logger metadata does not get merged and will overwrite current data.
:excluded_domains
is an option used to ignore Logger messages from certain domains, a metadata feature added to Logger in Elixir 1.10 (docs). plug_cowboy
2.3.0 added the :cowboy
domain to Logger messages coming from Cowboy, which allows the Logger backend to more reliably avoid double reporting exceptions that are also being sent by PlugCapture
.
An example configuration using all of the options could look like:
config :logger, Sentry.LoggerBackend,
# Send messages like `Logger.error("error")` to Sentry
capture_log_messages: true,
# Also send warn messages like `Logger.warn("warning")` to Sentry
level: :warn,
# Do not exclude exceptions from Plug/Cowboy
excluded_domains: [],
# Include metadata added with `Logger.metadata([foo_bar: "value"])`
metadata: [:foo_bar]
The LoggerBackend will now wrap non-exception errors like throws and bad exits into a Sentry.CrashError
to preserve the difference between exceptions and other types of errors.
This module now uses Logger metadata instead of using the process dictionary directly. The set_
functions no longer return their prior values, and the set_http_context
function was renamed to set_request_context
to match the data structure and verbiage used by Sentry.
To allow for more flexibility around HTTP libraries, the Sentry.HTTPClient
behaviour was refactored to be responsible only for transmitting the request and returning the response in #400. Sentry will still use hackney by default, but the dependency must now be explicitly listed. This change is intended to make it easier to use alternative HTTP libraries.
If you are currently using a custom Sentry.HTTPClient
, you will have to alter it to conform to the new callbacks.
The Sentry.capture_exception
function will now only accept an Elixir Exception
as the first argument. Non-exception values can be wrapped in other exceptions, or Sentry.capture_message
can be used to send a string message.
As always, if you run into any issues, don't hesitate to open an issue.