diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e6dc54..7fee3ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,11 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Update dependencies to latest versions, including `pretty` dependency which has moved to `clj-commons` with some breaking changes. [#39](https://github.com/amperity/dialog/pull/39) (credit @sundbp) +- The `:json` formatter now handles objects that aren't JSON serializable + by calling `clojure.core/str` on them and writing the resulting string. + Previously, these values would cause the event to be dropped with a warning similar to + `[dialog output error] Failed to write to output stdout: Don't know how to write JSON of class `. + [#41](https://github.com/amperity/dialog/pull/41) ## [2.0.115] - 2023-03-24 diff --git a/deps.edn b/deps.edn index 3041537..634880e 100644 --- a/deps.edn +++ b/deps.edn @@ -43,7 +43,8 @@ :test {:extra-paths ["test"] - :extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}} + :extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"} + clj-time/clj-time {:mvn/version "0.15.2"}} :jvm-opts ["-XX:-OmitStackTraceInFastThrow" "-Duser.language=en" "-Duser.country=US"] @@ -51,7 +52,8 @@ :coverage {:extra-paths ["test"] - :extra-deps {cloverage/cloverage {:mvn/version "RELEASE"}} + :extra-deps {cloverage/cloverage {:mvn/version "RELEASE"} + clj-time/clj-time {:mvn/version "0.15.2"}} :jvm-opts ["-Duser.language=en" "-Duser.country=US"] :main-opts ["-m" "cloverage.coverage" diff --git a/src/clojure/dialog/format/json.clj b/src/clojure/dialog/format/json.clj index a39dede..ee97443 100644 --- a/src/clojure/dialog/format/json.clj +++ b/src/clojure/dialog/format/json.clj @@ -75,6 +75,14 @@ (str v)))) +(defn- default-write-fn + "Default write handler for any types that don't implement + `clojure.data.json/JSONWriter`: just calls `str` on the value and writes the + resulting string." + [value out options] + (json/-write (str value) out options)) + + (defn formatter "Construct a JSON event formatting function." [_output] @@ -84,4 +92,5 @@ event :key-fn key-fn :value-fn value-fn + :default-write-fn default-write-fn :escape-slash false))) diff --git a/test/dialog/format/json_test.clj b/test/dialog/format/json_test.clj index 6b81824..9f0d4a7 100644 --- a/test/dialog/format/json_test.clj +++ b/test/dialog/format/json_test.clj @@ -1,5 +1,6 @@ (ns dialog.format.json-test (:require + [clj-time.core :as time] [clojure.string :as str] [clojure.test :refer [deftest testing is]] [dialog.format.json :as json]) @@ -43,4 +44,12 @@ (testing "throwables" (let [ex (RuntimeException. "BOOM") message (fmt {:error ex})] - (is (str/starts-with? message "{\"error\":[{\"class-name\":\"java.lang.RuntimeException\",")))))) + (is (str/starts-with? message "{\"error\":[{\"class-name\":\"java.lang.RuntimeException\",")))) + (testing "types that don't implement JSONWriter" + (let [date-time (time/date-time 2025 5 5) + event {:date-time date-time}] + (with-redefs [json/default-write-fn (fn [& _] (throw (Exception. "default-write-fn called")))] + (is (thrown? Exception #"^default-write-fn called$" + (fmt event)))) + (is (= "{\"date-time\":\"2025-05-05T00:00:00.000Z\"}" + (fmt {:date-time date-time})))))))