prop/test/microwaveprop/logger_format_test.exs
2026-06-12 16:14:14 -05:00

58 lines
2 KiB
Elixir

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
end
end