Skip to content

Commit 3381d83

Browse files
committed
in-app frames whitelist
1 parent 21153ae commit 3381d83

File tree

3 files changed

+77
-6
lines changed

3 files changed

+77
-6
lines changed

lib/sentry/event.ex

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ defmodule Sentry.Event do
154154

155155
@spec stacktrace_to_frames(Exception.stacktrace) :: [map]
156156
def stacktrace_to_frames(stacktrace) do
157+
in_app_module_whitelist = Application.get_env(:sentry, :in_app_module_whitelist, [])
157158
stacktrace
158159
|> Enum.map(fn(line) ->
159160
{mod, function, arity, location} = line
@@ -167,6 +168,7 @@ defmodule Sentry.Event do
167168
function: Exception.format_mfa(mod, function, arity),
168169
module: mod,
169170
lineno: line_number,
171+
in_app: is_in_app?(mod, in_app_module_whitelist),
170172
}
171173
|> put_source_context(file, line_number)
172174
end)
@@ -191,4 +193,23 @@ defmodule Sentry.Event do
191193

192194
defp arity_to_integer(arity) when is_list(arity), do: Enum.count(arity)
193195
defp arity_to_integer(arity) when is_integer(arity), do: arity
196+
197+
defp is_in_app?(nil, _in_app_whitelist), do: false
198+
defp is_in_app?(_, []), do: false
199+
defp is_in_app?(module, in_app_module_whitelist) do
200+
split_modules = module_split(module)
201+
202+
Enum.any?(in_app_module_whitelist, fn(module) ->
203+
whitelisted_split_modules = module_split(module)
204+
205+
count = Enum.count(whitelisted_split_modules)
206+
Enum.take(split_modules, count) == whitelisted_split_modules
207+
end)
208+
end
209+
210+
defp module_split(module) when is_binary(module) do
211+
String.split(module, ".")
212+
|> Enum.reject(&(&1 == "Elixir"))
213+
end
214+
defp module_split(module), do: module_split(String.Chars.to_string(module))
194215
end

