-
-
Notifications
You must be signed in to change notification settings - Fork 173
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Thread safety on println-appender #188
Comments
I created a quick and dirty fix using (defn println-appender
"Returns a simple `println` appender for Clojure/Script.
Use with ClojureScript requires that `cljs.core/*print-fn*` be set.
:stream (clj only) - e/o #{:auto :*out* :*err* :std-err :std-out <io-stream>}."
;; Unfortunately no easy way to check if *print-fn* is set. Metadata on the
;; default throwing fn would be nice...
[& [{:keys [stream] :or {stream :auto}}]]
(let [stream (case stream
:std-err timbre/default-err
:std-out timbre/default-out
stream)
locker (Object.)]
{:enabled? true
:async? false
:min-level nil
:rate-limit nil
:output-fn :inherit
:fn
(fn [data]
(let [{:keys [output_]} data]
(let [stream (case stream
:auto (if (:error? data) *err* *out*)
:*out* *out*
:*err* *err*
stream)]
(locking locker (binding [*out* stream] (println (force output_)))))))})) |
Hi there, Could you be a little more precise about what you mean here by "thread safe"? What kind of interleaving are you seeing? Under what circumstances? Can you provide an example? Thanks! |
Writing to Consider these examples. You might have to run the code a few times or try higher NUM_ITERS or NUM_THREADS to see the effect. (ns test.core
(:require
[taoensso.timbre :as timbre]))
(def NUM-ITERS 5)
(def NUM-THREADS 4)
(defn worker
[]
(doseq [i (range NUM-ITERS)]
(timbre/info (.getName (Thread/currentThread)) " " i)))
(defn print-stuff
[num-threads]
(doseq [i (range num-threads)]
(.start (Thread. worker (str "thread-" i)))))
(defn thread-safe-println-appender
[& [{:keys [stream] :or {stream :auto}}]]
(let [stream (case stream
:std-err timbre/default-err
:std-out timbre/default-out
stream)
locker (Object.)]
{:enabled? true
:async? false
:min-level nil
:rate-limit nil
:output-fn :inherit
:fn
(fn [data]
(let [{:keys [output_]} data]
(let [stream (case stream
:auto (if (:error? data) *err* *out*)
:*out* *out*
:*err* *err*
stream)]
(locking locker (binding [*out* stream]
(println (force output_)))))))}))
(defn set-println-appender [appender]
(let [config timbre/example-config]
(timbre/set-config! (assoc config :appenders
{:println (appender {:stream :auto})}))))
(defn test-appender
[appender]
(set-println-appender appender)
(println "testing " appender)
(print-stuff NUM-THREADS)
(Thread/sleep 1000))
(defn -main
[]
(test-appender taoensso.timbre.appenders.core/println-appender)
(test-appender thread-safe-println-appender)) output:
|
Thanks for the example, this was an unintended regression- fixed! |
Thanks! I had been observing the same. Is 4.7.4 coming out soon? |
Just cut a release. |
Thank you! :) |
This interleaving occurs on cljs, also. However, the 4.7.4 release only fixes it for clj. Any chance of a fix for cljs? I am seeing interleaving with 4.7.4 running on node. Thank you for your great work. |
Hi Chad, It's not immediately obvious to me how interleaving would be happening in a single-threaded Cljs environment - any chance you could provide an example or any more details? Thanks!
You're very welcome, cheers! :-) |
We are using many go blocks. The interleaving happens when we log large messages (stacktraces, mostly). We are seeing this in a large system, so it will take some time to create a minimal test case. I hope to do that this weekend. |
Hi there, Go blocks don't involve threading though, so the behaviour still surprises me. No need for a minimal test case - but could you possibly provide an example of your faulty (interleaved) output? Would like to understand better what's actually happening before choosing a solution. Thanks! Cheers :-) |
Oh, PS- you're welcome to send the example to my email address if you don't want to have to bother sanitising it for GitHub. My address is at www.taoensso.com. |
It seems that there are no guarantees that
println
commands are thread safe (no interleaved lines) onprintln-appender
. Is there some configuration switch that will assure thread safety or do I need to write a custom appender?The text was updated successfully, but these errors were encountered: