Disable Console Logs temporarily in Elixir
Sometimes you want to disable the Elixir logger temporarily, usually when you want to suppress some
annoying logs printed to the console when calling a certain function. And more often than not, it’s
when you’re running your 200+ test suite and don’t want anything to interrupt that beautiful green
line. Well, ExUnit.LogCapture
already does that for you. But what if you want
something similar outside your tests, in your regular application?
Sure, you could just change your Logger
config to set a different logging level but
that will affect your entire application, and won’t just suppress the logs for a specific call. This
was the case for me when I got really annoyed by the logger messages when stopping :mnesia
, and
just wanted to disable them for this specific function call.
iex(1)> :mnesia.stop
02:49:03.069 [info] Application mnesia exited: :stopped
I was looking for something like ExUnit.CaptureLog
that could suppress the log
for only the given function call. For context, this is how it works:
test "something being logged" do
logs = ExUnit.CaptureLog.capture_log(fn ->
Logger.info("Hello!")
end)
# Assert something with `logs`
end
After looking a bit into Logger
, I found add_backend/1
& remove_backend/1
, and learned that
:console
is the “Logger Backend” responsible for printing to the console. So, quickly came up
with a simple helper that can do what I want:
defmodule LogSuppressor do
def suppress(fun) do
Logger.remove_backend(:console)
fun.()
Logger.add_backend(:console)
end
end
It disables logging to the console, calls the function and then enables it back again. But wait,
there are a few problems with this. For starters, it doesn’t return back the result of the function.
Secondly, it doesn’t check if the console backend was initially enabled, and might enable it in
certain environments where we previously disabled it (:prod
for example). There’s one more
problem, this might cause race conditions for certain logs, but that’s not that big of a problem
in development, and productions logs are usually written to a file anyways.
After a few changes, this is how it looks:
defmodule LogSuppressor do
def suppress(fun) do
backend = Logger.remove_backend(:console)
result = fun.()
case backend do
:ok -> Logger.add_backend(:console)
{:error, _} -> nil
end
result
end
end
Now I can finally stop mnesia
without getting that stupid message.
LogSuppressor.suppress(fn ->
Application.stop(:mnesia)
end)