mirror of https://github.com/status-im/timbre.git
Rename appender argument: :max-message-per-msecs -> :limit-per-msecs (backwards compatible)
This commit is contained in:
parent
c30ae5fbcc
commit
6fc6baee37
|
@ -16,7 +16,7 @@ Timbre is an attempt to make **simple logging simple** and more **complex loggin
|
|||
* **Decent performance** (low overhead).
|
||||
* Flexible **fn-centric appender model** with **middleware**.
|
||||
* Sensible built-in appenders including simple **email appender**.
|
||||
* Tunable **flood control** and **asynchronous** logging support.
|
||||
* Tunable **rate limit** and **asynchronous** logging support.
|
||||
* Robust **namespace filtering**.
|
||||
* Dead-simple, logging-level-aware **logging profiler**.
|
||||
|
||||
|
@ -137,8 +137,8 @@ Filter logging output by namespaces:
|
|||
^{:host "mail.isp.net" :user "jsmith" :pass "sekrat!!1"}
|
||||
{:from "me@draines.com" :to "foo@example.com"})
|
||||
|
||||
;; Rate-limit to one email per message per minute
|
||||
(timbre/set-config! [:appenders :postal :max-message-per-msecs] 60000)
|
||||
;; Rate limit to one email per message per minute
|
||||
(timbre/set-config! [:appenders :postal :limit-per-msecs] 60000)
|
||||
|
||||
;; Make sure emails are sent asynchronously
|
||||
(timbre/set-config! [:appenders :postal :async?] true)
|
||||
|
@ -170,7 +170,7 @@ Writing a custom appender is dead-easy:
|
|||
:min-level :debug
|
||||
:enabled? true
|
||||
:async? false
|
||||
:max-message-per-msecs nil ; No rate limiting
|
||||
:limit-per-msecs nil ; No rate limit
|
||||
:fn (fn [{:keys [ap-config level prefix message more] :as args}]
|
||||
(when-not (:my-production-mode? ap-config)
|
||||
(apply println prefix "Hello world!" message more)))
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
|
||||
APPENDERS
|
||||
An appender is a map with keys:
|
||||
:doc, :min-level, :enabled?, :async?, :max-message-per-msecs, :fn
|
||||
:doc, :min-level, :enabled?, :async?, :limit-per-msecs, :fn
|
||||
|
||||
An appender's fn takes a single map argument with keys:
|
||||
:level, :message, :more ; From all logging macros (`info`, etc.)
|
||||
|
@ -88,16 +88,14 @@
|
|||
:appenders
|
||||
{:standard-out
|
||||
{:doc "Prints to *out* or *err* as appropriate. Enabled by default."
|
||||
:min-level nil :enabled? true :async? false
|
||||
:max-message-per-msecs nil
|
||||
:min-level nil :enabled? true :async? false :limit-per-msecs nil
|
||||
:fn (fn [{:keys [error? prefix message more]}]
|
||||
(binding [*out* (if error? *err* *out*)]
|
||||
(apply str-println prefix "-" message more)))}
|
||||
|
||||
:spit
|
||||
{:doc "Spits to (:spit-filename :shared-appender-config) file."
|
||||
:min-level nil :enabled? false :async? false
|
||||
:max-message-per-msecs nil
|
||||
:min-level nil :enabled? false :async? false :limit-per-msecs nil
|
||||
:fn (fn [{:keys [ap-config prefix message more]}]
|
||||
(when-let [filename (:spit-filename ap-config)]
|
||||
(try (spit filename
|
||||
|
@ -132,53 +130,55 @@
|
|||
(defn- wrap-appender-fn
|
||||
"Wraps compile-time appender fn with additional runtime capabilities
|
||||
controlled by compile-time config."
|
||||
[{apfn :fn :keys [async? max-message-per-msecs prefix-fn] :as appender}]
|
||||
(->> ; Wrapping applies per appender, bottom-to-top
|
||||
apfn
|
||||
[{apfn :fn :keys [async? limit-per-msecs prefix-fn] :as appender}]
|
||||
(let [limit-per-msecs (or (:max-message-per-msecs appender)
|
||||
limit-per-msecs)] ; Backwards-compatibility
|
||||
(->> ; Wrapping applies per appender, bottom-to-top
|
||||
apfn
|
||||
|
||||
;; Prefix-fn support
|
||||
((fn [apfn]
|
||||
(if-not prefix-fn
|
||||
apfn
|
||||
(fn [apfn-args]
|
||||
(apfn (assoc apfn-args
|
||||
:prefix (prefix-fn apfn-args)))))))
|
||||
;; Per-appender prefix-fn support (cmp. default prefix-fn)
|
||||
((fn [apfn]
|
||||
(if-not prefix-fn
|
||||
apfn
|
||||
(fn [apfn-args]
|
||||
(apfn (assoc apfn-args
|
||||
:prefix (prefix-fn apfn-args)))))))
|
||||
|
||||
;; Rate limit support
|
||||
((fn [apfn]
|
||||
(if-not max-message-per-msecs
|
||||
apfn
|
||||
(let [;; {:hash last-appended-time-msecs ...}
|
||||
flood-timers (atom {})]
|
||||
;; Rate limit support
|
||||
((fn [apfn]
|
||||
(if-not limit-per-msecs
|
||||
apfn
|
||||
(let [;; {:hash last-appended-time-msecs ...}
|
||||
flood-timers (atom {})]
|
||||
|
||||
(fn [{:keys [ns message] :as apfn-args}]
|
||||
(let [now (System/currentTimeMillis)
|
||||
hash (str ns "/" message)
|
||||
allow? (fn [last-msecs]
|
||||
(or (not last-msecs)
|
||||
(> (- now last-msecs) max-message-per-msecs)))]
|
||||
(fn [{:keys [ns message] :as apfn-args}]
|
||||
(let [now (System/currentTimeMillis)
|
||||
hash (str ns "/" message)
|
||||
allow? (fn [last-msecs]
|
||||
(or (not last-msecs)
|
||||
(> (- now last-msecs) limit-per-msecs)))]
|
||||
|
||||
(when (allow? (@flood-timers hash))
|
||||
(apfn apfn-args)
|
||||
(swap! flood-timers assoc hash now))
|
||||
(when (allow? (@flood-timers hash))
|
||||
(apfn apfn-args)
|
||||
(swap! flood-timers assoc hash now))
|
||||
|
||||
;; Occassionally garbage-collect all expired timers. Note
|
||||
;; that due to snapshotting, garbage-collection can cause
|
||||
;; some appenders to re-append prematurely.
|
||||
(when (< (rand) 0.001)
|
||||
(let [timers-snapshot @flood-timers
|
||||
expired-timers
|
||||
(->> (keys timers-snapshot)
|
||||
(filter #(allow? (timers-snapshot %))))]
|
||||
(when (seq expired-timers)
|
||||
(apply swap! flood-timers dissoc expired-timers))))))))))
|
||||
;; Occassionally garbage-collect all expired timers. Note
|
||||
;; that due to snapshotting, garbage-collection can cause
|
||||
;; some appenders to re-append prematurely.
|
||||
(when (< (rand) 0.001)
|
||||
(let [timers-snapshot @flood-timers
|
||||
expired-timers
|
||||
(->> (keys timers-snapshot)
|
||||
(filter #(allow? (timers-snapshot %))))]
|
||||
(when (seq expired-timers)
|
||||
(apply swap! flood-timers dissoc expired-timers))))))))))
|
||||
|
||||
;; Async (agent) support
|
||||
((fn [apfn]
|
||||
(if-not async?
|
||||
apfn
|
||||
(let [agent (agent nil :error-mode :continue)]
|
||||
(fn [apfn-args] (send-off agent (fn [_] (apfn apfn-args))))))))))
|
||||
;; Async (agent) support
|
||||
((fn [apfn]
|
||||
(if-not async?
|
||||
apfn
|
||||
(let [agent (agent nil :error-mode :continue)]
|
||||
(fn [apfn-args] (send-off agent (fn [_] (apfn apfn-args)))))))))))
|
||||
|
||||
(defn- make-timestamp-fn
|
||||
"Returns a unary fn that formats instants using given pattern string and an
|
||||
|
@ -410,4 +410,4 @@
|
|||
(if (contains? message :password)
|
||||
(assoc args :message (assoc message :password "*****"))
|
||||
args)
|
||||
:else args))]))
|
||||
:else args))]))
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
"Needs :irc config map in :shared-appender-config, e.g.:
|
||||
{:host \"irc.example.org\" :port 6667 :nick \"logger\"
|
||||
:name \"My Logger\" :chan \"#logs\"")
|
||||
:min-level :info :enabled? true :async? false
|
||||
:max-message-per-msecs nil ; no rate limit by default
|
||||
:min-level :info :enabled? true :async? false :limit-per-msecs nil
|
||||
:prefix-fn (fn [{:keys [level]}] (-> level name str/upper-case))
|
||||
:fn appender-fn})
|
||||
|
|
|
@ -11,11 +11,11 @@
|
|||
^{:host \"mail.isp.net\" :user \"jsmith\" :pass \"sekrat!!1\"}
|
||||
{:from \"Bob's logger <me@draines.com>\" :to \"foo@example.com\"}")
|
||||
:min-level :error :enabled? true :async? true
|
||||
:max-message-per-msecs (* 1000 60 10) ; 1 email per message per 10 mins
|
||||
:limit-per-msecs (* 1000 60 10) ; 1 subject / 10 mins
|
||||
:fn (fn [{:keys [ap-config prefix message more]}]
|
||||
(when-let [postal-config (:postal ap-config)]
|
||||
(postal/send-message
|
||||
(assoc postal-config
|
||||
:subject (str prefix " - " message)
|
||||
:body (if (seq more) (str/join " " more)
|
||||
"<no additional arguments>")))))})
|
||||
"<no additional arguments>")))))})
|
||||
|
|
Loading…
Reference in New Issue