-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Sanitize the context when tracking errors (#94)
Adds a `ErrorTracker.Filter` behavior that users can supply, it has a single function `sanitize/1` that takes an error context and returns a new error context which will be saved in the DB. Closes #88
- Loading branch information
Showing
3 changed files
with
106 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
defmodule ErrorTracker.Filter do | ||
@moduledoc """ | ||
Behaviour for sanitizing & modifying the error context before it's saved. | ||
defmodule MyApp.ErrorFilter do | ||
@behaviour ErrorTracker.Filter | ||
@impl true | ||
def sanitize(context) do | ||
context # Modify the context object (add or remove fields as much as you need.) | ||
end | ||
end | ||
Once implemented, include it in the ErrorTracker configuration: | ||
config :error_tracker, filter: MyApp.Filter | ||
With this configuration in place, the ErrorTracker will call `MyApp.Filter.sanitize/1` to get a context before | ||
saving error occurrence. | ||
> #### A note on performance {: .warning} | ||
> | ||
> Keep in mind that the `sanitize/1` 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 """ | ||
This function will be given an error context to inspect/modify before it's saved. | ||
""" | ||
@callback sanitize(context :: map()) :: map() | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
defmodule ErrorTracker.FilterTest do | ||
use ErrorTracker.Test.Case | ||
|
||
setup context do | ||
if filter = context[:filter] do | ||
previous_setting = Application.get_env(:error_tracker, :filter) | ||
Application.put_env(:error_tracker, :filter, filter) | ||
# Ensure that the application env is restored after each test | ||
on_exit(fn -> Application.put_env(:error_tracker, :filter, previous_setting) end) | ||
end | ||
|
||
[] | ||
end | ||
|
||
@sensitive_ctx %{ | ||
"request" => %{ | ||
"headers" => %{ | ||
"accept" => "application/json, text/plain, */*", | ||
"authorization" => "Bearer 12341234" | ||
} | ||
} | ||
} | ||
|
||
test "without an filter, context objects are saved as they are." do | ||
assert %ErrorTracker.Occurrence{context: ctx} = | ||
report_error(fn -> raise "BOOM" end, @sensitive_ctx) | ||
|
||
assert ctx == @sensitive_ctx | ||
end | ||
|
||
@tag filter: ErrorTracker.FilterTest.AuthHeaderHider | ||
test "user defined filter should be used to sanitize the context before it's saved." do | ||
assert %ErrorTracker.Occurrence{context: ctx} = | ||
report_error(fn -> raise "BOOM" end, @sensitive_ctx) | ||
|
||
assert ctx != @sensitive_ctx | ||
|
||
cleaned_header_value = | ||
ctx |> Map.get("request") |> Map.get("headers") |> Map.get("authorization") | ||
|
||
assert cleaned_header_value == "REMOVED" | ||
end | ||
end | ||
|
||
defmodule ErrorTracker.FilterTest.AuthHeaderHider do | ||
@behaviour ErrorTracker.Filter | ||
|
||
def sanitize(context) do | ||
context | ||
|> Enum.map(fn | ||
{"authorization", _} -> | ||
{"authorization", "REMOVED"} | ||
|
||
o -> | ||
o | ||
end) | ||
|> Enum.map(fn | ||
{key, val} when is_map(val) -> {key, sanitize(val)} | ||
o -> o | ||
end) | ||
|> Map.new() | ||
end | ||
end |