Faster, atomic string printer.

* Fixes rare issue with print interleaving.

Signed-off-by: Peter Taoussanis <p.taoussanis@gmail.com>
This commit is contained in:
Peter Taoussanis 2012-06-15 18:06:18 +07:00
parent c011e74e23
commit 6517db3a83

View File

@ -15,6 +15,12 @@
(str timestamp " " (-> level name str/upper-case) (str timestamp " " (-> level name str/upper-case)
" [" ns "] - " message)) " [" ns "] - " message))
(defn str-println
"Like 'println' but prints all objects to output stream as a single
atomic string. This is faster and avoids interleaving race conditions."
[& xs]
(print (str (str/join \space xs) \newline)))
(def config (def config
"This map atom controls everything about the way Timbre operates. In "This map atom controls everything about the way Timbre operates. In
particular note the flexibility to add arbitrary appenders. particular note the flexibility to add arbitrary appenders.
@ -34,7 +40,7 @@
:min-level nil :enabled? false :async? false :min-level nil :enabled? false :async? false
:max-message-per-msecs nil :max-message-per-msecs nil
:fn (fn [{:keys [more] :as args}] :fn (fn [{:keys [more] :as args}]
(apply println (prefixed-message args) more))} (apply str-println (prefixed-message args) more))}
:standard-out-or-err :standard-out-or-err
{:doc "Prints to *out* or *err* as appropriate. Enabled by default." {:doc "Prints to *out* or *err* as appropriate. Enabled by default."
@ -42,7 +48,7 @@
:max-message-per-msecs nil :max-message-per-msecs nil
:fn (fn [{:keys [error? more] :as args}] :fn (fn [{:keys [error? more] :as args}]
(binding [*out* (if error? *err* *out*)] (binding [*out* (if error? *err* *out*)]
(apply println (prefixed-message args) more)))} (apply str-println (prefixed-message args) more)))}
:postal :postal
{:doc (str "Sends an email using com.draines/postal.\n" {:doc (str "Sends an email using com.draines/postal.\n"
@ -95,7 +101,7 @@
(defn- wrap-appender-fn (defn- wrap-appender-fn
"Wraps compile-time appender fn with additional capabilities controlled by "Wraps compile-time appender fn with additional capabilities controlled by
compile-time config." compile-time config."
[appender-id {apfn :fn :keys [async? max-message-per-msecs] :as appender}] [{apfn :fn :keys [async? max-message-per-msecs] :as appender}]
(-> (->
;; Wrap to add compile-time stuff to runtime appender arguments ;; Wrap to add compile-time stuff to runtime appender arguments
(let [{:keys [timestamp-pattern locale] :as ap-config} (let [{:keys [timestamp-pattern locale] :as ap-config}
@ -172,8 +178,7 @@
;; Return nil if no relevant appenders ;; Return nil if no relevant appenders
(when-let [ap-ids (keys rel-aps)] (when-let [ap-ids (keys rel-aps)]
(->> ap-ids (->> ap-ids
(map (fn [n] (wrap-appender-fn (map #(wrap-appender-fn (rel-aps %)))
n (rel-aps n))))
(apply juxt)))))))) (apply juxt))))))))
(reset! juxt-cache))) (reset! juxt-cache)))
@ -250,7 +255,7 @@
(comment (comment
(info "foo" "bar") (info "foo" "bar")
(trace (Thread/sleep 5000)) (trace (Thread/sleep 5000))
(time (dotimes [n 10000] (trace "This won't log"))) ; Minimum overhead +/- 17ms (time (dotimes [n 10000] (trace "This won't log"))) ; Minimum overhead +/- 4.5ms
(time (dotimes [n 5] (info "foo" "bar"))) (time (dotimes [n 5] (info "foo" "bar")))
(spy (* 6 5 4 3 2 1)) (spy (* 6 5 4 3 2 1))
(info (Exception. "noes!") "bar") (info (Exception. "noes!") "bar")