Skip to content

Commit 98b1509

Browse files
authored
Add exception mechanism set handled/unhandled (#677)
Closes #666.
1 parent 989a684 commit 98b1509

File tree

7 files changed

+71
-12
lines changed

7 files changed

+71
-12
lines changed

lib/sentry/client.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ defmodule Sentry.Client do
234234
defp render_exception(%Interfaces.Exception{} = exception) do
235235
exception
236236
|> Map.from_struct()
237+
|> update_if_present(:mechanism, &Map.from_struct/1)
237238
|> update_if_present(:stacktrace, fn %Interfaces.Stacktrace{frames: frames} ->
238239
%{frames: Enum.map(frames, &Map.from_struct/1)}
239240
end)

lib/sentry/event.ex

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,13 @@ defmodule Sentry.Event do
254254
`:message` option is present. This is not present by default. See
255255
`Sentry.capture_message/2`. *Available since v10.1.0*.
256256
"""
257+
],
258+
259+
## Internal options
260+
handled: [
261+
type: :boolean,
262+
default: true,
263+
doc: false
257264
]
258265
]
259266

@@ -330,6 +337,7 @@ defmodule Sentry.Event do
330337
exception = Keyword.get(opts, :exception)
331338
stacktrace = Keyword.get(opts, :stacktrace)
332339
source = Keyword.get(opts, :event_source)
340+
handled? = Keyword.fetch!(opts, :handled)
333341

334342
event = %__MODULE__{
335343
attachments: attachments_context,
@@ -338,7 +346,7 @@ defmodule Sentry.Event do
338346
culprit: culprit_from_stacktrace(Keyword.get(opts, :stacktrace, [])),
339347
environment: Config.environment_name(),
340348
event_id: UUID.uuid4_hex(),
341-
exception: List.wrap(coerce_exception(exception, stacktrace, message)),
349+
exception: List.wrap(coerce_exception(exception, stacktrace, message, handled?)),
342350
extra: extra,
343351
fingerprint: Keyword.fetch!(opts, :fingerprint),
344352
level: Keyword.fetch!(opts, :level),
@@ -403,11 +411,13 @@ defmodule Sentry.Event do
403411
# If we have a message with a stacktrace, but no exceptions, for now we store the stacktrace in
404412
# the "threads" interface and we don't fill in the "exception" interface altogether. This might
405413
# be eventually fixed in Sentry itself: https://github.com/getsentry/sentry/issues/61239
406-
defp coerce_exception(_exception = nil, _stacktrace_or_nil, message) when is_binary(message) do
414+
defp coerce_exception(_exception = nil, _stacktrace_or_nil, message, _handled?)
415+
when is_binary(message) do
407416
nil
408417
end
409418

410-
defp coerce_exception(exception, stacktrace_or_nil, _message) when is_exception(exception) do
419+
defp coerce_exception(exception, stacktrace_or_nil, _message, handled?)
420+
when is_exception(exception) do
411421
stacktrace =
412422
if is_list(stacktrace_or_nil) do
413423
%Interfaces.Stacktrace{frames: stacktrace_to_frames(stacktrace_or_nil)}
@@ -416,11 +426,12 @@ defmodule Sentry.Event do
416426
%Interfaces.Exception{
417427
type: inspect(exception.__struct__),
418428
value: Exception.message(exception),
419-
stacktrace: stacktrace
429+
stacktrace: stacktrace,
430+
mechanism: %Interfaces.Exception.Mechanism{handled: handled?}
420431
}
421432
end
422433

423-
defp coerce_exception(_exception = nil, stacktrace, _message = nil) do
434+
defp coerce_exception(_exception = nil, stacktrace, _message = nil, _handled?) do
424435
unless is_nil(stacktrace) do
425436
raise ArgumentError,
426437
"cannot provide a :stacktrace option without an exception or a message, got: #{inspect(stacktrace)}"

lib/sentry/interfaces.ex

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,28 @@ defmodule Sentry.Interfaces do
113113
defstruct [:message, :params, :formatted]
114114
end
115115

116+
defmodule Exception.Mechanism do
117+
@moduledoc """
118+
The struct for the **exception mechanism** to be used within exceptions.
119+
120+
See `Sentry.Interfaces.Exception`.
121+
"""
122+
123+
@moduledoc since: "10.2.0"
124+
125+
@typedoc since: "10.2.0"
126+
@type t() :: %__MODULE__{
127+
type: String.t(),
128+
handled: boolean() | nil,
129+
data: map() | nil,
130+
synthetic: boolean() | nil,
131+
help_link: String.t() | nil,
132+
meta: map() | nil
133+
}
134+
135+
defstruct [:handled, :data, :synthetic, :help_link, :meta, type: "generic"]
136+
end
137+
116138
defmodule Exception do
117139
@moduledoc """
118140
The struct for the **exception** interface.
@@ -127,11 +149,12 @@ defmodule Sentry.Interfaces do
127149
type: String.t(),
128150
value: String.t(),
129151
module: String.t() | nil,
130-
stacktrace: Sentry.Interfaces.Stacktrace.t() | nil
152+
stacktrace: Sentry.Interfaces.Stacktrace.t() | nil,
153+
mechanism: Sentry.Interfaces.Exception.Mechanism.t() | nil
131154
}
132155

