Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates Rollbax to use :logger rather than :error_logger #127

Closed
wants to merge 11 commits into from
2 changes: 1 addition & 1 deletion config/config.exs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use Mix.Config
import Config

config :ex_unit,
assert_receive_timeout: 800,
Expand Down
14 changes: 8 additions & 6 deletions lib/rollbax.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ defmodule Rollbax do
* `:api_endpoint` - (binary) the Rollbar endpoint to report exceptions and messages to.
Defaults to `https://api.rollbar.com/api/1/item/`.

* `:enable_crash_reports` - see `Rollbax.Logger`.
* `:enable_crash_reports` - see `Rollbax.LoggerHandler`.

* `:reporters` - see `Rollbax.Logger`.
* `:reporters` - see `Rollbax.LoggerHandler`.

* `:proxy` - (binary) a proxy that can be used to connect to the Rollbar host. For more
information about the format of the proxy, check the proxy URL description in the
Expand Down Expand Up @@ -69,6 +69,8 @@ defmodule Rollbax do

use Application

require Logger

@allowed_message_levels [:critical, :error, :warning, :info, :debug]

@doc false
Expand All @@ -84,9 +86,9 @@ defmodule Rollbax do
end

if config[:enable_crash_reports] do
# We do this because the handler will read `:reporters` out of the app's environment.
Application.put_env(:rollbax, :reporters, config[:reporters])
:error_logger.add_report_handler(Rollbax.Logger)
:logger.add_handler(:rollbax_handler, Rollbax.LoggerHandler, %{
config: %{reporters: config[:reporters]}
})
end

