From 416be1c5b23e5ed9d790292c073364debd3212fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sundstr=C3=B6m=20Valter?= Date: Tue, 26 Apr 2022 21:26:01 +0200 Subject: [PATCH 1/5] Add Elixir 1.10@OTP21 and 1.13@OTP24 to CI --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 39019b7..4a8d5ab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,6 +39,10 @@ jobs: elixir: 1.5 - otp: 21.3 elixir: 1.8 + - otp: 21.3 + elixir: 1.10 + - otp: 24 + elixir: 1.13 env: MIX_ENV: test From 3b3e9a35c3c74d2f24d3116e351f6edb50be1ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sundstr=C3=B6m=20Valter?= Date: Tue, 26 Apr 2022 22:34:32 +0200 Subject: [PATCH 2/5] Copy crash report handling from --- lib/rollbax/reporter/standard.ex | 64 ++++++++++++++++++++++++++++++++ test/rollbax/logger_test.exs | 16 ++++---- 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/lib/rollbax/reporter/standard.ex b/lib/rollbax/reporter/standard.ex index 8857395..510c0bc 100644 --- a/lib/rollbax/reporter/standard.ex +++ b/lib/rollbax/reporter/standard.ex @@ -10,6 +10,10 @@ defmodule Rollbax.Reporter.Standard do handle_error_format(format, data) end + def handle_event(:error_report, {_pid, :crash_report, data}) do + handle_error_format(:crash_report, data) + end + def handle_event(_type, _event) do :next end @@ -92,6 +96,66 @@ 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 + # 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 diff --git a/test/rollbax/logger_test.exs b/test/rollbax/logger_test.exs index db44c33..8703b8e 100644 --- a/test/rollbax/logger_test.exs +++ b/test/rollbax/logger_test.exs @@ -32,8 +32,9 @@ defmodule Rollbax.LoggerTest do def init(args), do: {:ok, args} - def handle_cast(:raise_elixir, _state) do - Map.fetch!(Map.new(), :nonexistent_key) + def handle_cast(:raise_elixir, state) do + :ok = Map.fetch!(Map.new(), :nonexistent_key) + {:noreply, state} end end @@ -236,7 +237,7 @@ defmodule Rollbax.LoggerTest do data = assert_performed_request()["data"] assert data["body"]["trace"]["exception"] == %{ - "class" => "Task terminating (RuntimeError)", + "class" => "Crash report (RuntimeError)", "message" => "oops" } @@ -246,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 @@ -262,7 +263,7 @@ defmodule Rollbax.LoggerTest do data = assert_performed_request()["data"] assert data["body"]["trace"]["exception"] == %{ - "class" => "Task terminating (RuntimeError)", + "class" => "Crash report (RuntimeError)", "message" => "my message" } @@ -272,8 +273,9 @@ defmodule Rollbax.LoggerTest do assert data["custom"] == %{ "name" => inspect(task), "function" => "&MyModule.raise_error/1", - "arguments" => ~s(["my message"]), - "started_from" => inspect(self()) + "arguments" => "[:Argument__1]", + "started_from" => inspect(self()), + "crash_report" => "" } end) after From 4a449834280eb36dbd66ae647c179754b99dd9e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sundstr=C3=B6m=20Valter?= Date: Tue, 26 Apr 2022 22:35:09 +0200 Subject: [PATCH 3/5] Use start_supervised stop tests hanging in 1.12+ --- test/test_helper.exs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/test/test_helper.exs b/test/test_helper.exs index 475a68d..0e938cf 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -18,13 +18,16 @@ defmodule ExUnit.RollbaxCase do api_endpoint \\ "http://localhost:4004", proxy \\ nil ) do - Rollbax.Client.start_link( - api_endpoint: api_endpoint, - access_token: token, - environment: env, - enabled: true, - custom: custom, - proxy: proxy + start_supervised( + {Rollbax.Client, + [ + api_endpoint: api_endpoint, + access_token: token, + environment: env, + enabled: true, + custom: custom, + proxy: proxy + ]} ) end From 1a7f135f3b617616dd7d91380d57d589594f2e8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sundstr=C3=B6m=20Valter?= Date: Tue, 26 Apr 2022 22:42:19 +0200 Subject: [PATCH 4/5] Add test for undefined MFA --- test/rollbax/logger_test.exs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/rollbax/logger_test.exs b/test/rollbax/logger_test.exs index 8703b8e..609b723 100644 --- a/test/rollbax/logger_test.exs +++ b/test/rollbax/logger_test.exs @@ -282,6 +282,19 @@ defmodule Rollbax.LoggerTest do purge_module(MyModule) end + test "task with undefined mfa" do + defmodule Test.UndefinedMFA do + def func(_arg), do: nil + end + + capture_log(fn -> + {:ok, task} = Task.start(Test.UndefinedMFA, :func, []) + data = assert_performed_request()["data"] + end) + after + purge_module(Test.UndefinedMFA) + end + if List.to_integer(:erlang.system_info(:otp_release)) < 19 do test "gen_fsm terminating" do defmodule Elixir.MyGenFsm do From 0e5a30daf9dfca91813168edc6f01c248d7ab5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sundstr=C3=B6m=20Valter?= Date: Tue, 26 Apr 2022 22:49:28 +0200 Subject: [PATCH 5/5] Handle tuple infos --- lib/rollbax/reporter/standard.ex | 11 +++++++++-- test/rollbax/logger_test.exs | 22 +++++++++++++++++++--- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/lib/rollbax/reporter/standard.ex b/lib/rollbax/reporter/standard.ex index 510c0bc..27b7389 100644 --- a/lib/rollbax/reporter/standard.ex +++ b/lib/rollbax/reporter/standard.ex @@ -114,8 +114,15 @@ defmodule Rollbax.Reporter.Standard do {:exit, reason, stacktrace} when is_atom(reason) -> {inspect(reason), inspect(reason), stacktrace, ""} - {_, info, stacktrace} when is_tuple(info) -> - case elem(info, 0) do + {_, info, stacktrace} -> + info = + if is_tuple(info) do + elem(info, 0) + else + info + end + + case info do %class{message: message} -> {inspect(class), message, stacktrace, inspect(info)} diff --git a/test/rollbax/logger_test.exs b/test/rollbax/logger_test.exs index 609b723..d967020 100644 --- a/test/rollbax/logger_test.exs +++ b/test/rollbax/logger_test.exs @@ -283,16 +283,32 @@ defmodule Rollbax.LoggerTest do end test "task with undefined mfa" do - defmodule Test.UndefinedMFA do + defmodule Test.Undef do def func(_arg), do: nil end capture_log(fn -> - {:ok, task} = Task.start(Test.UndefinedMFA, :func, []) + {:ok, task} = Task.start(Elixir.UndefinedMFA, :func, []) + data = assert_performed_request()["data"] + + assert data["body"]["trace"]["exception"] == %{ + "class" => "Crash report (:undef)", + "message" => ":undef" + } + + assert find_frames_for_current_file(data["body"]["trace"]["frames"]) == [] + + assert data["custom"] == %{ + "name" => inspect(task), + "function" => "&UndefinedMFA.func/0", + "arguments" => "[]", + "started_from" => inspect(self()), + "crash_report" => ":undef" + } end) after - purge_module(Test.UndefinedMFA) + purge_module(UndefinedMFA) end if List.to_integer(:erlang.system_info(:otp_release)) < 19 do