Add new appender opt: `:appender-fmt-output-opts`

This commit is contained in:
Peter Taoussanis 2013-11-30 16:22:33 +07:00
parent f83b417cb0
commit f04aba6e0d
2 changed files with 41 additions and 18 deletions

View File

@ -92,13 +92,15 @@
"APPENDERS "APPENDERS
An appender is a map with keys: An appender is a map with keys:
:doc, :min-level, :enabled?, :async?, :fn, :doc, :min-level, :enabled?, :async?, :fn,
:rate-limit ([ncalls-limit window-ms] form). :rate-limit ; [ncalls-limit window-ms],
:fmt-output-opts ; Extra opts passed to `fmt-output-fn`.
An appender's fn takes a single map with keys: An appender's fn takes a single map with keys:
:level, :throwable :level, :throwable
:args, ; Raw logging macro args (as given to `info`, etc.). :args, ; Raw logging macro args (as given to `info`, etc.).
:message, ; Stringified logging macro args, or nil. :message, ; Stringified logging macro args, or nil.
:default-output ; Output of `fmt-output-fn`, used by built-in appenders. :output ; Output of `fmt-output-fn`, used by built-in appenders
; as final, formatted appender output.
:ap-config ; `shared-appender-config`. :ap-config ; `shared-appender-config`.
:profile-stats ; From `profile` macro. :profile-stats ; From `profile` macro.
And also: :instant, :timestamp, :hostname, :ns, :error? And also: :instant, :timestamp, :hostname, :ns, :error?
@ -129,30 +131,33 @@
(str timestamp " " hostname " " (-> level name str/upper-case) (str timestamp " " hostname " " (-> level name str/upper-case)
" [" ns "]")) " [" ns "]"))
;; Default output formatter used by built-in appenders. Custom appenders ;; Output formatter used by built-in appenders. Custom appenders may (but are
;; may (but are not required to use) its output (:default-output). ;; not required to use) its output (:output). Extra per-appender opts can be
;; supplied as an optional second (map) arg.
:fmt-output-fn :fmt-output-fn
(fn [{:keys [level throwable message timestamp hostname ns]}] (fn [{:keys [level throwable message timestamp hostname ns]}
;; Any extra appender-specific opts:
& [{:keys [nofonts?] :as appender-fmt-output-opts}]]
;; <timestamp> <hostname> <LEVEL> [<ns>] - <message> <throwable> ;; <timestamp> <hostname> <LEVEL> [<ns>] - <message> <throwable>
(format "%s %s %s [%s] - %s%s" (format "%s %s %s [%s] - %s%s"
timestamp hostname (-> level name str/upper-case) ns (or message "") timestamp hostname (-> level name str/upper-case) ns (or message "")
(or (stacktrace throwable "\n") ""))) (or (stacktrace throwable "\n" (when nofonts? {})) "")))
:shared-appender-config {} ; Provided to all appenders via :ap-config key :shared-appender-config {} ; Provided to all appenders via :ap-config key
:appenders :appenders
{:standard-out {:standard-out
{:doc "Prints to *out*/*err*. Enabled by default." {:doc "Prints to *out*/*err*. Enabled by default."
:min-level nil :enabled? true :async? false :rate-limit nil :min-level nil :enabled? true :async? false :rate-limit nil
:fn (fn [{:keys [error? default-output]}] :fn (fn [{:keys [error? output]}]
(binding [*out* (if error? *err* *out*)] (binding [*out* (if error? *err* *out*)]
(str-println default-output)))} (str-println output)))}
:spit :spit
{:doc "Spits to `(:spit-filename :shared-appender-config)` file." {:doc "Spits to `(:spit-filename :shared-appender-config)` file."
:min-level nil :enabled? false :async? false :rate-limit nil :min-level nil :enabled? false :async? false :rate-limit nil
:fn (fn [{:keys [ap-config default-output]}] :fn (fn [{:keys [ap-config output]}]
(when-let [filename (:spit-filename ap-config)] (when-let [filename (:spit-filename ap-config)]
(try (spit filename default-output :append true) (try (spit filename output :append true)
(catch java.io.IOException _))))}}}) (catch java.io.IOException _))))}}})
(utils/defonce* config (atom example-config)) (utils/defonce* config (atom example-config))
@ -164,7 +169,7 @@
(defn- wrap-appender-fn (defn- wrap-appender-fn
"Wraps compile-time appender fn with additional runtime capabilities "Wraps compile-time appender fn with additional runtime capabilities
controlled by compile-time config." controlled by compile-time config."
[config {apfn :fn :keys [async? rate-limit] :as appender}] [config {apfn :fn :keys [async? rate-limit fmt-output-opts] :as appender}]
(let [rate-limit (or rate-limit ; Backwards comp: (let [rate-limit (or rate-limit ; Backwards comp:
(if-let [x (:max-message-per-msecs appender)] [1 x] (if-let [x (:max-message-per-msecs appender)] [1 x]
(when-let [x (:limit-per-msecs appender)] [1 x])))] (when-let [x (:limit-per-msecs appender)] [1 x])))]
@ -174,6 +179,14 @@
(->> ; Wrapping applies per appender, bottom-to-top (->> ; Wrapping applies per appender, bottom-to-top
apfn apfn
;; Custom appender-level fmt-output-opts
((fn [apfn] ; Compile-time:
(if-not fmt-output-opts apfn ; Common case (no appender-level fmt opts)
(fn [apfn-args] ; Runtime:
;; Replace default (juxt-level) output:
(apfn (assoc apfn-args :output
((:fmt-output-fn config) apfn-args fmt-output-opts)))))))
;; Rate limit support ;; Rate limit support
((fn [apfn] ((fn [apfn]
;; Compile-time: ;; Compile-time:
@ -254,7 +267,7 @@
juxtfn-args (assoc juxtfn-args juxtfn-args (assoc juxtfn-args
;; DEPRECATED, here for backwards comp: ;; DEPRECATED, here for backwards comp:
:prefix (when-let [f prefix-fn] (f juxtfn-args)) :prefix (when-let [f prefix-fn] (f juxtfn-args))
:default-output (when-let [f fmt-output-fn] (f juxtfn-args)))] :output (when-let [f fmt-output-fn] (f juxtfn-args)))]
(juxtfn juxtfn-args))))))) (juxtfn juxtfn-args)))))))
;; Middleware transforms/filters support ;; Middleware transforms/filters support
@ -300,6 +313,7 @@
;; since configs will usually be assigned to a var for which we have proper ;; since configs will usually be assigned to a var for which we have proper
;; identity. ;; identity.
(fn [{:keys [appenders] :as config}] (fn [{:keys [appenders] :as config}]
(assert (map? appenders))
{:appenders-juxt {:appenders-juxt
(zipmap levels-ordered (zipmap levels-ordered
(->> levels-ordered (->> levels-ordered
@ -525,4 +539,13 @@
(mapv (fn [arg] (if-not (map? arg) arg (mapv (fn [arg] (if-not (map? arg) arg
(if-not (contains? arg :password) arg (if-not (contains? arg :password) arg
(assoc arg :password "****")))) (assoc arg :password "****"))))
args))))])) args))))])
;; fmt-output-opts
(-> (merge example-config
{:appenders
{:fmt-output-opts-test
{:min-level :error :enabled? true
:fmt-output-opts {:nofonts? true}
:fn (fn [{:keys [output]}] (str-println output))}}})
(log :report (Exception. "Oh noes") "Hello")))

View File

@ -17,11 +17,11 @@
^{:host \"mail.isp.net\" :user \"jsmith\" :pass \"sekrat!!1\"} ^{:host \"mail.isp.net\" :user \"jsmith\" :pass \"sekrat!!1\"}
{:from \"Bob's logger <me@draines.com>\" :to \"foo@example.com\"}") {:from \"Bob's logger <me@draines.com>\" :to \"foo@example.com\"}")
:min-level :error :enabled? true :async? true :min-level :error :enabled? true :async? true
:fmt-output-opts {:nofonts? true}
:rate-limit [5 (* 1000 60 2)] ; 5 calls / 2 mins :rate-limit [5 (* 1000 60 2)] ; 5 calls / 2 mins
:fn (fn [{:keys [ap-config default-output]}] :fn (fn [{:keys [ap-config output]}]
(when-let [postal-config (:postal ap-config)] (when-let [postal-config (:postal ap-config)]
(postal/send-message (postal/send-message
(assoc postal-config (assoc postal-config
:subject (-> default-output (str/trim) (str-trunc 150) :subject (-> output (str/trim) (str-trunc 150) (str/replace #"\s+" " "))
(str/replace #"\s+" " ")) :body output))))})
:body default-output))))})