133156
@enforce_keys [:type, :value]
134-
defstruct [:type, :value, :module, :stacktrace]
157+
defstruct [:type, :value, :module, :stacktrace, :mechanism]
135158
end
136159

137160
defmodule Stacktrace.Frame do

lib/sentry/logger_backend.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,8 @@ defmodule Sentry.LoggerBackend do
138138
# If the crash reason is an exception, we want to report the exception itself
139139
# for better event reporting.
140140
{exception, stacktrace} when is_exception(exception) and is_list(stacktrace) ->
141-
Sentry.capture_exception(exception, Keyword.put(opts, :stacktrace, stacktrace))
141+
opts = Keyword.merge(opts, stacktrace: stacktrace, handled: false)
142+
Sentry.capture_exception(exception, opts)
142143

143144
# If the crash reason is a {reason, stacktrace} tuple, then we can report
144145
# the originally-logged message (as a message) and include the stacktrace in

lib/sentry/logger_handler.ex

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ defmodule Sentry.LoggerHandler do
171171
case Map.new(report) do
172172
%{report: %{reason: {exception, stacktrace}}}
173173
when is_exception(exception) and is_list(stacktrace) ->
174-
Sentry.capture_exception(exception, Keyword.put(sentry_opts, :stacktrace, stacktrace))
174+
sentry_opts = Keyword.merge(sentry_opts, stacktrace: stacktrace, handled: false)
175+
Sentry.capture_exception(exception, sentry_opts)
175176

176177
%{report: %{reason: {reason, stacktrace}}} when is_list(stacktrace) ->
177178
sentry_opts = Keyword.put(sentry_opts, :stacktrace, stacktrace)
@@ -219,7 +220,8 @@ defmodule Sentry.LoggerHandler do
219220
%__MODULE__{}
220221
)
221222
when is_exception(exception) and is_list(stacktrace) do
222-
Sentry.capture_exception(exception, Keyword.put(sentry_opts, :stacktrace, stacktrace))
223+
sentry_opts = Keyword.merge(sentry_opts, stacktrace: stacktrace, handled: false)
224+
Sentry.capture_exception(exception, sentry_opts)
223225
end
224226

225227
defp log_from_crash_reason({reason, stacktrace}, string_message, sentry_opts, %__MODULE__{})

lib/sentry/plug_capture.ex

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,13 @@ defmodule Sentry.PlugCapture do
137137
exception
138138
end
139139

140-
_ = Sentry.capture_exception(exception, stacktrace: stacktrace, event_source: :plug)
140+
_ =
141+
Sentry.capture_exception(exception,
142+
stacktrace: stacktrace,
143+
event_source: :plug,
144+
handled: false
145+
)
146+
141147
:ok
142148
end
143149

test/event_test.exs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,22 @@ defmodule Sentry.EventTest do
180180
assert event.exception == [
181181
%Interfaces.Exception{
182182
type: "RuntimeError",
183-
value: "foo"
183+
value: "foo",
184+
mechanism: %Interfaces.Exception.Mechanism{handled: true}
185+
}
186+
]
187+
end
188+
189+
test "fills in the exception interface with the :handled option" do
190+
assert %Event{} =
191+
event =
192+
Event.create_event(exception: %RuntimeError{message: "foo"}, handled: false)
193+
194+
assert event.exception == [
195+
%Interfaces.Exception{
196+
type: "RuntimeError",
197+
value: "foo",
198+
mechanism: %Interfaces.Exception.Mechanism{handled: false}
184199
}
185200
]
186201
end

0 commit comments

Comments
 (0)