Skip to content

Commit b52d166

Browse files
committed
Finish LoggerBackends extraction
1 parent 9cdff30 commit b52d166

File tree

5 files changed

+30
-240
lines changed

5 files changed

+30
-240
lines changed

lib/logger/lib/logger.ex

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ defmodule Logger do
299299
300300
Erlang/OTP logger provides handlers. Handlers represent ability to integrate
301301
into the logging system to handle each logged message/event. Elixir automatically
302-
configures the default handler, but you can use Erlang's [`:logger`](`:logger)
302+
configures the default handler, but you can use Erlang's [`:logger`](`:logger`)
303303
module to add other handlers too.
304304
305305
Erlang/OTP handlers must be listed under your own application. For example,
@@ -364,9 +364,12 @@ defmodule Logger do
364364
All previous console configuration, except for `:level`, now go under
365365
`:default_formatter`.
366366
367-
* If you want to use the previous `:console` implementation,
368-
based on `Logger.Backends`, you can set `backends: [Logger.Backends.Console]`
369-
and place the configuration under `config :logger, Logger.Backends.Console`
367+
* If you want to use the previous `:console` implementation based on Logger
368+
Backends, you can still set `backends: [Logger.Backends.Console]` and place
369+
the configuration under `config :logger, Logger.Backends.Console`. Although
370+
consider using the [`:logger_backends`](https://github.com/elixir-lang/logger_backends)
371+
project in such case, as `Logger.Backends.Console` itself will be deprecated
372+
in future releases
370373
371374
"""
372375

@@ -725,7 +728,7 @@ defmodule Logger do
725728
Adds a new backend.
726729
"""
727730
# TODO: Deprecate this on Elixir v1.19
728-
@doc deprecated: "Use Logger.Backends.add/2 from :logger_backends dependency"
731+
@doc deprecated: "Use LoggerBackends.add/2 from :logger_backends dependency"
729732
def add_backend(backend, opts \\ []) do
730733
Logger.Backends.Internal.add(backend, opts)
731734
end
@@ -734,7 +737,7 @@ defmodule Logger do
734737
Removes a backend.
735738
"""
736739
# TODO: Deprecate this on Elixir v1.19
737-
@doc deprecated: "Use Logger.Backends.remove/2 from :logger_backends dependency"
740+
@doc deprecated: "Use LoggerBackends.remove/2 from :logger_backends dependency"
738741
def remove_backend(backend, opts \\ []) do
739742
Logger.Backends.Internal.remove(backend, opts)
740743
end
@@ -743,7 +746,7 @@ defmodule Logger do
743746
Configures the given backend.
744747
"""
745748
# TODO: Deprecate this on Elixir v1.19
746-
@doc deprecated: "Use Logger.Backends.configure/2 from :logger_backends dependency"
749+
@doc deprecated: "Use LoggerBackends.configure/2 from :logger_backends dependency"
747750
def configure_backend(:console, options) when is_list(options) do
748751
options = Keyword.merge(Application.get_env(:logger, :console, []), options)
749752
Application.put_env(:logger, :console, options)

lib/logger/lib/logger/app.ex

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ defmodule Logger.App do
1616
:error -> {[], true}
1717
end
1818

19-
# TODO: Warn if backends: [:console] is set on Elixir v1.19
20-
# TODO: Warn if :logger, :console is set on Elixir v1.19
19+
# TODO: Warn if :backends is set on Elixir v1.19
20+
# TODO: Warn if :console is set on Elixir v1.19
2121
default_handler =
2222
if console = Application.get_env(:logger, :console) do
2323
{handler, formatter} = Keyword.split(console, [:level])
@@ -61,6 +61,7 @@ defmodule Logger.App do
6161

6262
@doc false
6363
def stop(revert) do
64+
# TODO: Remove this line and all of Logger.Backends.* on Elixir v2.0+
6465
_ = :logger.remove_handler(Logger)
6566
_ = :logger.remove_primary_filter(:logger_process_level)
6667
_ = :logger.remove_primary_filter(:logger_translator)

lib/logger/lib/logger/backends/console.ex

Lines changed: 10 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,59 +2,19 @@ defmodule Logger.Backends.Console do
22
@moduledoc ~S"""
33
A logger backend that logs messages by printing them to the console.
44
5-
## Options
5+
This backend was typically configured as `config :logger, :console`,
6+
but it has been deprecated in favor of `:default_handler` and
7+
`:default_formatter`. However, for backwards compatibility, you can
8+
still add it as:
69
7-
* `:level` - the level to be logged by this backend.
8-
Note that messages are filtered by the general
9-
`:level` configuration for the `:logger` application first.
10-
11-
* `:format` - the format message used to print logs.
12-
Defaults to: `"\n$time $metadata[$level] $message\n"`.
13-
It may also be a `{module, function}` tuple that is invoked
14-
with the log level, the message, the current timestamp and
15-
the metadata and must return `t:IO.chardata/0`. See
16-
`Logger.Formatter`.
17-
18-
* `:metadata` - the metadata to be printed by `$metadata`.
19-
Defaults to an empty list (no metadata).
20-
Setting `:metadata` to `:all` prints all metadata. See
21-
the "Metadata" section in the `Logger` documentation for
22-
more information.
23-
24-
* `:colors` - a keyword list of coloring options.
25-
26-
* `:device` - the device to log error messages to. Defaults to
27-
`:user` but can be changed to something else such as `:standard_error`.
28-
29-
* `:max_buffer` - maximum events to buffer while waiting
30-
for a confirmation from the IO device (default: 32).
31-
Once the buffer is full, the backend will block until
32-
a confirmation is received.
33-
34-
The supported keys in the `:colors` keyword list are:
35-
36-
* `:enabled` - boolean value that allows for switching the
37-
coloring on and off. Defaults to: `IO.ANSI.enabled?/0`
38-
39-
* `:debug` - color for debug messages. Defaults to: `:cyan`
40-
41-
* `:info` - color for info and notice messages. Defaults to: `:normal`
42-
43-
* `:warning` - color for warning messages. Defaults to: `:yellow`
44-
45-
* `:error` - color for error and higher messages. Defaults to: `:red`
46-
47-
See the `IO.ANSI` module for a list of colors and attributes.
48-
49-
Here is an example of how to configure this backend in a
50-
`config/config.exs` file:
51-
52-
config :logger, Logger.Backends.Console,
53-
format: "\n$time $metadata[$level] $message\n",
54-
metadata: [:user_id]
10+
config :logger, :backends, [Logger.Backends.Console]
5511
12+
However, if you plan to continue using Logger backends in the long
13+
term, consider using the [`:logger_backends`](https://github.com/elixir-lang/logger_backends)
14+
project.
5615
"""
5716

17+
@moduledoc deprecated: "Use LoggerBackends.Console from :logger_backends dependency"
5818
@behaviour :gen_event
5919

6020
defstruct buffer: [],
@@ -68,6 +28,7 @@ defmodule Logger.Backends.Console do
6828
output: nil,
6929
ref: nil
7030

31+
# TODO: Deprecate me on Elixir v1.19
7132
@impl true
7233
def init(atom) when is_atom(atom) do
7334
config = read_env()

lib/logger/lib/logger/backends/internal.ex

Lines changed: 3 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -1,176 +1,7 @@
11
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
1713

1724
use Supervisor
173-
1745
@name __MODULE__
1756
@type backend :: :gen_event.handler()
1767

@@ -179,10 +10,11 @@ defmodule Logger.Backends.Internal do
17910
18011
See the module doc for more information.
18112
"""
13+
@backend_options [:sync_threshold, :discard_threshold, :truncate, :utc_log]
18214
@spec configure(keyword) :: :ok
18315
def configure(options) do
18416
ensure_started()
185-
Logger.Backends.Config.configure(options)
17+
Logger.Backends.Config.configure(Keyword.take(options, @backend_options))
18618
:ok = :logger.update_handler_config(Logger, :config, :refresh)
18719
end
18820

lib/logger/lib/logger/backends/watcher.ex

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,14 @@
11
defmodule Logger.Backends.Watcher do
22
@moduledoc false
3-
43
require Logger
54
use GenServer
65

7-
@doc """
8-
Starts a watcher server.
9-
10-
This is useful when there is a need to start a handler
11-
outside of the handler supervision tree.
12-
"""
6+
@doc false
137
def start_link(tuple) do
148
GenServer.start_link(__MODULE__, tuple)
159
end
1610

17-
## Callbacks
18-
19-
@doc false
11+
@impl true
2012
def init({handler, args}) do
2113
Process.flag(:trap_exit, true)
2214

@@ -45,7 +37,7 @@ defmodule Logger.Backends.Watcher do
4537
end
4638
end
4739

48-
@doc false
40+
@impl true
4941
def handle_info({:gen_event_EXIT, handler, reason}, handler)
5042
when reason in [:normal, :shutdown] do
5143
{:stop, reason, handler}
@@ -80,6 +72,7 @@ defmodule Logger.Backends.Watcher do
8072
end
8173
end
8274

75+
@impl true
8376
def terminate(_reason, handler) do
8477
# On terminate we remove the handler, this makes the
8578
# process sync, allowing existing messages to be flushed

0 commit comments

Comments
 (0)