From 73060973ce68e0e6dcb99b3c730159a0c789efba Mon Sep 17 00:00:00 2001 From: crbelaus Date: Mon, 2 Sep 2024 17:08:15 +0200 Subject: [PATCH 1/5] Ignore errors --- lib/error_tracker.ex | 9 +++++++-- lib/error_tracker/ignorer.ex | 39 ++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 lib/error_tracker/ignorer.ex diff --git a/lib/error_tracker.ex b/lib/error_tracker.ex index 7477138..2a513df 100644 --- a/lib/error_tracker.ex +++ b/lib/error_tracker.ex @@ -111,10 +111,9 @@ defmodule ErrorTracker do {kind, reason} = normalize_exception(exception, stacktrace) {:ok, stacktrace} = ErrorTracker.Stacktrace.new(stacktrace) {:ok, error} = Error.new(kind, reason, stacktrace) - context = Map.merge(get_context(), given_context) - if enabled?() do + if enabled?() && !ignored?(error, context) do {_error, occurrence} = upsert_error!(error, stacktrace, context, reason) occurrence else @@ -195,6 +194,12 @@ defmodule ErrorTracker do !!Application.get_env(:error_tracker, :enabled, true) end + defp ignored?(error, context) do + ignorer = Application.get_env(:error_tracker, :ignorer) + + ignorer && !ignorer.ignore?(error, context) + end + defp normalize_exception(%struct{} = ex, _stacktrace) when is_exception(ex) do {to_string(struct), Exception.message(ex)} end diff --git a/lib/error_tracker/ignorer.ex b/lib/error_tracker/ignorer.ex new file mode 100644 index 0000000..28e19b9 --- /dev/null +++ b/lib/error_tracker/ignorer.ex @@ -0,0 +1,39 @@ +defmodule ErrorTracker.Ignorer do + @moduledoc """ + Behaviour for ignoring errors. + + The ErrorTracker tracks every error that happens in your application. In certain cases you may + want to ignore some errors and don't track them. To do so you can implement this behaviour. + + defmodule MyApp.ErrorIgnorer do + @behaviour ErrorTracker.Ignorer + + @impl true + def ignore?(error = %ErrorTracker.Error{}, context) do + # return true if the error should be ignored + end + end + + Once implemented, include it in the ErrorTracker configuration: + + config :error_tracker, ignorer: MyApp.ErrorIgnorer + + With this configuration in place, the ErrorTracker will call `MyApp.ErrorIgnorer.ignore?/2` before + tracking errors. If the function returns `true` the error will be ignored and won't be tracked. + + > #### A note on performance {: .warning} + > + > Keep in mind that the `ignore?/2` will be called in the context of the ErrorTracker itself. + > Slow code will have a significant impact in the ErrorTracker performance. Buggy code can bring + > the ErrorTracker process down. + """ + + @doc """ + Decide wether the given error should be ignored or not. + + This function receives both the current Error and context and should return a boolean indicating + if it should be ignored or not. If the function returns true the error will be ignored, otherwise + it will be tracked. + """ + @callback ignore?(error :: ErrorTracker.Error.t(), context :: map()) :: boolean +end From fba3e82b49a3aec25dc028aeb0f0c56b11805400 Mon Sep 17 00:00:00 2001 From: crbelaus Date: Mon, 2 Sep 2024 17:08:19 +0200 Subject: [PATCH 2/5] Add tests --- test/error_tracker/ignorer_test.exs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 test/error_tracker/ignorer_test.exs diff --git a/test/error_tracker/ignorer_test.exs b/test/error_tracker/ignorer_test.exs new file mode 100644 index 0000000..7a1ace0 --- /dev/null +++ b/test/error_tracker/ignorer_test.exs @@ -0,0 +1,21 @@ +defmodule ErrorTracker.IgnorerTest do + use ErrorTracker.Test.Case + + setup_all do + Application.put_env(:error_tracker, :ignorer, ErrorTracker.EveryErrorIgnorer) + end + + test "ignores errors" do + refute report_error(fn -> raise "[IGNORE] Sample error" end) + assert report_error(fn -> raise "Sample error" end) + end +end + +defmodule ErrorTracker.EveryErrorIgnorer do + @behaviour ErrorTracker.Ignorer + + @impl true + def ignore?(error, _context) do + String.contains?(error.reason, "[IGNORE]") + end +end From 60671cac19c913fd0c363eeadd6a128e1eb26ede Mon Sep 17 00:00:00 2001 From: crbelaus Date: Mon, 2 Sep 2024 17:08:23 +0200 Subject: [PATCH 3/5] Update docs --- guides/Getting Started.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/guides/Getting Started.md b/guides/Getting Started.md index 7793e14..00378a8 100644 --- a/guides/Getting Started.md +++ b/guides/Getting Started.md @@ -136,9 +136,9 @@ This is completely optional, and you can find more information about it in the ` ## Notifications -We currently do not support notifications out of the box. +Currently ErrorTracker does not support notifications out of the box. -However, we provideo some detailed Telemetry events that you may use to implement your own notifications following your custom rules and notification channels. +However, it provides some detailed Telemetry events that you may use to implement your own notifications following your custom rules and notification channels. If you want to take a look at the events you can attach to, take a look at `ErrorTracker.Telemetry` module documentation. @@ -149,3 +149,10 @@ environments where you may want to prune old errors that have been resolved. The `ErrorTracker.Plugins.Pruner` module provides automatic pruning functionality with a configurable interval and error age. + +## Ignoring errors + +ErrorTracker tracks every error by default. In certain cases some errors may be expected or just not interesting to track. +ErrorTracker provides functionality that allows you to ignore errors based on their attributes and context. + +Take a look at the `ErrorTracker.Ignorer` behaviour for more information about how to implement your own ignorer. From 53868c816702071d9908616f9f20ca9b203fb09c Mon Sep 17 00:00:00 2001 From: crbelaus Date: Fri, 6 Sep 2024 16:32:36 +0200 Subject: [PATCH 4/5] Fix condition --- lib/error_tracker.ex | 2 +- test/error_tracker/ignorer_test.exs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/error_tracker.ex b/lib/error_tracker.ex index 2a513df..c737cde 100644 --- a/lib/error_tracker.ex +++ b/lib/error_tracker.ex @@ -197,7 +197,7 @@ defmodule ErrorTracker do defp ignored?(error, context) do ignorer = Application.get_env(:error_tracker, :ignorer) - ignorer && !ignorer.ignore?(error, context) + ignorer && ignorer.ignore?(error, context) end defp normalize_exception(%struct{} = ex, _stacktrace) when is_exception(ex) do diff --git a/test/error_tracker/ignorer_test.exs b/test/error_tracker/ignorer_test.exs index 7a1ace0..14de416 100644 --- a/test/error_tracker/ignorer_test.exs +++ b/test/error_tracker/ignorer_test.exs @@ -6,8 +6,8 @@ defmodule ErrorTracker.IgnorerTest do end test "ignores errors" do - refute report_error(fn -> raise "[IGNORE] Sample error" end) - assert report_error(fn -> raise "Sample error" end) + assert :noop = report_error(fn -> raise "[IGNORE] Sample error" end) + assert %ErrorTracker.Occurrence{} = report_error(fn -> raise "Sample error" end) end end From f671cc6460d8297fec0bf4db5dd20c080555750a Mon Sep 17 00:00:00 2001 From: crbelaus Date: Fri, 6 Sep 2024 16:38:26 +0200 Subject: [PATCH 5/5] Improve tests --- test/error_tracker/ignorer_test.exs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/test/error_tracker/ignorer_test.exs b/test/error_tracker/ignorer_test.exs index 14de416..9b1bbd8 100644 --- a/test/error_tracker/ignorer_test.exs +++ b/test/error_tracker/ignorer_test.exs @@ -1,14 +1,28 @@ defmodule ErrorTracker.IgnorerTest do use ErrorTracker.Test.Case - setup_all do - Application.put_env(:error_tracker, :ignorer, ErrorTracker.EveryErrorIgnorer) + setup context do + if ignorer = context[:ignorer] do + previous_setting = Application.get_env(:error_tracker, :ignorer) + Application.put_env(:error_tracker, :ignorer, ignorer) + # Ensure that the application env is restored after each test + on_exit(fn -> Application.put_env(:error_tracker, :ignorer, previous_setting) end) + end + + [] end - test "ignores errors" do + @tag ignorer: ErrorTracker.EveryErrorIgnorer + test "with an ignorer ignores errors" do assert :noop = report_error(fn -> raise "[IGNORE] Sample error" end) assert %ErrorTracker.Occurrence{} = report_error(fn -> raise "Sample error" end) end + + @tag ignorer: false + test "without an ignorer does not ignore errors" do + assert %ErrorTracker.Occurrence{} = report_error(fn -> raise "[IGNORE] Sample error" end) + assert %ErrorTracker.Occurrence{} = report_error(fn -> raise "Sample error" end) + end end defmodule ErrorTracker.EveryErrorIgnorer do