The `config_change` callback is called from `application_controller` process,
which is receiving env updates on releases. `Logger.configure` does a blocking
call to the `Logger` process, which calls `Application.put_env`
This causes a crash on logger config update.
The fix is to call `Logger.configure` only for the config that have not yet
been persisted.
When the logger report was in form of `%{label: term(), report: term()}`
the `report_cb` wasn't called and instead there was fall-back to the
"regular" formatter which could cause meaningless messages. This fixes
that by falling back to the "proper" `report_cb` in case when there was
no matching handler.
Earlier it assumed that the return type is the same as in `report_cb/1`
which is not true. `report_cb/1` returns format string and data while
`report_cb/2` returns already formatted string.
Previous logger versions would always compute the mode on the Logger
handler which meant that, if any other Logger handler blocked, either because
it was waiting on IO, the system is overloaded or due to long computations, a
burst of messages could make the Logger message queue grow quite large
until it notices it should change its mode.
This commit changes the computation to use a counter which is offset by
the current message length queue. This makes the following script go from
tens of thousands messages in the Logger inbox to only hundreds (assuming
a `sync_threshold` of 100) when writing a rate limited stdio with
`mix run foo.exs | pv -p -L 1k 1>/dev/null`:
```elixir
require Logger
# monitor memory
# :observer.start()
defmodule Loop do
def run() do
Logger.info(inspect(:crypto.strong_rand_bytes(1024)))
Process.sleep(10)
run()
end
end
for _i <- 1..100 do
spawn(fn ->
Loop.run()
end)
end
defmodule OtherLoop do
def run() do
IO.inspect(:stderr, Process.info(Process.whereis(Logger), :message_queue_len), [])
IO.inspect(:stderr, :ets.tab2list(Logger.Config), [])
Process.sleep(100)
run()
end
end
OtherLoop.run()
```
Otherwise it is impossible to dynamically remove them,
which partially defeats the point of adding them dynamically
in the first place.
Therefore this commit moves the whole dynamic backend
management to the user.
Closes#8213