mirror of https://github.com/status-im/timbre.git
[#168] Make rotor appender thread-safe (@mikesperber)
This commit is contained in:
parent
88bbff347b
commit
bd3d4b6707
|
@ -55,17 +55,20 @@
|
||||||
:rate-limit nil
|
:rate-limit nil
|
||||||
:output-fn :inherit
|
:output-fn :inherit
|
||||||
:fn
|
:fn
|
||||||
|
(let [lock (Object.)]
|
||||||
(fn [data]
|
(fn [data]
|
||||||
(let [{:keys [output-fn]} data
|
(let [{:keys [output-fn]} data
|
||||||
output-str (output-fn data)]
|
output-str (output-fn data)]
|
||||||
(when-let [log (io/file path)]
|
(let [log (io/file path)]
|
||||||
(try
|
(try
|
||||||
|
;; all the filesystem manipulations are unsafe in the face of concurrency
|
||||||
|
(locking lock
|
||||||
(when-not (.exists log)
|
(when-not (.exists log)
|
||||||
(io/make-parents log))
|
(io/make-parents log))
|
||||||
(when (> (.length log) max-size)
|
(when (> (.length log) max-size)
|
||||||
(rotate-logs path backlog))
|
(rotate-logs path backlog)))
|
||||||
(spit path (str (output-fn data) "\n") :append true)
|
(spit path (str (output-fn data) "\n") :append true)
|
||||||
(catch java.io.IOException _)))))})
|
(catch java.io.IOException _))))))})
|
||||||
|
|
||||||
;;;; Deprecated
|
;;;; Deprecated
|
||||||
|
|
||||||
|
|
|
@ -2,28 +2,100 @@
|
||||||
(:require
|
(:require
|
||||||
[clojure.test :refer :all]
|
[clojure.test :refer :all]
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
|
[clojure.set :as set]
|
||||||
[taoensso.timbre :as timbre]
|
[taoensso.timbre :as timbre]
|
||||||
[taoensso.timbre.appenders.3rd-party.rotor :as rotor]))
|
[taoensso.timbre.appenders.3rd-party.rotor :as rotor]))
|
||||||
|
|
||||||
(deftest rotor-test
|
(def logfile "rotor-test.log")
|
||||||
[]
|
|
||||||
(let [logfile "rotor-test.log"
|
(defn logname
|
||||||
n-logs 5]
|
[i]
|
||||||
|
(format "%s.%03d" logfile i))
|
||||||
|
|
||||||
|
(defn setup
|
||||||
|
[n-logs]
|
||||||
(timbre/merge-config!
|
(timbre/merge-config!
|
||||||
{:appenders {:rotor (rotor/rotor-appender
|
{:appenders {:rotor (rotor/rotor-appender
|
||||||
{:path logfile
|
{:path logfile
|
||||||
:max-size 200
|
:max-size 200
|
||||||
:backlog n-logs})}})
|
:backlog n-logs})}}))
|
||||||
(doseq [i (range 100)]
|
|
||||||
(timbre/info "testing..."))
|
|
||||||
|
|
||||||
|
(defn check-logs-present
|
||||||
|
[n-logs]
|
||||||
(let [f (io/file logfile)]
|
(let [f (io/file logfile)]
|
||||||
(is (.exists f))
|
(is (.exists f)))
|
||||||
(.delete f))
|
|
||||||
|
|
||||||
(doseq [i (range 1 (inc n-logs))]
|
(doseq [i (range 1 (inc n-logs))]
|
||||||
(let [f (io/file (str logfile ".00" i))]
|
(let [f (io/file (logname i))]
|
||||||
(is (.exists f))
|
(is (.exists f)))))
|
||||||
(.delete f)))))
|
|
||||||
|
(defn delete
|
||||||
|
[logfile]
|
||||||
|
(let [f (io/file logfile)]
|
||||||
|
(try
|
||||||
|
(.delete f)
|
||||||
|
(catch java.io.FileNotFoundException e nil))))
|
||||||
|
|
||||||
|
(defn teardown
|
||||||
|
[n-logs]
|
||||||
|
(delete logfile)
|
||||||
|
|
||||||
|
(doseq [i (range 1 (inc n-logs))]
|
||||||
|
(delete (logname i))))
|
||||||
|
|
||||||
|
(deftest rotor-test
|
||||||
|
(let [n-logs 5]
|
||||||
|
(setup n-logs)
|
||||||
|
(doseq [i (range 100)]
|
||||||
|
(timbre/info "testing..."))
|
||||||
|
(check-logs-present n-logs)
|
||||||
|
(teardown n-logs)))
|
||||||
|
|
||||||
|
(defn check-complete
|
||||||
|
[n-logs n-lines]
|
||||||
|
(is (= (set (range n-lines))
|
||||||
|
(apply set/union
|
||||||
|
(for [n (cons logfile (map logname (range 1 (inc n-logs))))]
|
||||||
|
(try
|
||||||
|
(with-open [rdr (io/reader n)]
|
||||||
|
(set (map (fn [line]
|
||||||
|
(let [[_ x] (re-matches #".*testing: ([0-9]+)$" line)]
|
||||||
|
(Integer/parseInt x)))
|
||||||
|
(line-seq rdr))))
|
||||||
|
(catch java.io.FileNotFoundException e (set []))))))))
|
||||||
|
|
||||||
|
|
||||||
|
(deftest rotor-complete-test
|
||||||
|
(testing "no log entry gets thrown away"
|
||||||
|
(let [n-logs 100
|
||||||
|
n-lines 100]
|
||||||
|
|
||||||
|
(setup n-logs)
|
||||||
|
|
||||||
|
(doseq [i (range n-lines)]
|
||||||
|
(timbre/info "testing:" i))
|
||||||
|
|
||||||
|
(check-complete n-logs n-lines)
|
||||||
|
|
||||||
|
(teardown n-logs))))
|
||||||
|
|
||||||
|
(deftest rotor-concurrency-test
|
||||||
|
(testing "no race rotating log files"
|
||||||
|
(let [n-logs 100
|
||||||
|
n-lines 100]
|
||||||
|
|
||||||
|
(setup n-logs)
|
||||||
|
|
||||||
|
(let [futures
|
||||||
|
(for [i (range n-lines)]
|
||||||
|
(future
|
||||||
|
(timbre/info "testing:" i)))]
|
||||||
|
(doseq [f futures]
|
||||||
|
@f))
|
||||||
|
|
||||||
|
(check-complete n-logs n-lines)
|
||||||
|
|
||||||
|
(teardown n-logs))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue