11defmodule Sentry.LoggerBackend do
22 @ moduledoc """
33 This module makes use of Elixir 1.7's new Logger metadata to report
4- crashes processes. It replaces the previous `Sentry.Logger` sytem.
4+ crashed processes. It replaces the previous `Sentry.Logger` sytem.
5+
6+ To include the backend in your application, the backend can be added in your
7+ application file:
8+
9+ def start(_type, _opts) do
10+ children = [
11+ supervisor(MyApp.Repo, []),
12+ supervisor(MyAppWeb.Endpoint, [])
13+ ]
14+
15+ opts = [strategy: :one_for_one, name: MyApp.Supervisor]
16+
17+ {:ok, _} = Logger.add_backend(Sentry.LoggerBackend)
18+
19+ Supervisor.start_link(children, opts)
20+ end
21+
22+ If you are on OTP 21+ and would like to configure the backend to include metadata from
23+ `Logger.metadata/0` in reported events, it can be enabled:
24+
25+ {:ok, _} = Logger.add_backend(Sentry.LoggerBackend)
26+ Logger.configure_backend(Sentry.LoggerBackend, include_logger_metadata: true)
27+
28+
29+ It is important to be aware of whether this will include sensitive information
30+ in Sentry events before enabling it.
31+
32+ ## Options
33+
34+ The supported options are:
35+
36+ * `:include_logger_metadata` - Enabling this option will read any key/value
37+ pairs with with binary, atom or number values from `Logger.metadata/0`
38+ and include that dictionary under the `:logger_metadata` key in an
39+ event's `:extra` metadata. This option defaults to `false`.
540 """
641 @ behaviour :gen_event
742
8- defstruct level: nil
43+ defstruct level: nil , include_logger_metadata: false
944
1045 def init ( __MODULE__ ) do
11- config = Application . get_env ( :logger , :sentry , [ ] )
46+ config = Application . get_env ( :logger , __MODULE__ , [ ] )
1247 { :ok , init ( config , % __MODULE__ { } ) }
1348 end
1449
1550 def init ( { __MODULE__ , opts } ) when is_list ( opts ) do
1651 config =
17- Application . get_env ( :logger , :sentry , [ ] )
52+ Application . get_env ( :logger , __MODULE__ , [ ] )
1853 |> Keyword . merge ( opts )
1954
2055 { :ok , init ( config , % __MODULE__ { } ) }
2156 end
2257
23- def handle_call ( { :configure , _options } , state ) do
58+ def handle_call ( { :configure , options } , state ) do
59+ config =
60+ Application . get_env ( :logger , __MODULE__ , [ ] )
61+ |> Keyword . merge ( options )
62+
63+ Application . put_env ( :logger , __MODULE__ , config )
64+ state = init ( config , state )
2465 { :ok , :ok , state }
2566 end
2667
@@ -29,16 +70,30 @@ defmodule Sentry.LoggerBackend do
2970 end
3071
3172 def handle_event ( { _level , _gl , { Logger , _msg , _ts , meta } } , state ) do
73+ % { include_logger_metadata: include_logger_metadata } = state
74+
75+ opts =
76+ if include_logger_metadata do
77+ [
78+ extra: % {
79+ logger_metadata: build_logger_metadata ( meta )
80+ }
81+ ]
82+ else
83+ [ ]
84+ end
85+
3286 case Keyword . get ( meta , :crash_reason ) do
3387 { reason , stacktrace } ->
3488 opts =
35- Keyword . put ( [ ] , :event_source , :logger )
89+ opts
90+ |> Keyword . put ( :event_source , :logger )
3691 |> Keyword . put ( :stacktrace , stacktrace )
3792
3893 Sentry . capture_exception ( reason , opts )
3994
4095 reason when is_atom ( reason ) and not is_nil ( reason ) ->
41- Sentry . capture_exception ( reason , event_source: :logger )
96+ Sentry . capture_exception ( reason , [ { :event_source , :logger } | opts ] )
4297
4398 _ ->
4499 :ok
@@ -69,6 +124,15 @@ defmodule Sentry.LoggerBackend do
69124
70125 defp init ( config , % __MODULE__ { } = state ) do
71126 level = Keyword . get ( config , :level )
72- % { state | level: level }
127+ include_logger_metadata = Keyword . get ( config , :include_logger_metadata )
128+ % { state | level: level , include_logger_metadata: include_logger_metadata }
129+ end
130+
131+ defp build_logger_metadata ( meta ) do
132+ meta
133+ |> Enum . filter ( fn { _key , value } ->
134+ is_binary ( value ) || is_atom ( value ) || is_number ( value )
135+ end )
136+ |> Enum . into ( % { } )
73137 end
74138end
0 commit comments