Skip to content

Ugly errors are raised when logging non-loggable stuff #7474

@whatyouhide

Description

@whatyouhide

I was going down the rabbit hole of Logger formatters, and I found a few interesting behaviours.

Let's start by logging something that doesn't look like a binary or a charlist. If we do this, we get a nice (and expected) Protocol.UndefinedError for String.Chars:

iex> Logger.info(%{})
** (Protocol.UndefinedError) protocol String.Chars not implemented for %{}

This is good™. Now, what actually calls to_string/1 is Logger.truncate/2. However, truncate/2 treats binaries and what look like charlists in a special way:

defp truncate(data, n) when is_list(data) or is_binary(data), do: Logger.Utils.truncate(data, n)
defp truncate(data, n), do: Logger.Utils.truncate(to_string(data), n)

The problem is that is_list/1 definitely doesn't tell if something is a charlist all the way down. Hence, it's easy to make Logger raise a (IMO) nasty FunctionClauseError:

iex> Logger.info([%{}])
** (FunctionClauseError) no function clause matching in Logger.Utils.truncate_n/2

Things get even worse when I trick Logger into bypassing truncate/2 altogether, that is, by configuring :truncate to be :infinity. In this case, if I pass a list, Logger still mistakes it for chardata and either gives it to a formatter (like the default one in the console backend) that crashes on it:

iex> Logger.configure(truncate: :infinity)
iex> Logger.info([%{}])
02:06:14.509 [error] GenEvent handler Logger.Backends.Console installed in Logger terminating
** (ArgumentError) argument error
    (stdlib) :unicode.characters_to_binary([[[] | "\e[22m"], ["\n", [[48, "2"], 58, [48, "6"], 58, "14", 46, "502"], " ", "", "[", "info", "] ", " ", [%{}], "\n"] | "\e[0m"])

or passes it down to custom formatters (like {module, function}) which will receive a message that they cannot turn to chardata straight away.

This is somehow of a problem with metadata as well, as they're only tried to be turned into a string by each specific formatter. However, with metadata I guess that this is good because smarted backends or formatters can use non-string-friendly metadata for their own specialized purposes. However, it feels like we should ensure formatters and backends that the message they will get is a binary or chardata. Thoughts?

Also, sorry for the brain dump as the issue report instead of a more formal issue, it's late and I'm headed to sleep and wanted to get this right and detailed before I forget to :) I'll clean it up tomorrow if necessary!

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions