viesti / timbre-json-appender

JSON appender for Timbre
MIT License
44 stars 11 forks source link

com.fasterxml.jackson.databind.JsonMappingException / java.lang.UnsupportedOperationException when logging certain objects #38

Open vemv opened 3 months ago

vemv commented 3 months ago

After starting to use the :json-error-fn, I found about the following happening when logging http-related stuff:

[{:type com.fasterxml.jackson.databind.JsonMappingException
 :message "(was java.lang.UnsupportedOperationException) (through reference chain: clojure.lang.PersistentHashMap[\":response\"]->clojure.lang.PersistentHashMap[\":http-client\"]->org.apache.http.impl.client.InternalHttpClient[\"params\"])"
:at [com.fasterxml.jackson.databind.JsonMappingException wrapWithPath "JsonMappingException.java" 402]}
{:type java.lang.UnsupportedOperationException
:message nil
:at [org.apache.http.impl.client.InternalHttpClient getParams "InternalHttpClient.java" 211]}]
:trace
[[org.apache.http.impl.client.InternalHttpClient getParams "InternalHttpClient.java" 211]
[jdk.internal.reflect.DirectMethodHandleAccessor invoke nil -1]
[java.lang.reflect.Method invoke nil -1]
[com.fasterxml.jackson.databind.ser.BeanPropertyWriter serializeAsField "BeanPropertyWriter.java" 688]
[com.fasterxml.jackson.databind.ser.std.BeanSerializerBase serializeFields "BeanSerializerBase.java" 770]
[com.fasterxml.jackson.databind.ser.BeanSerializer serialize "BeanSerializer.java" 183]
[com.fasterxml.jackson.databind.ser.std.MapSerializer serializeFields "MapSerializer.java" 808]
[com.fasterxml.jackson.databind.ser.std.MapSerializer serializeWithoutTypeInfo "MapSerializer.java" 764]
[com.fasterxml.jackson.databind.ser.std.MapSerializer serialize "MapSerializer.java" 720]
[com.fasterxml.jackson.databind.ser.std.MapSerializer serialize "MapSerializer.java" 35]
[com.fasterxml.jackson.databind.ser.std.MapSerializer serializeFields "MapSerializer.java" 808]
[com.fasterxml.jackson.databind.ser.std.MapSerializer serializeWithoutTypeInfo "MapSerializer.java" 764]
[com.fasterxml.jackson.databind.ser.std.MapSerializer serialize "MapSerializer.java" 720]
[com.fasterxml.jackson.databind.ser.std.MapSerializer serialize "MapSerializer.java" 35]
[com.fasterxml.jackson.databind.ser.DefaultSerializerProvider _serialize "DefaultSerializerProvider.java" 502]
[com.fasterxml.jackson.databind.ser.DefaultSerializerProvider serializeValue "DefaultSerializerProvider.java" 341]
[com.fasterxml.jackson.databind.ObjectMapper _writeValueAndClose "ObjectMapper.java" 4793]
[com.fasterxml.jackson.databind.ObjectMapper writeValueAsString "ObjectMapper.java" 4038]
[jsonista.core$write_value_as_string invokeStatic "core.clj" 249]
[timbre_json_appender.core$make_json_output_fn$fn__44143 invoke "core.clj" 179]
[taoensso.timbre$protected_fn$fn__17814 invoke "timbre.cljc" 612]
[taoensso.timbre$_log_BANG_$fn__17845$fn__17847 invoke "timbre.cljc" 745]
[clojure.lang.Delay deref "Delay.java" 42]
[clojure.lang.Delay force "Delay.java" 28]
[clojure.core$force invokeStatic "core.clj" 767]
[timbre_json_appender.core$json_appender$fn__44155 invoke "core.clj" 199]
[taoensso.timbre$_log_BANG_$fn__17845 invoke "timbre.cljc" 777]
[clojure.lang.PersistentArrayMap kvreduce "PersistentArrayMap.java" 429]
[clojure.core$fn__8525 invokeStatic "core.clj" 6909]
[clojure.core$fn__8525 invoke "core.clj" 6889]
[clojure.core.protocols$fn__8257$G__8252__8266 invoke "protocols.clj" 175]
[clojure.core$reduce_kv invokeStatic "core.clj" 6920]
[taoensso.timbre$_log_BANG_ invokeStatic "timbre.cljc" 779]

My guess is that jsonista knows how to encode PersistentHashMaps (ref), but not how to encode InternalHttpClients.

Thoughts? It would not be reasonable for timbre-json-appender/jsonista to know about every class imaginable.

I don't immediately know if jsonista has a recipe for this. Worst-case scenario one could experiment with clojure.data.json, which I hear got a lot faster in recent times.

Thanks - V

vemv commented 3 months ago

I reckon that a workaround would be to dissoc the org.apache.http.impl.client.InternalHttpClient which is deep inside the Timbre context I was logging and very much irrelevant.

viesti commented 3 months ago

Aaah, we should do a similar thing for the context map as we do to the ExceptionInfo data map, see process-ex-data-map and the docstring of default-ex-data-field-fn. clj-http puts the client class into the ExceptionInfo data map, so when a HTTP request fails, we a non-serialiable object in the data map.

Should though recursively walk through the context and the ExceptionInfo data map, probably.

vemv commented 3 months ago

Good to hear!

Just in case, I applied the described workaround so I'd be fine with any outcome for this issue.