mirror of https://github.com/status-im/timbre.git
NB migrate utils stuff to `encore` lib
This commit is contained in:
parent
f7b2615ae6
commit
7355cd6424
|
@ -41,8 +41,7 @@ The `refer-timbre` call is a convenience fn that executes:
|
|||
(require '[taoensso.timbre :as timbre
|
||||
:refer (log trace debug info warn error fatal report
|
||||
logf tracef debugf infof warnf errorf fatalf reportf
|
||||
spy logged-future with-log-level)])
|
||||
(require '[taoensso.timbre.utils :refer (sometimes)])
|
||||
spy logged-future with-log-level sometimes)])
|
||||
(require '[taoensso.timbre.profiling :as profiling :refer (pspy profile defnp)])
|
||||
```
|
||||
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
:global-vars {*warn-on-reflection* true
|
||||
*assert* true}
|
||||
:dependencies
|
||||
[[org.clojure/clojure "1.4.0"]
|
||||
[org.clojure/tools.macro "0.1.5"]
|
||||
[io.aviso/pretty "0.1.8"]]
|
||||
[[org.clojure/clojure "1.4.0"]
|
||||
[io.aviso/pretty "0.1.8"]
|
||||
[com.taoensso/encore "0.8.0"]]
|
||||
|
||||
:test-paths ["test" "src"]
|
||||
:profiles
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{:author "Peter Taoussanis"}
|
||||
(:require [clojure.string :as str]
|
||||
[io.aviso.exception :as aviso-ex]
|
||||
[taoensso.timbre.utils :as utils])
|
||||
[taoensso.encore :as encore])
|
||||
(:import [java.util Date Locale]
|
||||
[java.text SimpleDateFormat]))
|
||||
|
||||
|
@ -42,6 +42,12 @@
|
|||
|
||||
(comment (stacktrace (Exception. "foo") nil {}))
|
||||
|
||||
(defmacro sometimes
|
||||
"Executes body with probability e/o [0,1]. Useful for sampled logging."
|
||||
[probability & body]
|
||||
`(do (assert (<= 0 ~probability 1) "Probability: 0 <= p <= 1")
|
||||
(when (< (rand) ~probability) ~@body)))
|
||||
|
||||
;;;; Logging levels
|
||||
|
||||
(def level-compile-time
|
||||
|
@ -171,9 +177,9 @@
|
|||
(try (spit filename (str output "\n") :append true)
|
||||
(catch java.io.IOException _))))}}})
|
||||
|
||||
(utils/defonce* config (atom example-config))
|
||||
(encore/defonce* config (atom example-config))
|
||||
(defn set-config! [ks val] (swap! config assoc-in ks val))
|
||||
(defn merge-config! [& maps] (apply swap! config utils/merge-deep maps))
|
||||
(defn merge-config! [& maps] (apply swap! config encore/merge-deep maps))
|
||||
|
||||
;;;; Appender-fn decoration
|
||||
|
||||
|
@ -221,11 +227,11 @@
|
|||
;; Compile-time:
|
||||
(if-not rate-limit apfn
|
||||
(let [[ncalls-limit window-ms] rate-limit
|
||||
limiter-any (utils/rate-limiter ncalls-limit window-ms)
|
||||
limiter-any (encore/rate-limiter ncalls-limit window-ms)
|
||||
;; This is a little hand-wavy but it's a decent general
|
||||
;; strategy and helps us from making this overly complex to
|
||||
;; configure.
|
||||
limiter-specific (utils/rate-limiter (quot ncalls-limit 4)
|
||||
limiter-specific (encore/rate-limiter (quot ncalls-limit 4)
|
||||
window-ms)]
|
||||
(fn [{:keys [ns args] :as apfn-args}]
|
||||
;; Runtime: (test smaller limit 1st):
|
||||
|
@ -256,7 +262,7 @@
|
|||
(comment ((make-timestamp-fn "yyyy-MMM-dd" nil) (Date.)))
|
||||
|
||||
(def ^:private get-hostname
|
||||
(utils/memoize-ttl 60000
|
||||
(encore/memoize* 60000
|
||||
(fn []
|
||||
(let [p (promise)]
|
||||
(future ; Android doesn't like this on the main thread
|
||||
|
@ -499,8 +505,7 @@
|
|||
'[taoensso.timbre :as timbre
|
||||
:refer (log trace debug info warn error fatal report
|
||||
logf tracef debugf infof warnf errorf fatalf reportf
|
||||
spy logged-future with-log-level)])
|
||||
(require '[taoensso.timbre.utils :refer (sometimes)])
|
||||
spy logged-future with-log-level sometimes)])
|
||||
(require
|
||||
'[taoensso.timbre.profiling :as profiling :refer (pspy profile defnp)])"
|
||||
[]
|
||||
|
@ -508,8 +513,7 @@
|
|||
'[taoensso.timbre :as timbre
|
||||
:refer (log trace debug info warn error fatal report
|
||||
logf tracef debugf infof warnf errorf fatalf reportf
|
||||
spy logged-future with-log-level)])
|
||||
(require '[taoensso.timbre.utils :refer (sometimes)])
|
||||
spy logged-future with-log-level sometimes)])
|
||||
(require
|
||||
'[taoensso.timbre.profiling :as profiling :refer (pspy profile defnp)]))
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
"Logging profiler for Timbre, adapted from clojure.contrib.profile."
|
||||
{:author "Peter Taoussanis"}
|
||||
(:require [clojure.tools.macro :as macro]
|
||||
[taoensso.timbre :as timbre]
|
||||
[taoensso.timbre.utils :as utils]))
|
||||
[taoensso.encore :as encore]
|
||||
[taoensso.timbre :as timbre]))
|
||||
|
||||
(def ^:dynamic *pdata* "{::pname [time1 time2 ...]}" nil)
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
|||
of named body. Always returns the body's result."
|
||||
[name & body]
|
||||
`(if-not *pdata* (do ~@body)
|
||||
(let [name# (utils/fq-keyword ~name)
|
||||
(let [name# (encore/fq-keyword ~name)
|
||||
start-time# (System/nanoTime)]
|
||||
(try (do ~@body)
|
||||
(finally
|
||||
|
@ -42,7 +42,7 @@
|
|||
`(let [{result# :result stats# :stats} (with-pdata ~level ~@body)]
|
||||
(when stats#
|
||||
(timbre/log* {:profile-stats stats#} :format ~level
|
||||
"Profiling: %s\n%s" (utils/fq-keyword ~name)
|
||||
"Profiling: %s\n%s" (encore/fq-keyword ~name)
|
||||
(format-pdata stats#)))
|
||||
result#))
|
||||
|
||||
|
@ -86,7 +86,7 @@
|
|||
ft (fn [nanosecs]
|
||||
(let [pow #(Math/pow 10 %)
|
||||
ok-pow? #(>= nanosecs (pow %))
|
||||
to-pow #(utils/round-to %2 (/ nanosecs (pow %1)))]
|
||||
to-pow #(encore/round %2 :round (/ nanosecs (pow %1)))]
|
||||
(cond (ok-pow? 9) (str (to-pow 9 1) "s")
|
||||
(ok-pow? 6) (str (to-pow 6 0) "ms")
|
||||
(ok-pow? 3) (str (to-pow 3 0) "μs")
|
||||
|
|
|
@ -1,109 +1,2 @@
|
|||
(ns taoensso.timbre.utils
|
||||
{:author "Peter Taoussanis"}
|
||||
(:require [clojure.tools.macro :as macro]))
|
||||
|
||||
(defmacro defonce*
|
||||
"Like `clojure.core/defonce` but supports optional docstring and attributes
|
||||
map for name symbol."
|
||||
{:arglists '([name expr])}
|
||||
[name & sigs]
|
||||
(let [[name [expr]] (macro/name-with-attributes name sigs)]
|
||||
`(clojure.core/defonce ~name ~expr)))
|
||||
|
||||
(defn memoize-ttl "Low-overhead, common-case `memoize*`."
|
||||
[ttl-ms f]
|
||||
(let [cache (atom {})]
|
||||
(fn [& args]
|
||||
(when (<= (rand) 0.001) ; GC
|
||||
(let [instant (System/currentTimeMillis)]
|
||||
(swap! cache
|
||||
(fn [m] (reduce-kv (fn [m* k [dv udt :as cv]]
|
||||
(if (> (- instant udt) ttl-ms) m*
|
||||
(assoc m* k cv))) {} m)))))
|
||||
(let [[dv udt] (@cache args)]
|
||||
(if (and dv (< (- (System/currentTimeMillis) udt) ttl-ms)) @dv
|
||||
(locking cache ; For thread racing
|
||||
(let [[dv udt] (@cache args)] ; Retry after lock acquisition!
|
||||
(if (and dv (< (- (System/currentTimeMillis) udt) ttl-ms)) @dv
|
||||
(let [dv (delay (apply f args))
|
||||
cv [dv (System/currentTimeMillis)]]
|
||||
(swap! cache assoc args cv)
|
||||
@dv)))))))))
|
||||
|
||||
(defn rate-limiter
|
||||
"Returns a `(fn [& [id]])` that returns either `nil` (limit okay) or number of
|
||||
msecs until next rate limit window (rate limited)."
|
||||
[ncalls-limit window-ms]
|
||||
(let [state (atom [nil {}])] ; [<pull> {<id> {[udt-window-start ncalls]}}]
|
||||
(fn [& [id]]
|
||||
|
||||
(when (<= (rand) 0.001) ; GC
|
||||
(let [instant (System/currentTimeMillis)]
|
||||
(swap! state
|
||||
(fn [[_ m]]
|
||||
[nil (reduce-kv
|
||||
(fn [m* id [udt-window-start ncalls]]
|
||||
(if (> (- instant udt-window-start) window-ms) m*
|
||||
(assoc m* id [udt-window-start ncalls]))) {} m)]))))
|
||||
|
||||
(->
|
||||
(let [instant (System/currentTimeMillis)]
|
||||
(swap! state
|
||||
(fn [[_ m]]
|
||||
(if-let [[udt-window-start ncalls] (m id)]
|
||||
(if (> (- instant udt-window-start) window-ms)
|
||||
[nil (assoc m id [instant 1])]
|
||||
(if (< ncalls ncalls-limit)
|
||||
[nil (assoc m id [udt-window-start (inc ncalls)])]
|
||||
[(- (+ udt-window-start window-ms) instant) m]))
|
||||
[nil (assoc m id [instant 1])]))))
|
||||
(nth 0)))))
|
||||
|
||||
(comment
|
||||
(def rl (rate-limit 10 10000))
|
||||
(repeatedly 10 #(rl (rand-nth [:a :b :c])))
|
||||
(rl :a)
|
||||
(rl :b)
|
||||
(rl :c))
|
||||
|
||||
(defn merge-deep-with ; From clojure.contrib.map-utils
|
||||
"Like `merge-with` but merges maps recursively, applying the given fn
|
||||
only when there's a non-map at a particular level.
|
||||
|
||||
(merge-deep-with + {:a {:b {:c 1 :d {:x 1 :y 2}} :e 3} :f 4}
|
||||
{:a {:b {:c 2 :d {:z 9} :z 3} :e 100}})
|
||||
=> {:a {:b {:z 3, :c 3, :d {:z 9, :x 1, :y 2}}, :e 103}, :f 4}"
|
||||
[f & maps]
|
||||
(apply
|
||||
(fn m [& maps]
|
||||
(if (every? map? maps)
|
||||
(apply merge-with m maps)
|
||||
(apply f maps)))
|
||||
maps))
|
||||
|
||||
(def merge-deep (partial merge-deep-with (fn [x y] y)))
|
||||
|
||||
(comment (merge-deep {:a {:b {:c {:d :D :e :E}}}}
|
||||
{:a {:b {:g :G :c {:c {:f :F}}}}}))
|
||||
|
||||
(defn round-to "Rounds argument to given number of decimal places."
|
||||
[places x]
|
||||
(if (zero? places)
|
||||
(Math/round (double x))
|
||||
(let [modifier (Math/pow 10.0 places)]
|
||||
(/ (Math/round (* x modifier)) modifier))))
|
||||
|
||||
(comment (round-to 0 10)
|
||||
(round-to 2 10.123))
|
||||
|
||||
(defmacro fq-keyword "Returns namespaced keyword for given name."
|
||||
[name]
|
||||
`(if (and (keyword? ~name) (namespace ~name)) ~name
|
||||
(keyword (str ~*ns*) (clojure.core/name ~name))))
|
||||
|
||||
(comment (map #(fq-keyword %) ["foo" :foo :foo/bar]))
|
||||
|
||||
(defmacro sometimes "Executes body with probability e/o [0,1]."
|
||||
[probability & body]
|
||||
`(do (assert (<= 0 ~probability 1) "Probability: 0 <= p <= 1")
|
||||
(when (< (rand) ~probability) ~@body)))
|
||||
{:author "Peter Taoussanis"})
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
(ns taoensso.timbre.tests.main
|
||||
(:require [expectations :as test :refer :all]
|
||||
[taoensso.timbre :as timbre :refer (trace debug info warn
|
||||
error fatal spy)]
|
||||
[taoensso.timbre.profiling :as profiling :refer (p profile)]))
|
||||
[taoensso.timbre :as timbre]))
|
||||
|
||||
(timbre/refer-timbre)
|
||||
|
||||
(defn- before-run {:expectations-options :before-run} [])
|
||||
(defn- after-run {:expectations-options :after-run} [])
|
||||
|
||||
(expect true) ; TODO Add tests (PRs welcome!)
|
||||
(expect true) ; TODO Add tests (PRs welcome!)
|
||||
|
|
Loading…
Reference in New Issue