Can you use ex_unit to assert that a log statement was emitted with specific metadata?

Hi, Jason :wave: !

In one project I format logs in json and include metadata there in the message, so it’s pretty straight forward… (Jason.decode the captured log and assert on internals).

However, I guess that’s not your case, so I think we could add :logger handler and try to assert on the metadata within log_event.
Since handlers run in the same process as the one that emits the log we could send the log_event to self() and receive in test roughly something like this:

defmodule LoggerTestHelper do
  def log(log_event, config) do
    send(config.test_pid, {:logged_event, log_event})
  end
end

defmodule Test do
  use ExUnit.Case, async: true
  require Logger

  setup do
    :logger.add_handler(:test_handler, LoggerTestHelper, %{test_pid: self()})
    on_exit(fn -> :logger.remove_handler(:test_handler) end)
  end

  test "metadata" do
    Logger.info("hello", foo: :bar)

    assert_receive {:logged_event, %{meta: meta} = _log_event}
    assert meta.foo == :bar
  end
end

UPD: I just realized, that event might be logged by a process other than the test itself, and sending log_event to self() is quite limiting… Hence, I updated the example passing test_pid to logger handler config and having it to send log_event to test_pid explicitly.

3 Likes