test/event_test.exs

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ defmodule Sentry.EventTest do
2626
assert event.message == "(UndefinedFunctionError) function Sentry.Event.not_a_function/0 is undefined or private"
2727
assert is_binary(event.server_name)
2828
assert event.stacktrace == %{frames: Enum.reverse([
29-
%{filename: nil, function: "Sentry.Event.not_a_function/0", lineno: nil, module: Sentry.Event, context_line: nil, post_context: [], pre_context: []},
30-
%{filename: "test/event_test.exs", function: "Sentry.EventTest.event_generated_by_exception/1", lineno: 8, module: Sentry.EventTest, context_line: nil, post_context: [], pre_context: []},
31-
%{filename: "test/event_test.exs", function: "Sentry.EventTest.\"test parses error exception\"/1", lineno: 15, module: Sentry.EventTest, context_line: nil, post_context: [], pre_context: []},
32-
%{filename: "lib/ex_unit/runner.ex", function: "ExUnit.Runner.exec_test/1", lineno: 302, module: ExUnit.Runner, context_line: nil, post_context: [], pre_context: []},
33-
%{filename: "timer.erl", function: ":timer.tc/1", lineno: 166, module: :timer, context_line: nil, post_context: [], pre_context: []},
34-
%{filename: "lib/ex_unit/runner.ex", function: "anonymous fn/3 in ExUnit.Runner.spawn_test/3", lineno: 250, module: ExUnit.Runner, context_line: nil, post_context: [], pre_context: []}])
29+
%{filename: nil, function: "Sentry.Event.not_a_function/0", lineno: nil, module: Sentry.Event, context_line: nil, post_context: [], pre_context: [], in_app: false},
30+
%{filename: "test/event_test.exs", function: "Sentry.EventTest.event_generated_by_exception/1", lineno: 8, module: Sentry.EventTest, context_line: nil, post_context: [], pre_context: [], in_app: false},
31+
%{filename: "test/event_test.exs", function: "Sentry.EventTest.\"test parses error exception\"/1", lineno: 15, module: Sentry.EventTest, context_line: nil, post_context: [], pre_context: [], in_app: false},
32+
%{filename: "lib/ex_unit/runner.ex", function: "ExUnit.Runner.exec_test/1", lineno: 302, module: ExUnit.Runner, context_line: nil, post_context: [], pre_context: [], in_app: false},
33+
%{filename: "timer.erl", function: ":timer.tc/1", lineno: 166, module: :timer, context_line: nil, post_context: [], pre_context: [], in_app: false},
34+
%{filename: "lib/ex_unit/runner.ex", function: "anonymous fn/3 in ExUnit.Runner.spawn_test/3", lineno: 250, module: ExUnit.Runner, context_line: nil, post_context: [], pre_context: [], in_app: false}])
3535
}
3636
assert event.tags == %{}
3737
assert event.timestamp =~ ~r/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/
@@ -70,9 +70,58 @@ defmodule Sentry.EventTest do
7070
event = Sentry.Event.transform_exception(exception, [fingerprint: ["hello", "world"]])
7171
assert event.fingerprint == ["hello", "world"]
7272
end
73+
7374
test "not sending fingerprint when unset" do
7475
exception = RuntimeError.exception("error")
7576
event = Sentry.Event.transform_exception(exception, [])
7677
assert event.fingerprint == ["{{ default }}"]
7778
end
79+
80+
test "sets app_frame to true when configured" do
81+
modify_env(:sentry, in_app_module_whitelist: [Sentry, :random, Sentry.Submodule])
82+
exception = RuntimeError.exception("error")
83+
event = Sentry.Event.transform_exception(exception, [stacktrace: [{Elixir.Sentry.Fun, :method, 2, []}, {Elixir.Sentry, :other_method, 4, []},
84+
{:other_module, :a_method, 8, []}, {:random, :uniform, 0, []},
85+
{Sentry.Submodule.Fun, :this_method, 0, []}]])
86+
assert %{frames: [
87+
%{
88+
module: Sentry.Submodule.Fun,
89+
function: "Sentry.Submodule.Fun.this_method/0",
90+
in_app: true,
91+
filename: nil, lineno: nil,
92+
context_line: nil, post_context: [], pre_context: []
93+
},
94+
%{
95+
module: :random,
96+
function: ":random.uniform/0",
97+
in_app: true,
98+
filename: nil, lineno: nil,
99+
context_line: nil, post_context: [], pre_context: []
100+
},
101+
%{
102+
module: :other_module,
103+
function: ":other_module.a_method/8",
104+
in_app: false,
105+
filename: nil, lineno: nil,
106+
context_line: nil, post_context: [], pre_context: []
107+
},
108+
%{
109+
module: Sentry,
110+
function: "Sentry.other_method/4",
111+
in_app: true,
112+
filename: nil, lineno: nil,
113+
context_line: nil, post_context: [], pre_context: []
114+
},
115+
%{
116+
filename: nil,
117+
function: "Sentry.Fun.method/2",
118+
module: Sentry.Fun,
119+
lineno: nil,
120+
in_app: true,
121+
context_line: nil,
122+
post_context: [],
123+
pre_context: []
124+
},
125+
]} == event.stacktrace
126+
end
78127
end

test/logger_test.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ defmodule Sentry.LoggerTest do
8888
assert List.first(json["exception"])["value"] == "** (exit) :function_clause"
8989
assert List.last(json["stacktrace"]["frames"]) == %{"filename" => "lib/calendar.ex",
9090
"function" => "NaiveDateTime.from_erl/2",
91+
"in_app" => false,
9192
"lineno" => 1214,
9293
"module" => "Elixir.NaiveDateTime",
9394
"context_line" => nil,

0 commit comments

Comments
 (0)