mirror of https://github.com/status-im/timbre.git
Expose an official low-level logging API for tools, etc.
This commit is contained in:
parent
e611f7a584
commit
e9e20ef88e
|
@ -202,6 +202,7 @@
|
|||
"(fn [whitelist blacklist ns]) -> ?unfiltered-ns"
|
||||
(enc/memoize_
|
||||
(fn [whitelist blacklist ns]
|
||||
{:pre [(have? string? ns)]}
|
||||
((compile-ns-filters whitelist blacklist) ns))))
|
||||
|
||||
(comment (qb 10000 (ns-filter ["foo.*"] ["foo.baz"] "foo.bar")))
|
||||
|
@ -218,7 +219,7 @@
|
|||
(when blacklist
|
||||
(println (str "Compile-time (elision) Timbre ns blacklist: " blacklist)))
|
||||
|
||||
(partial ns-filter whitelist blacklist)))
|
||||
(fn [ns] (ns-filter whitelist blacklist ns))))
|
||||
|
||||
;;;; Utils
|
||||
|
||||
|
@ -273,15 +274,18 @@
|
|||
;;;; Internal logging core
|
||||
|
||||
(defn log?
|
||||
"Would Timbre currently log at the given logging level?
|
||||
* Compile-time `?ns-str` arg required to support ns filtering.
|
||||
* `config` arg required to support non-global config."
|
||||
[level & [?ns-str config]]
|
||||
(let [config (or config *config*)
|
||||
active-level (or (:level config) :report)]
|
||||
(and (level>= level active-level)
|
||||
(ns-filter (:ns-whitelist config) (:ns-blacklist config) (or ?ns-str ""))
|
||||
true)))
|
||||
"Would Timbre currently (runtime) log at the given logging level?
|
||||
* `?ns-str` arg required to support ns filtering
|
||||
* `config` arg required to support non-global config"
|
||||
([level ] (log? level nil nil))
|
||||
([level ?ns-str ] (log? level ?ns-str nil))
|
||||
([level ?ns-str config]
|
||||
(let [config (or config *config*)
|
||||
active-level (or (:level config) :report)]
|
||||
(and
|
||||
(level>= level active-level)
|
||||
(ns-filter (:ns-whitelist config) (:ns-blacklist config) (or ?ns-str ""))
|
||||
true))))
|
||||
|
||||
(comment
|
||||
(set-level! :debug)
|
||||
|
@ -306,6 +310,7 @@
|
|||
(def ^:dynamic *context*
|
||||
"General-purpose dynamic logging context. Context will be included in appender
|
||||
data map at logging time." nil)
|
||||
|
||||
(defmacro with-context [context & body] `(binding [*context* ~context] ~@body))
|
||||
|
||||
(declare get-hostname)
|
||||
|
@ -325,14 +330,18 @@
|
|||
(inherit-over :foo {:foo :inherit} {:foo :bar} nil)
|
||||
(inherit-into :foo {:foo {:a :A :b :B :c :C}} {:foo {:a 1 :b 2 :c 3 :d 4}} nil))
|
||||
|
||||
(defn log1-fn
|
||||
"Core fn-level logger. Implementation detail!"
|
||||
[config level ?ns-str ?file ?line msg-type vargs_ ?base-data]
|
||||
(when (log? level ?ns-str config)
|
||||
(let [instant (enc/now-dt)
|
||||
vargs*_ (delay (vsplit-err1 @vargs_))
|
||||
?err_ (delay (get @vargs*_ 0))
|
||||
vargs_ (delay (get @vargs*_ 1))
|
||||
(defn -log! "Core low-level log fn. Implementation detail."
|
||||
[config level ?ns-str ?file ?line msg-type ?err vargs_ ?base-data]
|
||||
(when (log? level ?ns-str config) ; Runtime check
|
||||
(let [instant (enc/now-dt)
|
||||
;; vargs_ (->delay vargs_)
|
||||
|
||||
;; Extract ?err as err-type a0 in vargs?:
|
||||
a0-err? (enc/kw-identical? ?err :auto)
|
||||
vargs*_ (if a0-err? (delay (vsplit-err1 @vargs_)) vargs_)
|
||||
?err_ (if a0-err? (delay (get @vargs*_ 0)) (delay ?err))
|
||||
vargs_ (if a0-err? (delay (get @vargs*_ 1)) vargs_)
|
||||
|
||||
context *context*
|
||||
data (merge ?base-data
|
||||
;; No, better nest than merge (appenders may want to pass
|
||||
|
@ -427,49 +436,76 @@
|
|||
nil)
|
||||
|
||||
(comment
|
||||
(log1-fn *config* :info nil nil nil :p (delay [(do (println "hi") :x) :y]) nil))
|
||||
(-log! *config* :info nil nil nil :p :auto
|
||||
(delay [(do (println "hi") :x) :y]) nil))
|
||||
|
||||
(defmacro log1-macro
|
||||
"Core macro-level logger. Implementation detail!"
|
||||
[config level msg-type args & [?base-data]]
|
||||
|
||||
;; Compile-time elision:
|
||||
(defmacro -with-elision
|
||||
"Implementation detail.
|
||||
Executes body iff given level and ns pass compile-time elision."
|
||||
[level-form ns-str-form & body]
|
||||
(when (or (nil? compile-time-level)
|
||||
(not (valid-levels level)) ; Not a compile-time level
|
||||
(level>= level compile-time-level))
|
||||
(not (valid-levels level-form)) ; Not a compile-time level const
|
||||
(level>= level-form compile-time-level))
|
||||
|
||||
(when (compile-time-ns-filter (str *ns*))
|
||||
(when (or (not (string? ns-str-form)) ; Not a compile-time ns-str const
|
||||
(compile-time-ns-filter ns-str-form))
|
||||
`(do ~@body))))
|
||||
|
||||
(let [ns-str (str *ns*)
|
||||
?file (let [f *file*] (when (not= f "NO_SOURCE_PATH") f))
|
||||
;; TODO Waiting on http://dev.clojure.org/jira/browse/CLJ-865:
|
||||
?line (:line (meta &form))]
|
||||
`(log1-fn ~config ~level ~ns-str ~?file ~?line ~msg-type
|
||||
(comment (-with-elision :info "ns" (println "foo")))
|
||||
|
||||
(defmacro log! ; Public wrapper around `-log!`
|
||||
"Core low-level log macro. Useful for tooling, etc.
|
||||
|
||||
* `level` - must eval to a valid logging level
|
||||
* `msg-type` - must eval to e/o #{:p :f nil}
|
||||
* `opts` - ks e/o #{:config :?err :?ns-str :?file :?line
|
||||
:?base-data}
|
||||
|
||||
Supports compile-time elision when compile-time const vals
|
||||
provided for `level` and/or `?ns-str`."
|
||||
[level msg-type args & [opts]]
|
||||
(have sequential? args) ; To allow -> (delay [~@args])
|
||||
(let [{:keys [?ns-str] :or {?ns-str (str *ns*)}} opts]
|
||||
(-with-elision
|
||||
level ; level-form (may/not be a compile-time kw const)
|
||||
?ns-str ; ns-str-form (may/not be a compile-time str const)
|
||||
(let [{:keys [config ?err ?file ?line ?base-data]
|
||||
:or {config 'taoensso.timbre/*config*
|
||||
?err :auto ; => Extract as err-type a0
|
||||
?file (let [f *file*] (when (not= f "NO_SOURCE_PATH") f))
|
||||
;; TODO Waiting on http://dev.clojure.org/jira/browse/CLJ-865:
|
||||
?line (:line (meta &form))}} opts]
|
||||
`(-log! ~config ~level ~?ns-str ~?file ~?line ~msg-type ~?err
|
||||
(delay [~@args]) ~?base-data)))))
|
||||
|
||||
;;;; API-level stuff
|
||||
(comment
|
||||
(log! :info :p ["foo"])
|
||||
(macroexpand '(log! :info :p ["foo"]))
|
||||
(macroexpand '(log! :info :p ["foo"] {:?line 42})))
|
||||
|
||||
;;;; Main public API-level stuff
|
||||
|
||||
;;; Log using print-style args
|
||||
(defmacro log* [config level & args] `(log1-macro ~config ~level :p ~args))
|
||||
(defmacro log [level & args] `(log1-macro *config* ~level :p ~args))
|
||||
(defmacro trace [& args] `(log1-macro *config* :trace :p ~args))
|
||||
(defmacro debug [& args] `(log1-macro *config* :debug :p ~args))
|
||||
(defmacro info [& args] `(log1-macro *config* :info :p ~args))
|
||||
(defmacro warn [& args] `(log1-macro *config* :warn :p ~args))
|
||||
(defmacro error [& args] `(log1-macro *config* :error :p ~args))
|
||||
(defmacro fatal [& args] `(log1-macro *config* :fatal :p ~args))
|
||||
(defmacro report [& args] `(log1-macro *config* :report :p ~args))
|
||||
(defmacro log* [config level & args] `(log! ~level :p ~args {:config ~config}))
|
||||
(defmacro log [level & args] `(log! ~level :p ~args))
|
||||
(defmacro trace [& args] `(log! :trace :p ~args))
|
||||
(defmacro debug [& args] `(log! :debug :p ~args))
|
||||
(defmacro info [& args] `(log! :info :p ~args))
|
||||
(defmacro warn [& args] `(log! :warn :p ~args))
|
||||
(defmacro error [& args] `(log! :error :p ~args))
|
||||
(defmacro fatal [& args] `(log! :fatal :p ~args))
|
||||
(defmacro report [& args] `(log! :report :p ~args))
|
||||
|
||||
;;; Log using format-style args
|
||||
(defmacro logf* [config level & args] `(log1-macro ~config ~level :f ~args))
|
||||
(defmacro logf [level & args] `(log1-macro *config* ~level :f ~args))
|
||||
(defmacro tracef [& args] `(log1-macro *config* :trace :f ~args))
|
||||
(defmacro debugf [& args] `(log1-macro *config* :debug :f ~args))
|
||||
(defmacro infof [& args] `(log1-macro *config* :info :f ~args))
|
||||
(defmacro warnf [& args] `(log1-macro *config* :warn :f ~args))
|
||||
(defmacro errorf [& args] `(log1-macro *config* :error :f ~args))
|
||||
(defmacro fatalf [& args] `(log1-macro *config* :fatal :f ~args))
|
||||
(defmacro reportf [& args] `(log1-macro *config* :report :f ~args))
|
||||
(defmacro logf* [config level & args] `(log! ~level :f ~args {:config ~config}))
|
||||
(defmacro logf [level & args] `(log! ~level :f ~args))
|
||||
(defmacro tracef [& args] `(log! :trace :f ~args))
|
||||
(defmacro debugf [& args] `(log! :debug :f ~args))
|
||||
(defmacro infof [& args] `(log! :info :f ~args))
|
||||
(defmacro warnf [& args] `(log! :warn :f ~args))
|
||||
(defmacro errorf [& args] `(log! :error :f ~args))
|
||||
(defmacro fatalf [& args] `(log! :fatal :f ~args))
|
||||
(defmacro reportf [& args] `(log! :report :f ~args))
|
||||
|
||||
(comment
|
||||
(infof "hello %s" "world")
|
||||
|
|
|
@ -1,27 +1,30 @@
|
|||
(ns taoensso.timbre.tools.logging
|
||||
"clojure.tools.logging.impl/Logger implementation.
|
||||
|
||||
The tools.logging API has some significant limits that native Timbre does not.
|
||||
Only use Timbre through tools.logging if you absolutely must (e.g. you're
|
||||
Please note that the tools.logging API has some significant limits
|
||||
that native Timbre does not. Would strongly recommend against using
|
||||
Timbre through tools.logging unless you absolutely must (e.g. you're
|
||||
working with a legacy codebase)."
|
||||
|
||||
(:require [clojure.tools.logging]
|
||||
[taoensso.encore :as enc]
|
||||
[taoensso.timbre :as timbre]))
|
||||
|
||||
(deftype Logger [logger-ns]
|
||||
clojure.tools.logging.impl/Logger
|
||||
|
||||
;; Limitations: no support for explicit config, or ns filtering
|
||||
(enabled? [_ level] (timbre/log? level))
|
||||
(enabled? [_ level]
|
||||
;; No support for explicit config, nor ns filtering:
|
||||
(timbre/log? level))
|
||||
|
||||
;; Limitations inline
|
||||
(write! [_ level throwable message]
|
||||
(let [config timbre/*config* ; No support for explicit config
|
||||
?ns-str nil ; No support
|
||||
?file nil ; ''
|
||||
?line nil ; ''
|
||||
msg-type :p ; No support for pre-msg raw args
|
||||
]
|
||||
(timbre/log1-fn config level ?ns-str ?file ?line msg-type [message] nil))))
|
||||
(timbre/log! level :p
|
||||
[message] ; No support for pre-msg raw args
|
||||
{:config timbre/*config* ; No support for explicit config
|
||||
:?ns-str nil ; Not provided by tools.logging API
|
||||
:?file nil ; ''
|
||||
:?line nil ; ''
|
||||
:?err throwable})))
|
||||
|
||||
(deftype LoggerFactory []
|
||||
clojure.tools.logging.impl/LoggerFactory
|
||||
|
|
Loading…
Reference in New Issue