children = [
Expand All @@ -96,7 +98,7 @@ defmodule Rollbax do
Supervisor.start_link(children, strategy: :one_for_one)
end

defp init_config() do
defp init_config do
env = Application.get_all_env(:rollbax)

config =
Expand Down
22 changes: 12 additions & 10 deletions lib/rollbax/client.ex
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
defmodule Rollbax.Client do
@moduledoc false
@moduledoc """
This GenServer keeps a pre-built bare-bones version of an exception (a
"draft") to be reported to Rollbar, which is then filled with the data
related to each specific exception when such exception is being
reported. This GenServer is also responsible for actually sending data to
the Rollbar API and receiving responses from said API.

# This GenServer keeps a pre-built bare-bones version of an exception (a
# "draft") to be reported to Rollbar, which is then filled with the data
# related to each specific exception when such exception is being
# reported. This GenServer is also responsible for actually sending data to
# the Rollbar API and receiving responses from said API.
"""

use GenServer

require Logger

alias Rollbax.Item

require Logger

@name __MODULE__
@hackney_pool __MODULE__
@headers [{"content-type", "application/json"}]
Expand Down Expand Up @@ -47,12 +48,13 @@ defmodule Rollbax.Client do

def emit(level, timestamp, body, custom, occurrence_data)
when is_atom(level) and is_integer(timestamp) and timestamp > 0 and is_map(body) and
is_map(custom) and is_map(occurrence_data) do
is_map(custom) and
is_map(occurrence_data) do
if pid = Process.whereis(@name) do
event = {Atom.to_string(level), timestamp, body, custom, occurrence_data}
GenServer.cast(pid, {:emit, event})
else
Logger.warn(
Logger.warning(
"(Rollbax) Trying to report an exception but the :rollbax application has not been started",
rollbax: false
)
Expand Down
21 changes: 13 additions & 8 deletions lib/rollbax/item.ex
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ defmodule Rollbax.Item do
@spec compose(map, {String.t(), pos_integer, map, map, map}) :: map
def compose(draft, {level, timestamp, body, custom, occurrence_data})
when is_map(draft) and is_binary(level) and is_integer(timestamp) and timestamp > 0 and
is_map(body) and is_map(custom) and is_map(occurrence_data) do
is_map(body) and
is_map(custom) and is_map(occurrence_data) do
Map.update!(draft, "data", fn data ->
data
|> Map.merge(occurrence_data)
Expand Down Expand Up @@ -84,7 +85,7 @@ defmodule Rollbax.Item do

def exception_class_and_message(:exit, value) do
message =
if Exception.exception?(value) do
if is_exception(value) do
Exception.format_banner(:error, value)
else
Exception.format_exit(value)
Expand Down Expand Up @@ -114,13 +115,17 @@ defmodule Rollbax.Item do
end

defp stacktrace_entry_to_frame({fun, arity, location}) when is_integer(arity) do
%{"method" => Exception.format_fa(fun, arity)}
|> put_location(location)
put_location(%{"method" => Exception.format_fa(fun, arity)}, location)
end

defp stacktrace_entry_to_frame({fun, arity, location}) when is_list(arity) do
%{"method" => Exception.format_fa(fun, length(arity)), "args" => Enum.map(arity, &inspect/1)}
|> put_location(location)
put_location(
%{
"method" => Exception.format_fa(fun, length(arity)),
"args" => Enum.map(arity, &inspect/1)
},
location
)
end

defp maybe_format_application(module) do
Expand Down Expand Up @@ -155,12 +160,12 @@ defmodule Rollbax.Item do
end
end

defp host() do
defp host do
{:ok, host} = :inet.gethostname()
List.to_string(host)
end

defp notifier() do
defp notifier do
%{
"name" => "Rollbax",
"version" => unquote(Mix.Project.config()[:version])
Expand Down
113 changes: 0 additions & 113 deletions lib/rollbax/logger.ex

This file was deleted.

76 changes: 76 additions & 0 deletions lib/rollbax/logger_handler.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
defmodule Rollbax.LoggerHandler do
@moduledoc """
More information on this can be found in the documentation for `Logger.Handler`

1. This module can be added as a `:logger` handler
2. Log events come in to the `log/2` callback
3. It checks the configured reporters
4. Events are passed to the reporters for possible submission to Rollbar
5. Depending on the response, the event is either reported to Rollbar, the event is passed to the next reporter, or the event is ignored

This allows customizing and processing of events via reporters before sending to Rollbar.
"""

require Logger

@doc """
Handle a log message
"""
def log(event, %{config: %{reporters: reporters}}) when is_list(reporters) do
run_reporters(reporters, event)
end

@doc """
Handle initialization by making sure we have a valid config
"""
def adding_handler(config) do
{:ok, initialize_config(config)}
end

@doc """
Handle updated config by making sure the internal portion is valid
"""
def changing_config(:update, _old_config, new_config) do
{:ok, initialize_config(new_config)}
end

@doc """
Create a valid Rollbax.LoggerHandler config by filling in any missing options
"""
def initialize_config(existing) do
config =
existing
|> Map.get(:config, %{})
|> Map.put_new(:reporters, [Rollbax.Reporter.Standard])

existing
|> Map.put(:config, config)
|> Map.put_new(:initialized, true)
end

defp run_reporters([reporter | rest], %{level: level, meta: meta, msg: {:string, msg}} = event) do
case reporter.handle_event(level, {Logger, msg, meta[:time], meta}) do
%Rollbax.Exception{} = exception ->
Rollbax.report_exception(exception)

:next ->
run_reporters(rest, event)

:ignore ->
:ok
end
end

defp run_reporters([_ | _], event) do
# I think all messages will have a the format of {:string, msg} as defined above: but just in case
Logger.error("Rollbax.LoggerHandler: Unexpected event format: #{inspect(event)}")
:ok
end

# If no reporter ignored or reported this event, then we're gonna report this
# as a Rollbar "message" with the same logic that Logger uses to translate
# messages (so that it will have Elixir syntax when reported).
defp run_reporters([], _event) do
:ok
end
end
18 changes: 16 additions & 2 deletions lib/rollbax/reporter.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
defmodule Rollbax.Reporter do
@moduledoc """
Behaviour to be implemented by Rollbax reporters that wish to report `:error_logger` messages to
Rollbar. See `Rollbax.Logger` for more information.
Behaviour to be implemented by Rollbax reporters that wish to report `:logger` messages to
Rollbar. See `Rollbax.LoggerHandler` for more information.

The Event shape is taken from the 'logger_backends' package as specified here: https://github.com/elixir-lang/logger_backends/blob/master/lib/logger_backend.ex#L15

The handler should be designed to handle the following events:

- {level, group_leader, {Logger, message, timestamp, metadata}} where:
- level is one of :debug, :info, :warn, or :error, as previously described (for compatibility with pre 1.10 backends the :notice will be translated to :info and all messages above :error will be translated to :error)
- group_leader is the group leader of the process which logged the message
- {Logger, message, timestamp, metadata} is a tuple containing information about the logged message:
- the first element is always the atom Logger
- message is the actual message (as chardata)
- timestamp is the timestamp for when the message was logged, as a {{year, month, day}, {hour, minute, second, millisecond}} tuple
- metadata is a keyword list of metadata used when logging the message
- : flush
"""

@callback handle_event(type :: term, event :: term) :: Rollbax.Exception.t() | :next | :ignore
Expand Down
Loading