@@ -29,7 +29,22 @@ defmodule Sentry.Event do
2929 @ typedoc """
3030 The type for the event struct.
3131
32- See [`%Sentry.Event{}`](`__struct__/0`) for more information.
32+ All of the fields in this struct map directly to the fields described in the
33+ [Sentry documentation](https://develop.sentry.dev/sdk/event-payloads). These fields
34+ are the exceptions, and are specific to the Elixir Sentry SDK:
35+
36+ * `:source` - the source of the event. `Sentry.LoggerBackend` and `Sentry.LoggerHandler`
37+ set this to `:logger`, while `Sentry.PlugCapture` and `Sentry.PlugContext` set it to
38+ `:plug`. You can set it to any atom. See the `:event_source` option in `create_event/1`
39+ and `transform_exception/2`.
40+
41+ * `:original_exception` - the original exception that is being reported, if there's one.
42+ The Elixir Sentry SDK manipulates reported exceptions to make them fit the payload
43+ required by the Sentry API, and these end up in the `:exception` field. The
44+ `:original_exception` field, instead, contains the original exception as the raw Elixir
45+ term (such as `%RuntimeError{...}`).
46+
47+ See also [`%Sentry.Event{}`](`__struct__/0`).
3348 """
3449 @ type t ( ) :: % __MODULE__ {
3550 # Required
@@ -53,113 +68,144 @@ defmodule Sentry.Event do
5368 # Interfaces.
5469 breadcrumbs: [ Interfaces.Breadcrumb . t ( ) ] ,
5570 contexts: Interfaces . context ( ) ,
56- exception: Interfaces.Exception . t ( ) | nil ,
71+ exception: [ Interfaces.Exception . t ( ) ] ,
5772 message: String . t ( ) | nil ,
5873 request: Interfaces . request ( ) ,
5974 sdk: Interfaces.SDK . t ( ) | nil ,
6075 user: Interfaces . user ( ) | nil ,
6176
6277 # Non-payload fields.
63- __source__: term ( ) ,
64- __original_exception__ : Exception . t ( ) | nil
78+ source: atom ( ) ,
79+ original_exception : Exception . t ( ) | nil
6580 }
6681
6782 @ doc """
6883 The struct representing the event.
6984
70- In general, you 're not advised to manipulate this struct's fields directly. Instead,
71- try to use functions such as `create_event/1` or `transform_exception/2` for creating
85+ You 're not advised to manipulate this struct's fields directly. Instead,
86+ use functions such as `create_event/1` or `transform_exception/2` for creating
7287 events.
88+
89+ See the `t:t/0` type for information on the fields and their types.
7390 """
7491 @ enforce_keys [ :event_id , :timestamp ]
7592 defstruct [
7693 # Required. Hexadecimal string representing a uuid4 value. The length is exactly 32
7794 # characters. Dashes are not allowed. Has to be lowercase.
78- : event_id,
95+ event_id: nil ,
7996
8097 # Required. Indicates when the event was created in the Sentry SDK. The format is either a
8198 # string as defined in RFC 3339 or a numeric (integer or float) value representing the number
8299 # of seconds that have elapsed since the Unix epoch.
83- :timestamp ,
84-
85- # Optional fields without defaults.
86- :level ,
87- :logger ,
88- :transaction ,
89- :server_name ,
90- :release ,
91- :dist ,
92-
93- # Interfaces.
94- :breadcrumbs ,
95- :contexts ,
96- :exception ,
97- :message ,
98- :request ,
99- :sdk ,
100- :user ,
100+ timestamp: nil ,
101+
102+ # Optional fields.
103+ breadcrumbs: [ ] ,
104+ contexts: nil ,
105+ dist: nil ,
106+ environment: "production" ,
107+ exception: [ ] ,
108+ extra: % { } ,
109+ fingerprint: [ ] ,
110+ level: nil ,
111+ logger: nil ,
112+ message: nil ,
113+ modules: % { } ,
114+ platform: :elixir ,
115+ release: nil ,
116+ request: % { } ,
117+ sdk: nil ,
118+ server_name: nil ,
119+ tags: % { } ,
120+ transaction: nil ,
121+ user: % { } ,
101122
102123 # "Culprit" is not documented anymore and we should move to transactions at some point.
103124 # https://forum.sentry.io/t/culprit-deprecated-in-favor-of-what/4871/9
104- : culprit,
125+ culprit: nil ,
105126
106127 # Non-payload "private" fields.
107- :__source__ ,
108- :__original_exception__ ,
109-
110- # Required. Has to be "elixir".
111- platform: :elixir ,
112-
113- # Optional fields with defaults.
114- tags: % { } ,
115- modules: % { } ,
116- extra: % { } ,
117- fingerprint: [ ] ,
118- environment: "production"
128+ source: nil ,
129+ original_exception: nil
119130 ]
120131
132+ # Removes all the non-payload keys from the event so that the client can render
133+ @ doc false
134+ @ spec remove_non_payload_keys ( t ( ) ) :: map ( )
135+ def remove_non_payload_keys ( % __MODULE__ { } = event ) do
136+ event
137+ |> Map . from_struct ( )
138+ |> Map . drop ( [ :original_exception , :source ] )
139+ end
140+
121141 @ doc """
122142 Creates an event struct out of collected context and options.
123143
144+ > #### Merging Options with Context and Config {: .info}
145+ >
146+ > Some of the options documented below are **merged** with the Sentry context, or
147+ > with the Sentry context *and* the configuration. The option you pass here always
148+ > has higher precedence, followed by the context and finally by the configuration.
149+ >
150+ > See also `Sentry.Context` for information on the Sentry context and `Sentry` for
151+ > information on configuration.
152+
124153 ## Options
125154
126- * `:exception` - an `t:Exception.t/0`
155+ * `:exception` - an `t:Exception.t/0`. This is the exception that gets reported in the
156+ `:exception` field of `t:t/0`. The term passed here also ends up unchanged in the
157+ `:original_exception` field of `t:t/0`. This option is **required** unless the
158+ `:message` option is present. This is not present by default.
127159
128- * `:stacktrace` - a stacktrace, as in `t:Exception.stacktrace/0`
160+ * `:stacktrace` - a stacktrace, as in `t:Exception.stacktrace/0`. This is not present
161+ by default.
129162
130- * `:message` - a message (`t:String.t/0`)
163+ * `:message` - a message (`t:String.t/0`). This is not present by default.
131164
132165 * `:extra` - map of extra context, which gets merged with the current context
133- (see `Sentry.Context`)
166+ (see `Sentry.Context.set_extra_context/1`). If fields collide, the ones
167+ in the map passed through this option have precedence over the ones in
168+ the context. Defaults to `%{}`.
134169
135170 * `:user` - map of user context, which gets merged with the current context
136- (see `Sentry.Context`)
171+ (see `Sentry.Context.set_user_context/1`). If fields collide, the ones
172+ in the map passed through this option have precedence over the ones in
173+ the context. Defaults to `%{}`.
137174
138- * `:tags` - map of tags context, which gets merged with the current context
139- (see `Sentry.Context`)
175+ * `:tags` - map of tags context, which gets merged with the current context (see
176+ `Sentry.Context.set_tags_context/1`) and with the `:tags` option in the global
177+ Sentry configuration. If fields collide, the ones in the map passed through
178+ this option have precedence over the ones in the context, which have precedence
179+ over the ones in the configuration. Defaults to `%{}`.
140180
141181 * `:request` - map of request context, which gets merged with the current context
142- (see `Sentry.Context`)
182+ (see `Sentry.Context.set_request_context/1`). If fields collide, the ones
183+ in the map passed through this option have precedence over the ones in
184+ the context. Defaults to `%{}`.
143185
144- * `:breadcrumbs` - list of breadcrumbs
186+ * `:breadcrumbs` - list of breadcrumbs. This list gets **prepended** to the list
187+ in the context (see `Sentry.Context.add_breadcrumb/1`). Defaults to `[]`.
145188
146- * `:level` - error level (see `t:t/0`)
189+ * `:level` - error level (see `t:t/0`). Defaults to `:error`.
147190
148- * `:fingerprint` - list of the fingerprint for grouping this event (a list of `t:String.t/0`)
191+ * `:fingerprint` - list of the fingerprint for grouping this event (a list
192+ of `t:String.t/0`). Defaults to `["{{ default }}"]`.
149193
150- * `:event_source` - the source of the event. This fills in the `:__source__ ` field of the
151- returned struct.
194+ * `:event_source` - the source of the event. This fills in the `:source ` field of the
195+ returned struct. This is not present by default.
152196
153197 ## Examples
154198
155199 iex> event = create_event(exception: %RuntimeError{message: "oops"}, level: :warning)
156200 iex> event.level
157201 :warning
158- iex> event.exception.type
202+ iex> hd( event.exception) .type
159203 "RuntimeError"
204+ iex> event.original_exception
205+ %RuntimeError{message: "oops"}
160206
161- iex> event = create_event(event_source: :plug)
162- iex> event.__source__
207+ iex> event = create_event(message: "Unknown route", event_source: :plug)
208+ iex> event.source
163209 :plug
164210
165211 """
@@ -173,7 +219,7 @@ defmodule Sentry.Event do
173219 | { :level , level ( ) }
174220 | { :fingerprint , [ String . t ( ) ] }
175221 | { :message , String . t ( ) }
176- | { :event_source , term ( ) }
222+ | { :event_source , atom ( ) }
177223 | { :exception , Exception . t ( ) }
178224 | { :stacktrace , Exception . stacktrace ( ) }
179225 def create_event ( opts ) when is_list ( opts ) do
@@ -191,25 +237,18 @@ defmodule Sentry.Event do
191237 request: request_context
192238 } = Sentry.Context . get_all ( )
193239
240+ level = Keyword . get ( opts , :level , :error )
194241 fingerprint = Keyword . get ( opts , :fingerprint , [ "{{ default }}" ] )
195242
196- extra =
197- extra_context
198- |> Map . merge ( Keyword . get ( opts , :extra , % { } ) )
199-
200- user =
201- user_context
202- |> Map . merge ( Keyword . get ( opts , :user , % { } ) )
243+ extra = Map . merge ( extra_context , Keyword . get ( opts , :extra , % { } ) )
244+ user = Map . merge ( user_context , Keyword . get ( opts , :user , % { } ) )
245+ request = Map . merge ( request_context , Keyword . get ( opts , :request , % { } ) )
203246
204247 tags =
205248 Config . tags ( )
206249 |> Map . merge ( tags_context )
207250 |> Map . merge ( Keyword . get ( opts , :tags , % { } ) )
208251
209- request =
210- request_context
211- |> Map . merge ( Keyword . get ( opts , :request , % { } ) )
212-
213252 breadcrumbs =
214253 Keyword . get ( opts , :breadcrumbs , [ ] )
215254 |> Kernel . ++ ( breadcrumbs_context )
@@ -218,31 +257,30 @@ defmodule Sentry.Event do
218257
219258 message = Keyword . get ( opts , :message )
220259 exception = Keyword . get ( opts , :exception )
260+ stacktrace = Keyword . get ( opts , :stacktrace )
261+ source = Keyword . get ( opts , :event_source )
221262
222263 % __MODULE__ {
223- event_id: UUID . uuid4_hex ( ) ,
224- timestamp: timestamp ,
225- level: Keyword . get ( opts , :level , :error ) ,
226- server_name: Config . server_name ( ) || to_string ( :net_adm . localhost ( ) ) ,
227- release: Config . release ( ) ,
228- sdk: @ sdk ,
229- tags: tags ,
230- modules:
231- Enum . reduce ( @ deps , % { } , fn app , acc ->
232- Map . put ( acc , app , to_string ( Application . spec ( app , :vsn ) ) )
233- end ) ,
234- culprit: culprit_from_stacktrace ( Keyword . get ( opts , :stacktrace , [ ] ) ) ,
235- extra: extra ,
236264 breadcrumbs: breadcrumbs ,
237265 contexts: generate_contexts ( ) ,
238- exception: coerce_exception ( exception , Keyword . get ( opts , :stacktrace ) , message ) ,
239- message: message ,
240- fingerprint: fingerprint ,
266+ culprit: culprit_from_stacktrace ( Keyword . get ( opts , :stacktrace , [ ] ) ) ,
241267 environment: Config . environment_name ( ) ,
242- user: user ,
268+ event_id: UUID . uuid4_hex ( ) ,
269+ exception: List . wrap ( coerce_exception ( exception , stacktrace , message ) ) ,
270+ extra: extra ,
271+ fingerprint: fingerprint ,
272+ level: level ,
273+ message: message ,
274+ modules: Map . new ( @ deps , & { & 1 , to_string ( Application . spec ( & 1 , :vsn ) ) } ) ,
275+ original_exception: exception ,
276+ release: Config . release ( ) ,
243277 request: request ,
244- __source__: Keyword . get ( opts , :event_source ) ,
245- __original_exception__: exception
278+ sdk: @ sdk ,
279+ server_name: Config . server_name ( ) || to_string ( :net_adm . localhost ( ) ) ,
280+ source: source ,
281+ tags: tags ,
282+ timestamp: timestamp ,
283+ user: user
246284 }
247285 end
248286
0 commit comments