protocol Jason.Encoder not implemented for tuple
dvic opened this issue · comments
I'm getting the following error (the value {1, 1, 1, 1}
is dummy here)
Protocol.UndefinedError: protocol Jason.Encoder not implemented for {1, 1, 1, 1} of type Tuple, Jason.Encoder protocol must always be explicitly implemented. This protocol is implemented for the following type(s): ....
File "lib/jason.ex", line 199, in Jason.encode_to_iodata!/2
File "lib/logger_json.ex", line 290, in LoggerJSON.format_event/5
File "lib/logger_json.ex", line 225, in LoggerJSON.log_event/5
File "lib/logger_json.ex", line 127, in LoggerJSON.handle_event/2
File "gen_event.erl", line 620, in :gen_event.server_update/4
File "gen_event.erl", line 602, in :gen_event.server_notify/4
File "gen_event.erl", line 343, in :gen_event.handle_msg/6
File "proc_lib.erl", line 226, in :proc_lib.init_p_do_apply/3
It seems like the event that the formatter (GoogleCloudLogger
in my case) cannot be encoded to JSON. I have no idea where this tuple is coming from (looks like an ip address). The GoogleCloudLogger
should never crash right? The only thing I can think of is that one of the @processed_metadata_keys
(pid, file, line, function, module or application) contains this tuple as value, because these are not "safe" converted but taken as-is. Do you have any idea on how I can debug this?
@dvic which version of LoggerJSON is used? In one of recent changes we have added SafeEncoder which inspects everything Jason does not support
Version 4.1 (76037738cd0b71bfb6230c8e3dc505c4f5789bb47e7a2e3d4a0421c6778d48e4
), so it should include the SafeEncoder.
I should add that I'm using :all
and also Sentry (which is probably the one adding the IP).
The problem could then be in take_metadata:
def take_metadata(metadata, :all, ignored_keys) do
metadata
|> Keyword.drop(ignored_keys ++ @ignored_metadata_keys)
|> Enum.into(%{})
end
which is called in
defp format_metadata(md, md_keys) do
LoggerJSON.take_metadata(md, md_keys, @processed_metadata_keys)
|> JasonSafeFormatter.format()
|> FormatterUtils.maybe_put(:error, FormatterUtils.format_process_crash(md))
|> FormatterUtils.maybe_put(:"logging.googleapis.com/sourceLocation", format_source_location(md))
|> FormatterUtils.maybe_put(:"logging.googleapis.com/operation", format_operation(md))
end
Shouldn't the take_metadata
function also apply SafeEncoder?
never mind, I missed the JasonSafeFormatter.format()
call above
@dvic I think then we need to find a place where JasonSafeFormatter fails to encode that tuple. If you can submit a PR with a failing test case I can jump on it and fix it ASAP.
I'll try to see if I can replicate it in an test.
I'm not sure that PR fixes my example (which was plain {1, 1, 1, 1}
) but I'll try to see if I can create a test case.
@dvic I had the exact same error in Sentry, just a plain tuple. Jason only complains about the innermost value that it cannot encode:
iex(3)> Jason.encode!([{1, 2}, 3])
** (Protocol.UndefinedError) protocol Jason.Encoder not implemented for {1, 2} of type Tuple, Jason.Encoder protocol must always be explicitly implemented. This protocol is implemented for the following type(s): ...
(jason 1.2.2) lib/jason.ex:150: Jason.encode!/2
The only place that didn't call the format function recursively on each value was the function clause for formatting tuples.
Found another place: #75
@woylie wow, I see! Will try the master version