From abcc42441eda7c8e178eda82fc22a45b7a852cd9 Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Wed, 12 Jul 2023 18:36:37 +0700 Subject: [PATCH 1/2] try/catch requests in http client --- lib/sentry/client.ex | 11 +++++++- mix.exs | 3 ++- mix.lock | 1 + test/client_test.exs | 60 ++++++++++++++++++++++++++++++++++++++++++++ test/event_test.exs | 1 + test/test_helper.exs | 2 ++ 6 files changed, 76 insertions(+), 2 deletions(-) diff --git a/lib/sentry/client.ex b/lib/sentry/client.ex index 4aa7a251..387509a9 100644 --- a/lib/sentry/client.ex +++ b/lib/sentry/client.ex @@ -216,6 +216,8 @@ defmodule Sentry.Client do e -> {:error, e} end + catch + kind, data -> {:error, {kind, data, __STACKTRACE__}} end @doc """ @@ -358,7 +360,14 @@ defmodule Sentry.Client do "Unable to encode JSON Sentry error - #{inspect(error)}" {:error, {:request_failure, last_error}} -> - "Error in HTTP Request to Sentry - #{inspect(last_error)}" + case last_error do + {kind, data, stacktrace} + when kind in [:exit, :throw, :error] and is_list(stacktrace) -> + Exception.format(kind, data, stacktrace) + + _other -> + "Error in HTTP Request to Sentry - #{inspect(last_error)}" + end {:error, error} -> inspect(error) diff --git a/mix.exs b/mix.exs index fbbd61c5..e86aa2dc 100644 --- a/mix.exs +++ b/mix.exs @@ -46,7 +46,8 @@ defmodule Sentry.Mixfile do {:ex_doc, "~> 0.29.0", only: :dev}, {:bypass, "~> 2.0", only: [:test]}, {:phoenix, "~> 1.5", only: [:test]}, - {:phoenix_html, "~> 2.0", only: [:test]} + {:phoenix_html, "~> 2.0", only: [:test]}, + {:mox, "~> 1.0", only: [:test]} ] end diff --git a/mix.lock b/mix.lock index 71e91c09..7e459bb7 100644 --- a/mix.lock +++ b/mix.lock @@ -18,6 +18,7 @@ "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mime": {:hex, :mime, "1.5.0", "203ef35ef3389aae6d361918bf3f952fa17a09e8e43b5aa592b93eba05d0fb8d", [:mix], [], "hexpm", "55a94c0f552249fc1a3dd9cd2d3ab9de9d3c89b559c2bd01121f824834f24746"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, + "mox": {:hex, :mox, "1.0.2", "dc2057289ac478b35760ba74165b4b3f402f68803dd5aecd3bfd19c183815d64", [:mix], [], "hexpm", "f9864921b3aaf763c8741b5b8e6f908f44566f1e427b2630e89e9a73b981fef2"}, "nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"}, "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, "phoenix": {:hex, :phoenix, "1.5.8", "71cfa7a9bb9a37af4df98939790642f210e35f696b935ca6d9d9c55a884621a4", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "35ded0a32f4836168c7ab6c33b88822eccd201bcd9492125a9bea4c54332d955"}, diff --git a/test/client_test.exs b/test/client_test.exs index 9959ec6e..86d212c2 100644 --- a/test/client_test.exs +++ b/test/client_test.exs @@ -1,6 +1,7 @@ defmodule Sentry.ClientTest do use ExUnit.Case import ExUnit.CaptureLog + import Mox import Sentry.TestEnvironmentHelper require Logger @@ -354,4 +355,63 @@ defmodule Sentry.ClientTest do Sentry.capture_message("something happened", extra: %{metadata: [keyword: "list"]}) end) =~ "Failed to send Sentry event. Unable to encode JSON" end + + describe "client handles exits/throws/exceptions in adapters" do + setup :verify_on_exit! + + setup do + modify_env(:sentry, + dsn: "http://public:secret@localhost:0/1", + client: Sentry.MockClient + ) + + faulty_capture_message = fn failure -> + expect(Sentry.MockClient, :post, fn _url, _headers, _body -> failure.() end) + {:ok, task} = Sentry.capture_message("all your code are belong to us", result: :async) + Task.await(task) + end + + {:ok, faulty_capture_message: faulty_capture_message} + end + + test "exits", %{faulty_capture_message: faulty_capture_message} do + log = + capture_log(fn -> + assert {:error, {:request_failure, {:exit, :through_the_window, _stacktrace}}} = + faulty_capture_message.(fn -> exit(:through_the_window) end) + end) + + assert log =~ """ + Failed to send Sentry event. ** (exit) :through_the_window + test/client_test.exs:\ + """ + end + + test "throws", %{faulty_capture_message: faulty_capture_message} do + log = + capture_log(fn -> + assert {:error, {:request_failure, {:throw, :catch_me_if_you_can, _stacktrace}}} = + faulty_capture_message.(fn -> throw(:catch_me_if_you_can) end) + end) + + assert log =~ """ + Failed to send Sentry event. ** (throw) :catch_me_if_you_can + test/client_test.exs:\ + """ + end + + test "exceptions", %{faulty_capture_message: faulty_capture_message} do + log = + capture_log(fn -> + assert {:error, + {:request_failure, {:error, %RuntimeError{message: "oops"}, _stacktrace}}} = + faulty_capture_message.(fn -> raise "oops" end) + end) + + assert log =~ """ + Failed to send Sentry event. ** (RuntimeError) oops + test/client_test.exs:\ + """ + end + end end diff --git a/test/event_test.exs b/test/event_test.exs index c6f0bea3..eba405f1 100644 --- a/test/event_test.exs +++ b/test/event_test.exs @@ -267,6 +267,7 @@ defmodule Sentry.EventTest do :metrics, :mime, :mimerl, + :mox, :parse_trans, :phoenix, :phoenix_html, diff --git a/test/test_helper.exs b/test/test_helper.exs index d7f91567..ff3d2685 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -5,6 +5,8 @@ Code.require_file("test/support/test_filter.exs") Code.require_file("test/support/test_gen_server.exs") Code.require_file("test/support/test_error_view.exs") +Mox.defmock(Sentry.MockClient, for: Sentry.HTTPClient) + ExUnit.start(assert_receive_timeout: 500) Application.ensure_all_started(:bypass) From 61231a2add1d34ec20634689a2c3710bfd073139 Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Wed, 12 Jul 2023 21:44:34 +0700 Subject: [PATCH 2/2] rename: Sentry.MockClient -> Sentry.HTTPClientMock --- test/client_test.exs | 4 ++-- test/test_helper.exs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/client_test.exs b/test/client_test.exs index 86d212c2..8582c89d 100644 --- a/test/client_test.exs +++ b/test/client_test.exs @@ -362,11 +362,11 @@ defmodule Sentry.ClientTest do setup do modify_env(:sentry, dsn: "http://public:secret@localhost:0/1", - client: Sentry.MockClient + client: Sentry.HTTPClientMock ) faulty_capture_message = fn failure -> - expect(Sentry.MockClient, :post, fn _url, _headers, _body -> failure.() end) + expect(Sentry.HTTPClientMock, :post, fn _url, _headers, _body -> failure.() end) {:ok, task} = Sentry.capture_message("all your code are belong to us", result: :async) Task.await(task) end diff --git a/test/test_helper.exs b/test/test_helper.exs index ff3d2685..5b351320 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -5,7 +5,7 @@ Code.require_file("test/support/test_filter.exs") Code.require_file("test/support/test_gen_server.exs") Code.require_file("test/support/test_error_view.exs") -Mox.defmock(Sentry.MockClient, for: Sentry.HTTPClient) +Mox.defmock(Sentry.HTTPClientMock, for: Sentry.HTTPClient) ExUnit.start(assert_receive_timeout: 500)