diff --git a/.travis.yml b/.travis.yml index 002569d..565f972 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,22 @@ -sudo: false - language: elixir +elixir: + - 1.11.1 +otp_release: + - 23.1 -otp_release: '21.1' -elixir: '1.8' - -stages: - - check formatted - - test - -jobs: +matrix: include: - - stage: test - - - otp_release: '18.3' - elixir: '1.4' + - elixir: 1.11.1 + otp_release: 23.1 + - elixir: 1.8.0 + otp_release: 19.3 - - stage: check formatted - script: mix format --check-formatted +script: + - if [[ "$TRAVIS_ELIXIR_VERSION" == "1.11"* ]]; then mix format --check-formatted; fi + - mix test +sudo: false +dist: trusty +cache: + directories: + - _build + - deps diff --git a/lib/rollbax/reporter/standard.ex b/lib/rollbax/reporter/standard.ex index 8857395..325d0b9 100644 --- a/lib/rollbax/reporter/standard.ex +++ b/lib/rollbax/reporter/standard.ex @@ -10,7 +10,11 @@ defmodule Rollbax.Reporter.Standard do handle_error_format(format, data) end - def handle_event(_type, _event) do + def handle_event(:error_report, {_, :crash_report, data}) do + handle_error_format(:crash_report, data) + end + + def handle_event(_, _) do :next end @@ -70,6 +74,51 @@ defmodule Rollbax.Reporter.Standard do } end + # OTP error logger crash report + defp handle_error_format(:crash_report, [data, _]) do + {m, f, a} = Keyword.fetch!(data, :initial_call) + + name = + case Keyword.get(data, :registered_name) do + [] -> data |> Keyword.fetch!(:pid) |> inspect() + name -> inspect(name) + end + + {class, message, stacktrace, crash_report} = + case Keyword.fetch!(data, :error_info) do + {_, %class{message: message}, stacktrace} -> + {inspect(class), message, stacktrace, ""} + + {:exit, reason, stacktrace} when is_atom(reason) -> + {inspect(reason), inspect(reason), stacktrace, ""} + + {_, info, stacktrace} when is_tuple(info) -> + case elem(info, 0) do + %class{message: message} -> {inspect(class), message, stacktrace, inspect(info)} + %class{} -> {inspect(class), inspect(class), stacktrace, inspect(info)} + atom when is_atom(atom) -> {inspect(atom), inspect(atom), stacktrace, inspect(info)} + {%class{message: message}, inner_stacktrace} -> {inspect(class), message, inner_stacktrace, inspect(info)} + {%class{}, inner_stacktrace} -> {inspect(class), inspect(class), inner_stacktrace, inspect(info)} + {atom, inner_stacktrace} when is_atom(atom) -> {inspect(atom), inspect(atom), inner_stacktrace, inspect(info)} + {{%class{message: message}, inner_stacktrace}, _} -> {inspect(class), message, inner_stacktrace, inspect(info)} + reason -> {"ProcessCrash", "A process crashed", stacktrace, inspect(reason, limit: :infinity)} + end + end + + %Rollbax.Exception{ + class: "Crash report (#{class})", + message: message, + stacktrace: stacktrace, + custom: %{ + name: name, + started_from: data |> Keyword.fetch!(:ancestors) |> hd() |> inspect(), + function: inspect(Function.capture(m, f, length(a))), + arguments: inspect(a), + crash_report: crash_report + } + } + end + defp handle_error_format('** State machine ' ++ _ = message, data) do if charlist_contains?(message, 'Callback mode') do :next @@ -94,7 +143,7 @@ defmodule Rollbax.Reporter.Standard do # Any other error (for example, the ones logged through # :error_logger.error_msg/1). This reporter doesn't report those to Rollbar. - defp handle_error_format(_format, _data) do + defp handle_error_format(_, _) do :next end diff --git a/mix.lock b/mix.lock index 1cf3253..daba4d0 100644 --- a/mix.lock +++ b/mix.lock @@ -1,13 +1,13 @@ %{ "cowboy": {:hex, :cowboy, "1.1.2", "61ac29ea970389a88eca5a65601460162d370a70018afe6f949a29dca91f3bb0", [:rebar3], [{:cowlib, "~> 1.0.2", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.3.2", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"}, - "cowlib": {:hex, :cowlib, "1.0.2", "9d769a1d062c9c3ac753096f868ca121e2730b9a377de23dec0f7e08b1df84ee", [:make], []}, + "cowlib": {:hex, :cowlib, "1.0.2", "9d769a1d062c9c3ac753096f868ca121e2730b9a377de23dec0f7e08b1df84ee", [:make], [], "hexpm"}, "earmark": {:hex, :earmark, "1.2.4", "99b637c62a4d65a20a9fb674b8cffb8baa771c04605a80c911c4418c69b75439", [:mix], [], "hexpm"}, "ex_doc": {:hex, :ex_doc, "0.18.1", "37c69d2ef62f24928c1f4fdc7c724ea04aecfdf500c4329185f8e3649c915baf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"}, - "hackney": {:hex, :hackney, "1.3.2", "43bd07ab88753f5e136e38fddd2a09124bee25733b03361eeb459d0173fc17ab", [:rebar, :make], [{:idna, "~> 1.0.2", [hex: :idna, optional: false]}, {:ssl_verify_hostname, "~> 1.0.5", [hex: :ssl_verify_hostname, optional: false]}]}, - "idna": {:hex, :idna, "1.0.3", "d456a8761cad91c97e9788c27002eb3b773adaf5c893275fc35ba4e3434bbd9b", [:rebar3], []}, + "hackney": {:hex, :hackney, "1.3.2", "43bd07ab88753f5e136e38fddd2a09124bee25733b03361eeb459d0173fc17ab", [:make, :rebar], [{:idna, "~> 1.0.2", [hex: :idna, repo: "hexpm", optional: false]}, {:ssl_verify_hostname, "~> 1.0.5", [hex: :ssl_verify_hostname, repo: "hexpm", optional: false]}], "hexpm"}, + "idna": {:hex, :idna, "1.0.3", "d456a8761cad91c97e9788c27002eb3b773adaf5c893275fc35ba4e3434bbd9b", [:rebar3], [], "hexpm"}, "jason": {:hex, :jason, "1.0.0", "0f7cfa9bdb23fed721ec05419bcee2b2c21a77e926bce0deda029b5adc716fe2", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, - "mime": {:hex, :mime, "1.0.1", "05c393850524767d13a53627df71beeebb016205eb43bfbd92d14d24ec7a1b51", [:mix], []}, + "mime": {:hex, :mime, "1.0.1", "05c393850524767d13a53627df71beeebb016205eb43bfbd92d14d24ec7a1b51", [:mix], [], "hexpm"}, "plug": {:hex, :plug, "1.4.3", "236d77ce7bf3e3a2668dc0d32a9b6f1f9b1f05361019946aae49874904be4aed", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1", [hex: :cowboy, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm"}, "ranch": {:hex, :ranch, "1.3.2", "e4965a144dc9fbe70e5c077c65e73c57165416a901bd02ea899cfd95aa890986", [:rebar3], [], "hexpm"}, - "ssl_verify_hostname": {:hex, :ssl_verify_hostname, "1.0.6", "45866d958d9ae51cfe8fef0050ab8054d25cba23ace43b88046092aa2c714645", [:make], []}, + "ssl_verify_hostname": {:hex, :ssl_verify_hostname, "1.0.6", "45866d958d9ae51cfe8fef0050ab8054d25cba23ace43b88046092aa2c714645", [:make], [], "hexpm"}, } diff --git a/test/rollbax/logger_test.exs b/test/rollbax/logger_test.exs index c291329..4de5a43 100644 --- a/test/rollbax/logger_test.exs +++ b/test/rollbax/logger_test.exs @@ -33,7 +33,7 @@ defmodule Rollbax.LoggerTest do def init(args), do: {:ok, args} def handle_cast(:raise_elixir, state) do - Map.fetch!(%{}, :nonexistent_key) + _ = Map.fetch!(%{}, :nonexistent_key) {:noreply, state} end end @@ -47,11 +47,11 @@ defmodule Rollbax.LoggerTest do data = assert_performed_request()["data"] # Check the exception. - assert data["body"]["trace"]["exception"] == %{ + assert %{ "class" => "GenServer terminating (KeyError)", - "message" => "key :nonexistent_key not found in: %{}" - } - + "message" => message + } = data["body"]["trace"]["exception"] + assert message =~ "key :nonexistent_key not found" assert [frame] = find_frames_for_current_file(data["body"]["trace"]["frames"]) assert frame["method"] == "MyGenServer.handle_cast/2" @@ -247,7 +247,7 @@ defmodule Rollbax.LoggerTest do ~r[anonymous fn/0 in Rollbax.LoggerTest.(\")?test task with anonymous function raising an error(\")?/1] assert data["custom"]["name"] == inspect(task) - assert data["custom"]["function"] =~ ~r/\A#Function<.* in Rollbax\.LoggerTest/ + assert data["custom"]["function"] =~ ~r/Rollbax\.LoggerTest/ assert data["custom"]["arguments"] == "[]" end) end @@ -270,10 +270,9 @@ defmodule Rollbax.LoggerTest do assert [frame] = find_frames_for_current_file(data["body"]["trace"]["frames"]) assert frame["method"] == "MyModule.raise_error/1" - assert data["custom"] == %{ + assert Map.take(data["custom"], ["name", "function", "started_from"]) == %{ "name" => inspect(task), "function" => "&MyModule.raise_error/1", - "arguments" => ~s(["my message"]), "started_from" => inspect(self()) } end)