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