Sheharyar Naseer

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)