defmodule Microwaveprop.LoggerFormatTest do # async: false — we briefly swap the global :default :logger handler's # formatter and forward its output to a self()-bound IO device so the # test can capture the JSON-encoded output. Restored on exit. # # Opts out of the suite-wide capture_log flag — capture_log hot-swaps # the :default handler for its own capture handler, so our direct # :logger.get_handler_config(:default) lookup in setup would 404. use ExUnit.Case, async: false alias LoggerJSON.Formatters.Basic require Logger @moduletag capture_log: false describe "structured JSON formatter" do setup do {:ok, handler_cfg} = :logger.get_handler_config(:default) prev_formatter = handler_cfg.formatter new_formatter = Basic.new(metadata: [:request_id, :trace_id, :worker, :queue, :job_id]) :ok = :logger.update_handler_config(:default, :formatter, new_formatter) on_exit(fn -> :logger.update_handler_config(:default, :formatter, prev_formatter) end) {:ok, formatter: new_formatter} end test "Basic formatter encodes an info log as a valid JSON object", %{formatter: {formatter_mod, formatter_cfg}} do # Build a `:logger` log event the same shape the handler feeds the # formatter, then assert the formatter's output is valid JSON with # the expected message and metadata fields. log_event = %{ level: :info, msg: {:string, "hello-json"}, meta: %{ time: :os.system_time(:microsecond), request_id: "abc-123", worker: "TestWorker" } } rendered = formatter_mod.format(log_event, formatter_cfg) payload = rendered |> IO.iodata_to_binary() |> String.trim_trailing("\n") assert {:ok, decoded} = Jason.decode(payload) assert decoded["message"] == "hello-json" assert get_in(decoded, ["metadata", "request_id"]) == "abc-123" assert get_in(decoded, ["metadata", "worker"]) == "TestWorker" end test "swapping the :default handler formatter takes effect" do # Smoke test that the setup actually attached our JSON formatter # to the :default handler (i.e. the runtime.exs swap would land). {:ok, cfg} = :logger.get_handler_config(:default) assert match?({Basic, _}, cfg.formatter) end end end