mirror of https://github.com/status-im/timbre.git
Level checks hk, fix compile-time logging level (prepor)
This commit is contained in:
parent
b21d5c3d6c
commit
e0a9a08b6b
|
@ -43,13 +43,11 @@
|
||||||
(comment (stacktrace (Exception. "foo") nil {}))
|
(comment (stacktrace (Exception. "foo") nil {}))
|
||||||
|
|
||||||
;;;; Logging levels
|
;;;; Logging levels
|
||||||
;; Level precendence: compile-time > dynamic > atom
|
|
||||||
|
|
||||||
(def level-compile-time
|
(def level-compile-time
|
||||||
"Constant, compile-time logging level determined by the `TIMBRE_LOG_LEVEL`
|
"Constant, compile-time logging level determined by the `TIMBRE_LOG_LEVEL`
|
||||||
environment variable. When set, overrules dynamically-configurable logging
|
environment variable. When set, overrules dynamically-configurable logging
|
||||||
level as a performance optimization (e.g. for use in performance sensitive
|
level as a performance optimization."
|
||||||
production environments)."
|
|
||||||
(keyword (System/getenv "TIMBRE_LOG_LEVEL")))
|
(keyword (System/getenv "TIMBRE_LOG_LEVEL")))
|
||||||
|
|
||||||
(def ^:dynamic *level-dynamic* nil)
|
(def ^:dynamic *level-dynamic* nil)
|
||||||
|
@ -63,28 +61,22 @@
|
||||||
;;;
|
;;;
|
||||||
|
|
||||||
(def levels-ordered [:trace :debug :info :warn :error :fatal :report])
|
(def levels-ordered [:trace :debug :info :warn :error :fatal :report])
|
||||||
(def ^:private levels-scored (assoc (zipmap levels-ordered (next (range))) nil 0))
|
(def levels-scored (zipmap levels-ordered (next (range))))
|
||||||
|
|
||||||
(defn error-level? [level] (boolean (#{:error :fatal} level))) ; For appenders, etc.
|
|
||||||
|
|
||||||
|
(defn- level-error? [level] (boolean (#{:error :fatal} level)))
|
||||||
(defn- level-checked-score [level]
|
(defn- level-checked-score [level]
|
||||||
(or (levels-scored level)
|
(or (when (nil? level) 0) ; < any valid level
|
||||||
|
(levels-scored level)
|
||||||
(throw (Exception. (format "Invalid logging level: %s" level)))))
|
(throw (Exception. (format "Invalid logging level: %s" level)))))
|
||||||
|
|
||||||
(def ^:private levels-compare (memoize (fn [x y] (- (level-checked-score x)
|
(def ^:private levels-compare (memoize (fn [x y] (- (level-checked-score x)
|
||||||
(level-checked-score y)))))
|
(level-checked-score y)))))
|
||||||
|
|
||||||
(declare config)
|
(defn level-sufficient? "Precendence: compile-time > dynamic > config > atom."
|
||||||
;; Used in macros, must be public:
|
[level config] (<= 0 (levels-compare level (or level-compile-time
|
||||||
(defn level-sufficient? [level ; & [config] ; Deprecated
|
*level-dynamic*
|
||||||
]
|
(:current-level config)
|
||||||
(>= (levels-compare level
|
@level-atom))))
|
||||||
(or level-compile-time
|
|
||||||
*level-dynamic*
|
|
||||||
;; Deprecate config-specified level:
|
|
||||||
;;(:current-level (or config @config)) ; Don't need compile here
|
|
||||||
(:current-level @config) ; DEPRECATED, here for backwards comp
|
|
||||||
@level-atom)) 0))
|
|
||||||
|
|
||||||
;;;; Default configuration and appenders
|
;;;; Default configuration and appenders
|
||||||
|
|
||||||
|
@ -136,7 +128,10 @@
|
||||||
The `example-config` code contains further settings and details.
|
The `example-config` code contains further settings and details.
|
||||||
See also `set-config!`, `merge-config!`, `set-level!`."
|
See also `set-config!`, `merge-config!`, `set-level!`."
|
||||||
|
|
||||||
{;;; Control log filtering by namespace patterns (e.g. ["my-app.*"]).
|
{;; Prefer `level-atom` to in-config level when possible:
|
||||||
|
;; :current-logging-level :debug
|
||||||
|
|
||||||
|
;;; Control log filtering by namespace patterns (e.g. ["my-app.*"]).
|
||||||
;;; Useful for turning off logging in noisy libraries, etc.
|
;;; Useful for turning off logging in noisy libraries, etc.
|
||||||
:ns-whitelist []
|
:ns-whitelist []
|
||||||
:ns-blacklist []
|
:ns-blacklist []
|
||||||
|
@ -342,15 +337,14 @@
|
||||||
re-pattern (re-find (str ns)) boolean))
|
re-pattern (re-find (str ns)) boolean))
|
||||||
|
|
||||||
(def compile-config ; Used in macros, must be public
|
(def compile-config ; Used in macros, must be public
|
||||||
"Returns {:appenders-juxt {<level> <wrapped-juxt or nil>}
|
"Implementation detail.
|
||||||
:ns-filter (fn relevant-ns? [ns])}."
|
Returns {:appenders-juxt {<level> <wrapped-juxt or nil>}
|
||||||
|
:ns-filter (fn relevant-ns? [ns])}."
|
||||||
(memoize
|
(memoize
|
||||||
;; Careful. The presence of fns actually means that inline config's won't
|
;; Careful. The presence of fns means that inline config's won't correctly
|
||||||
;; actually be identified as samey. In practice not a major (?) problem
|
;; be identified as samey. In practice not a major (?) problem since configs
|
||||||
;; since configs will usually be assigned to a var for which we have proper
|
;; 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
|
||||||
|
@ -372,26 +366,18 @@
|
||||||
(or (empty? ns-blacklist)
|
(or (empty? ns-blacklist)
|
||||||
(not-any? (partial ns-match? ns) ns-blacklist)))))))})))
|
(not-any? (partial ns-match? ns) ns-blacklist)))))))})))
|
||||||
|
|
||||||
(comment (compile-config example-config))
|
(comment (compile-config example-config)
|
||||||
|
(compile-config nil))
|
||||||
|
|
||||||
;;;; Logging macros
|
;;;; Logging macros
|
||||||
|
|
||||||
(defmacro logging-enabled?
|
(defn ns-unfiltered? [config & [ns]] ((:ns-filter (compile-config config))
|
||||||
"Returns true iff current logging level is sufficient and current namespace
|
(or ns *ns*)))
|
||||||
unfiltered. The namespace test is runtime, the logging-level test compile-time
|
|
||||||
iff a compile-time logging level was specified."
|
|
||||||
[level & [config]]
|
|
||||||
(if level-compile-time
|
|
||||||
(when (level-sufficient? level)
|
|
||||||
`(let [ns-filter# (:ns-filter (compile-config (or ~config @config)))]
|
|
||||||
(ns-filter# ~(str *ns*))))
|
|
||||||
`(and (level-sufficient? ~level)
|
|
||||||
(let [ns-filter# (:ns-filter (compile-config (or ~config @config)))]
|
|
||||||
(ns-filter# ~(str *ns*))))))
|
|
||||||
|
|
||||||
(comment (def compile-time-level :info)
|
(defn logging-enabled? "For 3rd-party utils, etc."
|
||||||
(def compile-time-level nil)
|
[level] (let [config' @config]
|
||||||
(macroexpand-1 '(logging-enabled? :debug)))
|
(and (level-sufficient? level config')
|
||||||
|
(ns-unfiltered? config'))))
|
||||||
|
|
||||||
(defn send-to-appenders! "Implementation detail."
|
(defn send-to-appenders! "Implementation detail."
|
||||||
[;; Args provided by both Timbre, tools.logging:
|
[;; Args provided by both Timbre, tools.logging:
|
||||||
|
@ -407,7 +393,7 @@
|
||||||
:file file ; No tools.logging support
|
:file file ; No tools.logging support
|
||||||
:line line ; No tools.logging support
|
:line line ; No tools.logging support
|
||||||
:level level
|
:level level
|
||||||
:error? (error-level? level)
|
:error? (level-error? level)
|
||||||
:args log-vargs ; No tools.logging support
|
:args log-vargs ; No tools.logging support
|
||||||
:throwable throwable
|
:throwable throwable
|
||||||
:message message ; Timbre: nil, tools.logging: nil or string
|
:message message ; Timbre: nil, tools.logging: nil or string
|
||||||
|
@ -420,32 +406,40 @@
|
||||||
[base-appender-args msg-type config level & log-args])}
|
[base-appender-args msg-type config level & log-args])}
|
||||||
[base-appender-args msg-type & [s1 s2 :as sigs]]
|
[base-appender-args msg-type & [s1 s2 :as sigs]]
|
||||||
{:pre [(#{:nil :print-str :format} msg-type)]}
|
{:pre [(#{:nil :print-str :format} msg-type)]}
|
||||||
`(let [;;; Support [level & log-args], [config level & log-args] sigs:
|
;; Compile-time:
|
||||||
s1# ~s1
|
(when (or (nil? level-compile-time)
|
||||||
default-config?# (or (keyword? s1#) (nil? s1#))
|
(let [level (cond (levels-scored s1) s1
|
||||||
config# (if default-config?# @config s1#)
|
(levels-scored s2) s2)]
|
||||||
level# (if default-config?# s1# ~s2)]
|
(or (nil? level) ; Also needs to be compile-time
|
||||||
|
(level-sufficient? level nil))))
|
||||||
(when (logging-enabled? level# config#)
|
;; Runtime:
|
||||||
(when-let [juxt-fn# (get-in (compile-config config#)
|
`(let [;;; Support [level & log-args], [config level & log-args] sigs:
|
||||||
[:appenders-juxt level#])]
|
s1# ~s1
|
||||||
(let [[x1# & xn# :as xs#] (if default-config?#
|
default-config?# (levels-scored s1#)
|
||||||
(vector ~@(next sigs))
|
config# (if default-config?# @config s1#)
|
||||||
(vector ~@(nnext sigs)))
|
level# (if default-config?# s1# ~s2)]
|
||||||
has-throwable?# (instance? Throwable x1#)
|
;; (println "DEBUG: Runtime level check")
|
||||||
log-vargs# (vec (if has-throwable?# xn# xs#))]
|
(when (and (level-sufficient? level# config#)
|
||||||
(send-to-appenders!
|
(ns-unfiltered? config#))
|
||||||
level#
|
(when-let [juxt-fn# (get-in (compile-config config#)
|
||||||
~base-appender-args
|
[:appenders-juxt level#])]
|
||||||
log-vargs#
|
(let [[x1# & xn# :as xs#] (if default-config?#
|
||||||
~(str *ns*)
|
(vector ~@(next sigs))
|
||||||
(when has-throwable?# x1#)
|
(vector ~@(nnext sigs)))
|
||||||
nil ; Timbre generates msg only after middleware
|
has-throwable?# (instance? Throwable x1#)
|
||||||
juxt-fn#
|
log-vargs# (vec (if has-throwable?# xn# xs#))]
|
||||||
~msg-type
|
(send-to-appenders!
|
||||||
(let [file# ~*file*] (when (not= file# "NO_SOURCE_PATH") file#))
|
level#
|
||||||
;; TODO Waiting on http://dev.clojure.org/jira/browse/CLJ-865:
|
~base-appender-args
|
||||||
~(:line (meta &form))))))))
|
log-vargs#
|
||||||
|
~(str *ns*)
|
||||||
|
(when has-throwable?# x1#)
|
||||||
|
nil ; Timbre generates msg only after middleware
|
||||||
|
juxt-fn#
|
||||||
|
~msg-type
|
||||||
|
(let [file# ~*file*] (when (not= file# "NO_SOURCE_PATH") file#))
|
||||||
|
;; TODO Waiting on http://dev.clojure.org/jira/browse/CLJ-865:
|
||||||
|
~(:line (meta &form)))))))))
|
||||||
|
|
||||||
(defmacro log
|
(defmacro log
|
||||||
"Logs using print-style args. Takes optional logging config (defaults to
|
"Logs using print-style args. Takes optional logging config (defaults to
|
||||||
|
@ -585,4 +579,13 @@
|
||||||
{:min-level :error :enabled? true
|
{:min-level :error :enabled? true
|
||||||
:fmt-output-opts {:nofonts? true}
|
:fmt-output-opts {:nofonts? true}
|
||||||
:fn (fn [{:keys [output]}] (str-println output))}}})
|
:fn (fn [{:keys [output]}] (str-println output))}}})
|
||||||
(log :report (Exception. "Oh noes") "Hello")))
|
(log :report (Exception. "Oh noes") "Hello"))
|
||||||
|
|
||||||
|
;; compile-time level (enabled log* debug println)
|
||||||
|
(def level-compile-time :warn)
|
||||||
|
(debug "hello")
|
||||||
|
|
||||||
|
(log :info "hello") ; Discarded at compile-time
|
||||||
|
(log {} :info) ; Discarded at compile-time
|
||||||
|
(log (or :info) "hello") ; Discarded at runtime
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue