1
1
defmodule Logger.Backends.Internal do
2
- # TODO: Move the docs to a separate package
3
-
4
- @ moduledoc """
5
- `:gen_event`-based backends with overload protection.
6
-
7
- This module provides backends for Elixir's Logger with
8
- built-in overload protection. This was the default
9
- mechanism for hooking into Elixir's Logger until Elixir v1.15.
10
-
11
- Elixir backends run in a separate process which comes with overload
12
- protection. All backends run in this same process as a unified front
13
- for handling log events.
14
-
15
- The available backends by default are:
16
-
17
- * `Logger.Backends.Console` - logs messages to the console
18
- (see its documentation for more information)
19
-
20
- Developers may also implement their own backends, an option that
21
- is explored in more detail later.
22
-
23
- The initial backends are loaded via the `:backends` configuration.
24
- However, by the time this application starts, the code for your
25
- own and third-party backends may not yet be available. For this reason,
26
- it is preferred to add and remove backends via `add/2` and
27
- `remove/2` functions. This is often done in your `c:Application.start/2`
28
- callback:
29
-
30
- @impl true
31
- def start(_type, _args) do
32
- Logger.Backends.add(MyCustomBackend)
33
-
34
- The backend can be configured either on the `add_backend/2` call:
35
-
36
- @impl true
37
- def start(_type, _args) do
38
- Logger.Backends.add(MyCustomBackend, some_config: ...)
39
-
40
- Or in your config files:
41
-
42
- config :logger, MyCustomBackend,
43
- some_config: ...
44
-
45
- ## Application configuration
46
-
47
- Application configuration goes under the `:logger` application for
48
- backwards compatibility. The following keys must be set before
49
- the `:logger` application (and this application) are started.
50
-
51
- * `:backends` - the backends to be used. Defaults to `[]`.
52
- See the "Backends" section for more information.
53
-
54
- * `:start_options` - passes start options to Logger's main process, such
55
- as `:spawn_opt` and `:hibernate_after`. All options in `t:GenServer.option/0`
56
- are accepted, except `:name`.
57
-
58
- ## Runtime configuration
59
-
60
- The following keys can be set at runtime via the `configure/1` function.
61
- In your config files, they also go under the `:logger` application
62
- for backwards compatibility.
63
-
64
- * `:utc_log` - when `true`, uses UTC in logs. By default it uses
65
- local time (i.e., it defaults to `false`).
66
-
67
- * `:truncate` - the maximum message size to be logged (in bytes).
68
- Defaults to 8192 bytes. Note this configuration is approximate.
69
- Truncated messages will have `" (truncated)"` at the end.
70
- The atom `:infinity` can be passed to disable this behavior.
71
-
72
- * `:sync_threshold` - if the `Logger` manager has more than
73
- `:sync_threshold` messages in its queue, `Logger` will change
74
- to *sync mode*, to apply backpressure to the clients.
75
- `Logger` will return to *async mode* once the number of messages
76
- in the queue is reduced to one below the `sync_threshold`.
77
- Defaults to 20 messages. `:sync_threshold` can be set to `0` to
78
- force *sync mode*.
79
-
80
- * `:discard_threshold` - if the `Logger` manager has more than
81
- `:discard_threshold` messages in its queue, `Logger` will change
82
- to *discard mode* and messages will be discarded directly in the
83
- clients. `Logger` will return to *sync mode* once the number of
84
- messages in the queue is reduced to one below the `discard_threshold`.
85
- Defaults to 500 messages.
86
-
87
- * `:discard_threshold_periodic_check` - a periodic check that
88
- checks and reports if logger is discarding messages. It logs a warning
89
- message whenever the system is (or continues) in discard mode and
90
- it logs a warning message whenever if the system was discarding messages
91
- but stopped doing so after the previous check. By default it runs
92
- every `30_000` milliseconds.
93
-
94
- ## Custom backends
95
-
96
- Any developer can create their own backend. Since `Logger` is an
97
- event manager powered by `:gen_event`, writing a new backend
98
- is a matter of creating an event handler, as described in the
99
- [`:gen_event`](`:gen_event`) documentation.
100
-
101
- From now on, we will be using the term "event handler" to refer
102
- to your custom backend, as we head into implementation details.
103
-
104
- Once Logger starts, it installs all event handlers listed under
105
- the `:backends` configuration into the `Logger` event manager.
106
- The event manager and all added event handlers are automatically
107
- supervised by `Logger`.
108
-
109
- Note that if a backend fails to start by returning `{:error, :ignore}`
110
- from its `init/1` callback, then it's not added to the backends but
111
- nothing fails. If a backend fails to start by returning `{:error, reason}`
112
- from its `init/1` callback, the system will fail to start.
113
-
114
- Once initialized, the handler should be designed to handle the
115
- following events:
116
-
117
- * `{level, group_leader, {Logger, message, timestamp, metadata}}` where:
118
- * `level` is one of `:debug`, `:info`, `:warn`, or `:error`, as previously
119
- described (for compatibility with pre 1.10 backends the `:notice` will
120
- be translated to `:info` and all messages above `:error` will be translated
121
- to `:error`)
122
- * `group_leader` is the group leader of the process which logged the message
123
- * `{Logger, message, timestamp, metadata}` is a tuple containing information
124
- about the logged message:
125
- * the first element is always the atom `Logger`
126
- * `message` is the actual message (as chardata)
127
- * `timestamp` is the timestamp for when the message was logged, as a
128
- `{{year, month, day}, {hour, minute, second, millisecond}}` tuple
129
- * `metadata` is a keyword list of metadata used when logging the message
130
-
131
- * `:flush`
132
-
133
- It is recommended that handlers ignore messages where the group
134
- leader is in a different node than the one where the handler is
135
- installed. For example:
136
-
137
- def handle_event({_level, gl, {Logger, _, _, _}}, state)
138
- when node(gl) != node() do
139
- {:ok, state}
140
- end
141
-
142
- In the case of the event `:flush` handlers should flush any pending
143
- data. This event is triggered by `Logger.flush/0`.
144
-
145
- Furthermore, backends can be configured via the `configure_backend/2`
146
- function which requires event handlers to handle calls of the
147
- following format:
148
-
149
- {:configure, options}
150
-
151
- where `options` is a keyword list. The result of the call is the result
152
- returned by `configure_backend/2`. The recommended return value for
153
- successful configuration is `:ok`. For example:
154
-
155
- def handle_call({:configure, options}, state) do
156
- new_state = reconfigure_state(state, options)
157
- {:ok, :ok, new_state}
158
- end
159
-
160
- It is recommended that backends support at least the following configuration
161
- options:
162
-
163
- * `:level` - the logging level for that backend
164
- * `:format` - the logging format for that backend
165
- * `:metadata` - the metadata to include in that backend
166
-
167
- Check the `Logger.Backends.Console` implementation in Elixir's codebase
168
- for examples on how to handle the recommendations in this section and
169
- how to process the existing options.
170
- """
2
+ @ moduledoc false
171
3
172
4
use Supervisor
173
-
174
5
@ name __MODULE__
175
6
@ type backend :: :gen_event . handler ( )
176
7
@@ -179,10 +10,11 @@ defmodule Logger.Backends.Internal do
179
10
180
11
See the module doc for more information.
181
12
"""
13
+ @ backend_options [ :sync_threshold , :discard_threshold , :truncate , :utc_log ]
182
14
@ spec configure ( keyword ) :: :ok
183
15
def configure ( options ) do
184
16
ensure_started ( )
185
- Logger.Backends.Config . configure ( options )
17
+ Logger.Backends.Config . configure ( Keyword . take ( options , @ backend_options ) )
186
18
:ok = :logger . update_handler_config ( Logger , :config , :refresh )
187
19
end
188
20
0 commit comments