From f04aba6e0d29c52029b2dd4b8e8e586ae6bfd18f Mon Sep 17 00:00:00 2001 From: Peter Taoussanis Date: Sat, 30 Nov 2013 16:22:33 +0700 Subject: [PATCH] Add new appender opt: `:appender-fmt-output-opts` --- src/taoensso/timbre.clj | 51 +++++++++++++++++------- src/taoensso/timbre/appenders/postal.clj | 8 ++-- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/taoensso/timbre.clj b/src/taoensso/timbre.clj index ffc1878..5858035 100644 --- a/src/taoensso/timbre.clj +++ b/src/taoensso/timbre.clj @@ -92,13 +92,15 @@ "APPENDERS An appender is a map with keys: :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: :level, :throwable :args, ; Raw logging macro args (as given to `info`, etc.). :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`. :profile-stats ; From `profile` macro. And also: :instant, :timestamp, :hostname, :ns, :error? @@ -129,30 +131,33 @@ (str timestamp " " hostname " " (-> level name str/upper-case) " [" ns "]")) - ;; Default output formatter used by built-in appenders. Custom appenders - ;; may (but are not required to use) its output (:default-output). + ;; Output formatter used by built-in appenders. Custom appenders may (but are + ;; not required to use) its output (:output). Extra per-appender opts can be + ;; supplied as an optional second (map) arg. :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}]] ;; [] - (format "%s %s %s [%s] - %s%s" 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 :appenders {:standard-out {:doc "Prints to *out*/*err*. Enabled by default." :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*)] - (str-println default-output)))} + (str-println output)))} :spit {:doc "Spits to `(:spit-filename :shared-appender-config)` file." :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)] - (try (spit filename default-output :append true) + (try (spit filename output :append true) (catch java.io.IOException _))))}}}) (utils/defonce* config (atom example-config)) @@ -164,7 +169,7 @@ (defn- wrap-appender-fn "Wraps compile-time appender fn with additional runtime capabilities 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: (if-let [x (:max-message-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 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 ((fn [apfn] ;; Compile-time: @@ -253,8 +266,8 @@ juxtfn-args (assoc juxtfn-args :timestamp (timestamp-fn instant)) juxtfn-args (assoc juxtfn-args ;; DEPRECATED, here for backwards comp: - :prefix (when-let [f prefix-fn] (f juxtfn-args)) - :default-output (when-let [f fmt-output-fn] (f juxtfn-args)))] + :prefix (when-let [f prefix-fn] (f juxtfn-args)) + :output (when-let [f fmt-output-fn] (f juxtfn-args)))] (juxtfn juxtfn-args))))))) ;; Middleware transforms/filters support @@ -300,6 +313,7 @@ ;; since configs will usually be assigned to a var for which we have proper ;; identity. (fn [{:keys [appenders] :as config}] + (assert (map? appenders)) {:appenders-juxt (zipmap levels-ordered (->> levels-ordered @@ -525,4 +539,13 @@ (mapv (fn [arg] (if-not (map? arg) arg (if-not (contains? arg :password) arg (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"))) diff --git a/src/taoensso/timbre/appenders/postal.clj b/src/taoensso/timbre/appenders/postal.clj index 3b699cf..1639142 100644 --- a/src/taoensso/timbre/appenders/postal.clj +++ b/src/taoensso/timbre/appenders/postal.clj @@ -17,11 +17,11 @@ ^{:host \"mail.isp.net\" :user \"jsmith\" :pass \"sekrat!!1\"} {:from \"Bob's logger \" :to \"foo@example.com\"}") :min-level :error :enabled? true :async? true + :fmt-output-opts {:nofonts? true} :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)] (postal/send-message (assoc postal-config - :subject (-> default-output (str/trim) (str-trunc 150) - (str/replace #"\s+" " ")) - :body default-output))))}) + :subject (-> output (str/trim) (str-trunc 150) (str/replace #"\s+" " ")) + :body output))))})