-
Notifications
You must be signed in to change notification settings - Fork 108
Description
Bug Description
LoggerJSON.Formatters.Datadog crashes with a BadMapError when a Logger.error call includes error: as a metadata key with a non-map value (e.g., a string or tuple).
Affected Version
v7.0.3 (and likely all 7.x)
Root Cause
In lib/logger_json/formatters/datadog.ex lines 266-270, format_error/4 does:
defp format_error(%{message: message}, metadata, level, reported_levels) when is_binary(message) do
if level in reported_levels do
error =
metadata[:error]
|> Kernel.||(%{})
|> Map.put(:kind, get_error_kind(metadata))
|> Map.put(:message, message)
|> maybe_put(:stack, get_error_stack(metadata))
%{error: error}
end
endThe Kernel.||(%{}) fallback only triggers when metadata[:error] is nil or false. If a user passes any truthy non-map value (string, tuple, atom, etc.), the || does not fall through, and Map.put is called on a non-map — crashing with:
** (BadMapError) expected a map, got: "some error message"
This produces FORMATTER CRASH entries in production logs, silently swallowing the actual error log output.
How to Reproduce
Logger.error("Something failed", error: "connection refused")
Logger.error("Something failed", error: {:timeout, "request timed out"})Any Logger.error (or :critical/:alert/:emergency) call with a non-map error: metadata key triggers the crash.
Note: error: is a very natural metadata key name for logging, so users are likely to hit this without realizing the Datadog formatter reserves it for structured error tracking.
Suggested Fix
Add a guard or pattern match to ensure metadata[:error] is a map before merging into it:
defp format_error(%{message: message}, metadata, level, reported_levels) when is_binary(message) do
if level in reported_levels do
base =
case metadata[:error] do
%{} = map -> map
_other -> %{}
end
error =
base
|> Map.put(:kind, get_error_kind(metadata))
|> Map.put(:message, message)
|> maybe_put(:stack, get_error_stack(metadata))
%{error: error}
end
endThe same defensive check should be applied to get_error_kind/1 and get_error_stack/1 — though those already pattern-match on maps so they are safe today.
Workaround
Avoid using error: as a top-level Logger metadata key, or ensure it is always a map conforming to Datadog's error tracking format (%{kind: ..., message: ..., stack: ...}). We renamed all our error: metadata keys to error_details: as a workaround.