From 597c7a0617d0d7ffe614c3d3532e1de3ef1a11f8 Mon Sep 17 00:00:00 2001 From: Peter Taoussanis Date: Thu, 20 Oct 2022 17:23:42 +0200 Subject: [PATCH] [mod] [#356] Call `pr-str` on non-string arguments Change (both Clj and Cljs): For print-style logging commands (`debug`, `info`, etc.): By default, `pr-str` (rather than `str`) is now called on all non-string arguments when generating `:msg_` and `:output_` vals in Timbre's log data map. I.e. will affect generated output. For format-style logging commands (`debugf`, `infof`, etc.): No change since format-style logging commands presume that a format pattern will explicitly specify the desired formatting, so arguments are not automatically formatted. I.e. should not affect generated output. Motivation: My hope is that this change should be positive or neutral for the vast majority of users. There are several known cases where `pr-str` produces better output (e.g. for JS objects in Cljs), and currently no known cases where `pr-str` produces worse output (though please ping me if you know of something!). To customise this behaviour (message generation), see the `default-output-fn` docstring. --- src/taoensso/timbre.cljc | 68 ++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/src/taoensso/timbre.cljc b/src/taoensso/timbre.cljc index 872470e7..28c0d2df 100644 --- a/src/taoensso/timbre.cljc +++ b/src/taoensso/timbre.cljc @@ -565,21 +565,6 @@ ;;;; Utils -(defn- str-join [xs] - (enc/str-join " " - (map - (fn [x] - (let [x (enc/nil->str x)] ; Undefined, nil -> "nil" - (cond - (record? x) (pr-str x) - ;; (enc/lazy-seq? x) (pr-str x) ; Dubious? - :else x)))) - xs)) - -(comment - (defrecord MyRec [x]) - (str-join ["foo" (MyRec. "foo")])) - #?(:clj (enc/defonce ^:private get-agent (enc/fmemoize (fn [appender-id] (agent nil :error-mode :continue))))) @@ -1101,21 +1086,50 @@ (str enc/system-newline (ef data))))))))) +(defn- default-arg->str-fn [x] + (enc/cond + (nil? x) "nil" + (string? x) x + :else + #?(:clj (with-out-str (pr x)) + :cljs (pr-str x)))) + +(defn- legacy-arg->str-fn [x] + (enc/cond + (nil? x) "nil" + (record? x) (pr-str x) + :else x)) + +(defn- str-join + ([ xs] (str-join default-arg->str-fn xs)) + ([arg->str-fn xs] (enc/str-join " " (map arg->str-fn) xs))) + +(comment + (defrecord MyRec [x]) + (str-join ["foo" (MyRec. "foo")])) + (defn default-output-msg-fn "(fn [data]) -> string, used by `default-output-fn` to generate output for `:vargs` value (vector of raw logging arguments) in log data." - [{:keys [msg-type ?msg-fmt vargs] :as data}] - (case msg-type - nil "" - :p (str-join vargs) - :f - (if (string? ?msg-fmt) - (enc/format* ?msg-fmt vargs) - (throw - (ex-info "Timbre format-style logging call without a format pattern string" - {:?msg-fmt ?msg-fmt :type (type ?msg-fmt) :vargs vargs}))))) - -(comment (default-output-msg-fn {:msg-type :p :vargs ["a" "b"]})) + [{:keys [msg-type ?msg-fmt vargs output-opts] :as data}] + (let [{:keys [arg->str-fn] ; Undocumented + :or {arg->str-fn default-arg->str-fn}} + output-opts] + + (case msg-type + nil "" + :p (str-join arg->str-fn vargs) + :f + (if (string? ?msg-fmt) + (enc/format* ?msg-fmt vargs) ; Don't use arg->str-fn, would prevent custom formatting + (throw + (ex-info "Timbre format-style logging call without a format pattern string" + {:?msg-fmt ?msg-fmt :type (type ?msg-fmt) :vargs vargs})))))) + +(comment + (default-output-msg-fn + {:msg-type :p :vargs ["a" "b"] + :output-opts {:arg->str-fn (fn [_] "x")}})) #?(:clj (def ^:private default-stacktrace-fonts