Skip to content

:error_logger.add_report_handler documentation issue #205

@DavidAntaramian

Description

@DavidAntaramian

We're preparing our upgrade to Sentry Elixir 6.0 at Timber, and we ran into an issue on the usage of :error_logger.add_report_handler/1 with umbrella applications.

Because :error_logger is implemented as a :gen_event manager and :error_logger.add_report_handler/1 is a lightweight wrapper around :gen_event.add_handler/3, report handlers are not unique by module. It is therefore valid to add a report handler multiple times.

This means that if an end-user of Sentry Elixir adds :error_logger.add_report_handler(Sentry.Logger) to the start/2 function in two applications in an umbrella application, there would be two Sentry.Logger instances. With Timber, we ended up calling it in 9 application, and the result was this:

iex(1)> :gen_event.which_handlers(:error_logger)                  
[Sentry.Logger, Sentry.Logger, Sentry.Logger, Sentry.Logger, Sentry.Logger,
 Sentry.Logger, Sentry.Logger, Sentry.Logger, Sentry.Logger,
 Logger.ErrorHandler, :error_logger]

Following that, a single error would be reported to Sentry 9 times, since the event would be sent to every instance of Sentry.Logger.

There are two solutions to fix this (we use the second):

  1. The easy-but-brittle solution is to only add the report handler in the start/2 of the primary entrypoint application. This ensures that Sentry.Logger will only be added once. However, if at some point the entry-point changes or the end-user switches to a multiple release style, they will need to switch to option 2. (And hopefully have documented this fact in case anyone joins the team later).

  2. The second solution is a bit more robust, but it makes implementation assumptions about :error_logger (notably that it will always be a :gen_event manager registered with the name :error_logger). It works by testing whether Sentry.Logger is already in the list of handlers. With this logic, it can be added to any and every application's start/2 function but only ever be added as a handler once:

if !(Sentry.Logger in :gen_event.which_handlers(:error_logger)) do
  :ok = :error_logger.add_report_handler(Sentry.Logger)
end

Metadata

Metadata

Assignees

Labels

No labels
No labels
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions