mirror of https://github.com/status-im/timbre.git
Final hk?
This commit is contained in:
parent
6ab9c4ac59
commit
7c969ca0e6
39
CHANGELOG.md
39
CHANGELOG.md
|
@ -1,5 +1,44 @@
|
|||
> This project uses [Break Versioning](https://github.com/ptaoussanis/encore/blob/master/BREAK-VERSIONING.md) as of **Aug 16, 2014**.
|
||||
|
||||
## v4.0.0-beta1 / 2015 May 26
|
||||
|
||||
> This is a **MAJOR** update. Your custom appenders **WILL BREAK**. Your configuration **MIGHT BREAK**. Your call sites should be fine. I've updated all included appenders, but **haven't tested** any 3rd-party appenders.
|
||||
|
||||
* **New**: full **ClojureScript** support, including a default js/console appender [#51]
|
||||
* **New**: support for compile-time ns filtering + elision (both Clj+Cljs)
|
||||
* **New**: support for MDC-like contexts [#42]
|
||||
* **New**: default :println appender has picked up a :stream opt [#49]
|
||||
* **New**: create necessary spit appender paths [#93]
|
||||
* **New**: full-power fn-level `log*` util [#99]
|
||||
* **New**: added a reference appender example [here](https://github.com/ptaoussanis/timbre/blob/master/src/taoensso/timbre/appenders/example_appender.clj)
|
||||
* **Implementation**: modernized + simplified codebase
|
||||
* **Implementation**: significant performance improvements across the board
|
||||
* **Implementation**: use delays to avoid unnecessarily producing unused arg msgs [#71]
|
||||
* **Fix**: auto shutdown agents to prevent slow app shutdown [#61]
|
||||
|
||||
```clojure
|
||||
[com.taoensso/timbre "4.0.0-beta1"]
|
||||
```
|
||||
|
||||
### Migration checklist
|
||||
|
||||
* Removed vars: `timbre/config`, `timbre/level-atom`, `default-fmt-output-fn`
|
||||
* The fn signature for `set-config!` has changed: `[ks val]` -> `[config]`
|
||||
* Middleware now apply left->right, not right->left
|
||||
* Renamed default appender: `:standard-out` -> `:println`
|
||||
* Renamed config opts: `:timestamp-pattern`, `:timestamp-locale` -> `:timestamp-opts {:pattern _ :locale _ :timezone _}`
|
||||
* Appender :rate-limit format has changed: `[ncalls ms]` -> `[[ncalls ms] <...>]`
|
||||
* Renamed appender args: `:ns`->`:?ns-str`, `:file`->`:?file`, `:line`->`:?line`
|
||||
* Appender args now wrapped with delays: `:throwable`->`:?err_`, `:message`->`:msg_`, `:timestamp`->`:timestamp_`, `:hostname`->`:hostname_`, `:args`->`:vargs_`
|
||||
* Appender args removed: `:output`, `:ap-config`
|
||||
* Appender args added: `:output-fn (fn [data])`, `:appender-opts`
|
||||
* `stacktrace` util fn signature changed: `[throwable & [sep fonts]` -> `[err & [opts]]`
|
||||
* All bundles 3rd-party appenders have moved to a new `3rd-party` ns
|
||||
|
||||
Apologies for the hassle in migrating. The changes made here all bring serious benefits (performance, simplicity, future extensibility, cross-platform support) and I'm confident that v4's the last time I'll need to touch the core design. Future work will be focused on polish, stability, and better+more bundled appenders.
|
||||
|
||||
/ Peter Taoussanis
|
||||
|
||||
## v3.4.0 / 2015 Feb 16
|
||||
|
||||
> This should be a **non-breaking** release that only bumps some old dependencies.
|
||||
|
|
69
README.md
69
README.md
|
@ -133,7 +133,6 @@ This is the biggest win over Java logging IMO. Here's `timbre/example-config` (a
|
|||
The `example-config` source code contains further settings and details.
|
||||
See also `set-config!`, `merge-config!`, `set-level!`."
|
||||
|
||||
(merge
|
||||
{:level :debug ; e/o #{:trace :debug :info :warn :error :fatal :report}
|
||||
|
||||
;; Control log filtering by namespaces/patterns. Useful for turning off
|
||||
|
@ -143,69 +142,15 @@ This is the biggest win over Java logging IMO. Here's `timbre/example-config` (a
|
|||
|
||||
:middleware [] ; (fns [data]) -> ?data, applied left->right
|
||||
|
||||
#+clj :timestamp-opts
|
||||
#+clj default-timestamp-opts ; {:pattern _ :locale _ :timezone _}
|
||||
|
||||
:output-fn default-output-fn ; (fn [data]) -> string
|
||||
|
||||
:appenders
|
||||
#+clj
|
||||
{:println ; Appender id
|
||||
;; Appender <map>:
|
||||
{:doc "Prints to (:stream <appender-opts>) IO stream. Enabled by default."
|
||||
:min-level nil :enabled? true :async? false :rate-limit nil
|
||||
|
||||
;; Any custom appender opts:
|
||||
:opts {:stream :auto ; e/o #{:std-err :std-out :auto <stream>}
|
||||
}
|
||||
|
||||
:fn
|
||||
{:simple-println ; Appender id
|
||||
;; Appender definition (just a map):
|
||||
{:min-level nil :enabled? true :async? false
|
||||
:rate-limit [[1 250] [10 5000]] ; 1/250ms, 10/5s
|
||||
:fn ; Appender's fn
|
||||
(fn [data]
|
||||
(let [{:keys [output-fn error? appender-opts]} data
|
||||
{:keys [stream]} appender-opts
|
||||
stream (case stream
|
||||
(nil :auto) (if error? default-err *out*)
|
||||
:std-err default-err
|
||||
:std-out default-out
|
||||
stream)]
|
||||
(binding [*out* stream] (println (output-fn data)))))}
|
||||
|
||||
:spit
|
||||
{:doc "Spits to (:spit-filename <appender-opts>) file."
|
||||
:min-level nil :enabled? false :async? false :rate-limit nil
|
||||
:opts {:spit-filename "timbre-spit.log"}
|
||||
:fn
|
||||
(fn [data]
|
||||
(let [{:keys [output-fn appender-opts]} data
|
||||
{:keys [spit-filename]} appender-opts]
|
||||
(when-let [fname (enc/as-?nblank spit-filename)]
|
||||
(try (ensure-spit-dir-exists! fname)
|
||||
(spit fname (str (output-fn data) "\n") :append true)
|
||||
(catch java.io.IOException _)))))}}
|
||||
|
||||
#+cljs
|
||||
{:console
|
||||
{:doc "Logs to js/console when it exists. Enabled by default."
|
||||
:min-level nil :enabled? true :async? false :rate-limit nil
|
||||
:opts {}
|
||||
:fn
|
||||
(let [have-logger? (and (exists? js/console) (.-log js/console))
|
||||
have-warn-logger? (and have-logger? (.-warn js/console))
|
||||
have-error-logger? (and have-logger? (.-error js/console))
|
||||
adjust-level {:fatal (if have-error-logger? :error :info)
|
||||
:error (if have-error-logger? :error :info)
|
||||
:warn (if have-warn-logger? :warn :info)}]
|
||||
(if-not have-logger?
|
||||
(fn [data] nil)
|
||||
(fn [data]
|
||||
(let [{:keys [level appender-opts output-fn]} data
|
||||
{:keys []} appender-opts
|
||||
output (output-fn data)]
|
||||
|
||||
(case (adjust-level level)
|
||||
:error (.error js/console output)
|
||||
:warn (.warn js/console output)
|
||||
(.log js/console output))))))}}}))
|
||||
(let [{:keys [output-fn]} data]
|
||||
(println (output-fn data))))}}})
|
||||
```
|
||||
|
||||
A few things to note:
|
||||
|
|
|
@ -12,11 +12,6 @@
|
|||
[java.text SimpleDateFormat]
|
||||
[java.io File]))
|
||||
|
||||
;;;; TODO
|
||||
;; - Try ease backward comp, update README, CHANGELOG
|
||||
;; - Document shutdown-agents,
|
||||
;; Ref. https://github.com/ptaoussanis/timbre/pull/100/files
|
||||
|
||||
;;;; Encore version check
|
||||
|
||||
#+clj
|
||||
|
@ -105,7 +100,6 @@
|
|||
The `example-config` source code contains further settings and details.
|
||||
See also `set-config!`, `merge-config!`, `set-level!`."
|
||||
|
||||
(merge
|
||||
{:level :debug ; e/o #{:trace :debug :info :warn :error :fatal :report}
|
||||
|
||||
;; Control log filtering by namespaces/patterns. Useful for turning off
|
||||
|
@ -123,7 +117,7 @@
|
|||
:appenders
|
||||
#+clj
|
||||
{:println ; Appender id
|
||||
;; Appender <map>:
|
||||
;; Appender map:
|
||||
{:doc "Prints to (:stream <appender-opts>) IO stream. Enabled by default."
|
||||
:min-level nil :enabled? true :async? false :rate-limit nil
|
||||
|
||||
|
@ -177,7 +171,7 @@
|
|||
(case (adjust-level level)
|
||||
:error (.error js/console output)
|
||||
:warn (.warn js/console output)
|
||||
(.log js/console output))))))}}}))
|
||||
(.log js/console output))))))}}})
|
||||
|
||||
(comment
|
||||
(set-config! example-config)
|
||||
|
@ -196,7 +190,7 @@
|
|||
(defn merge-config! [m] (swap-config! (fn [old] (enc/nested-merge old m))))
|
||||
|
||||
(defn set-level! [level] (swap-config! (fn [m] (merge m {:level level}))))
|
||||
(defn with-level [level & body]
|
||||
(defmacro with-level [level & body]
|
||||
`(binding [*config* (merge *config* {:level ~level})] ~@body))
|
||||
|
||||
(comment (set-level! :info) *config*)
|
||||
|
@ -205,11 +199,11 @@
|
|||
|
||||
(def ordered-levels [:trace :debug :info :warn :error :fatal :report])
|
||||
(def ^:private scored-levels (zipmap ordered-levels (next (range))))
|
||||
(def ^:private valid-levels (set ordered-levels))
|
||||
(def ^:private valid-level
|
||||
(let [valid-level-set (set ordered-levels)]
|
||||
(fn [level]
|
||||
(or (valid-level-set level)
|
||||
(throw (ex-info (str "Invalid logging level: " level) {:level level}))))))
|
||||
(or (valid-levels level)
|
||||
(throw (ex-info (str "Invalid logging level: " level) {:level level})))))
|
||||
|
||||
(comment (valid-level :info))
|
||||
|
||||
|
@ -220,7 +214,9 @@
|
|||
|
||||
#+clj (defn- env-val [id] (when-let [s (System/getenv id)] (enc/read-edn s)))
|
||||
#+clj (def ^:private compile-time-level
|
||||
(have [:or nil? valid-level] (keyword (env-val "TIMBRE_LEVEL"))))
|
||||
(have [:or nil? valid-level]
|
||||
(keyword (or (env-val "TIMBRE_LEVEL")
|
||||
(env-val "TIMBRE_LOG_LEVEL")))))
|
||||
|
||||
(defn get-active-level [& [config]] (or (:level (or config *config*)) :report))
|
||||
|
||||
|
@ -307,7 +303,7 @@
|
|||
|
||||
(comment (def rf (get-rate-limiter :my-appender [[10 5000]])))
|
||||
|
||||
;;;; Logging core
|
||||
;;;; Internal logging core
|
||||
|
||||
(defn log?
|
||||
"Would Timbre currently log at the given logging level?
|
||||
|
@ -328,14 +324,15 @@
|
|||
|
||||
(declare get-hostname)
|
||||
|
||||
(defn log* "Core fn-level logger. Implementation detail."
|
||||
[config level ?ns-str ?file ?line msg-type vargs_ & [base-data]]
|
||||
(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 (force vargs_)))
|
||||
?err_ (delay (get @vargs*_ 0))
|
||||
vargs_ (delay (get @vargs*_ 1))
|
||||
data (merge base-data *context*
|
||||
data (merge ?base-data *context*
|
||||
{:config config ; Entire config!
|
||||
;; :context *context* ; Extra destructure's a nuisance
|
||||
:instant instant
|
||||
|
@ -352,8 +349,8 @@
|
|||
(when-not (nil? msg-type)
|
||||
(when-let [vargs (have [:or nil? vector?] (force vargs_))]
|
||||
(case msg-type
|
||||
:print (enc/spaced-str vargs)
|
||||
:format (let [[fmt args] (enc/vsplit-first vargs)]
|
||||
:p (enc/spaced-str vargs)
|
||||
:f (let [[fmt args] (enc/vsplit-first vargs)]
|
||||
(enc/format* fmt args))))))
|
||||
?data
|
||||
(reduce ; Apply middleware: data->?data
|
||||
|
@ -418,41 +415,49 @@
|
|||
nil)
|
||||
|
||||
(comment
|
||||
(log* *config* :info nil nil nil :print (delay [(do (println "hi") :x) :y])))
|
||||
(log1-fn *config* :info nil nil nil :p (delay [(do (println "hi") :x) :y]) nil))
|
||||
|
||||
;;;; Logging macros
|
||||
|
||||
(defmacro log "Core macro-level logger."
|
||||
[config level msg-type args & [base-data]]
|
||||
(defmacro log1-macro
|
||||
"Core macro-level logger. Implementation detail!"
|
||||
[config level msg-type args & [?base-data]]
|
||||
|
||||
;; Compile-time elision:
|
||||
(when (or (nil? compile-time-level) (level>= level compile-time-level))
|
||||
(when (or (nil? compile-time-level)
|
||||
(not (valid-levels level)) ; Not a compile-time level
|
||||
(level>= level compile-time-level))
|
||||
|
||||
(when (compile-time-ns-filter (str *ns*))
|
||||
|
||||
(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))]
|
||||
`(log* ~config ~level ~ns-str ~?file ~?line ~msg-type
|
||||
(delay [~@args]) ~base-data)))))
|
||||
`(log1-fn ~config ~level ~ns-str ~?file ~?line ~msg-type
|
||||
(delay [~@args]) ~?base-data)))))
|
||||
|
||||
;;;; API-level stuff
|
||||
|
||||
;;; Log using print-style args
|
||||
(defmacro trace [& args] `(log *config* :trace :print ~args))
|
||||
(defmacro debug [& args] `(log *config* :debug :print ~args))
|
||||
(defmacro info [& args] `(log *config* :info :print ~args))
|
||||
(defmacro warn [& args] `(log *config* :warn :print ~args))
|
||||
(defmacro error [& args] `(log *config* :error :print ~args))
|
||||
(defmacro fatal [& args] `(log *config* :fatal :print ~args))
|
||||
(defmacro report [& args] `(log *config* :report :print ~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))
|
||||
|
||||
;;; Log using format-style args
|
||||
(defmacro tracef [& args] `(log *config* :trace :format ~args))
|
||||
(defmacro debugf [& args] `(log *config* :debug :format ~args))
|
||||
(defmacro infof [& args] `(log *config* :info :format ~args))
|
||||
(defmacro warnf [& args] `(log *config* :warn :format ~args))
|
||||
(defmacro errorf [& args] `(log *config* :error :format ~args))
|
||||
(defmacro fatalf [& args] `(log *config* :fatal :format ~args))
|
||||
(defmacro reportf [& args] `(log *config* :report :format ~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))
|
||||
|
||||
(comment
|
||||
(infof "hello %s" "world")
|
||||
|
@ -485,7 +490,7 @@
|
|||
([config level name expr]
|
||||
`(log-and-rethrow-errors
|
||||
(let [result# ~expr]
|
||||
(log ~config ~level :print [~name "=>" result#])
|
||||
(log* ~config ~level [~name "=>" result#])
|
||||
result#))))
|
||||
|
||||
#+clj
|
||||
|
@ -540,7 +545,7 @@
|
|||
(binding [aviso-ex/*fonts* fonts] (aviso-ex/format-exception err))
|
||||
(aviso-ex/format-exception err)))
|
||||
|
||||
(comment (stacktrace (Exception. "Boo")))
|
||||
(comment (stacktrace (Exception. "Boo") {:stacktrace-fonts {}}))
|
||||
|
||||
#+clj
|
||||
(def ^:private ensure-spit-dir-exists!
|
||||
|
@ -556,9 +561,17 @@
|
|||
`(do (assert (<= 0 ~probability 1) "Probability: 0 <= p <= 1")
|
||||
(when (< (rand) ~probability) ~@body)))
|
||||
|
||||
;;;; Shutdown hook ; Workaround for http://dev.clojure.org/jira/browse/CLJ-124
|
||||
;;;; EXPERIMENTAL shutdown hook
|
||||
;; Workaround for http://dev.clojure.org/jira/browse/CLJ-124
|
||||
|
||||
#+clj
|
||||
(defonce ^:private shutdown-hook
|
||||
(.addShutdownHook (Runtime/getRuntime)
|
||||
(Thread. (fn [] (shutdown-agents)))))
|
||||
|
||||
;;;; Deprecated
|
||||
|
||||
(defn str-println [& xs] (enc/spaced-str xs))
|
||||
(defmacro with-log-level [level & body] `(with-level ~level ~@body))
|
||||
(defmacro with-logging-config [config & body] `(with-config ~config ~@body))
|
||||
(defn logging-enabled? [level compile-time-ns] (log? level (str compile-time-ns)))
|
||||
|
|
|
@ -42,3 +42,7 @@
|
|||
:error (android.util.Log/e ns output)
|
||||
:fatal (android.util.Log/e ns output)
|
||||
:report (android.util.Log/i ns output)))))})))
|
||||
|
||||
;;;; Deprecated
|
||||
|
||||
(def make-logcat-appender make-appender)
|
||||
|
|
|
@ -73,3 +73,7 @@
|
|||
:name "Lazylus Logus"
|
||||
:chan "bob"}}}})
|
||||
(timbre/error "A multiple\nline message\nfor you"))
|
||||
|
||||
;;;; Deprecated
|
||||
|
||||
(def make-irc-appender make-appender)
|
||||
|
|
|
@ -73,3 +73,7 @@
|
|||
(let [default-appender-config {:enabled? true :min-level nil}]
|
||||
(merge default-appender-config appender-config
|
||||
{:fn (make-appender-fn path pattern)})))
|
||||
|
||||
;;;; Deprecated
|
||||
|
||||
(def make-rolling-appender make-appender)
|
||||
|
|
|
@ -35,3 +35,7 @@
|
|||
(zmq/register socket :pollout :pollerr))]
|
||||
(merge default-appender-config appender-config
|
||||
{:fn (make-appender-fn socket poller)})))
|
||||
|
||||
;;;; Deprecated
|
||||
|
||||
(def make-zmq-appender make-appender)
|
||||
|
|
|
@ -144,3 +144,7 @@
|
|||
|
||||
(count (query-entries {} :info 2))
|
||||
(count (query-entries {} :info 2 :asc)))
|
||||
|
||||
;;;; Deprecated
|
||||
|
||||
(def make-carmine-appender make-appender)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
[taoensso.timbre :as timbre]
|
||||
[taoensso.encore :as enc :refer (have have?)]))
|
||||
|
||||
(defn make-postal-appender
|
||||
(defn make-appender
|
||||
"Returns a Postal email appender.
|
||||
A Postal config map can be provided here as an argument, or as a :postal key
|
||||
in :shared-appender-config.
|
||||
|
@ -44,3 +44,7 @@
|
|||
(str/replace #"\s+" " ")
|
||||
(enc/substr 0 subject-len))
|
||||
:body (body-fn output)))))))})))
|
||||
|
||||
;;;; Deprecated
|
||||
|
||||
(def make-postal-appender make-appender)
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
[level id & body]
|
||||
`(let [{result# :result stats# :stats} (with-pdata ~level ~@body)]
|
||||
(when stats#
|
||||
(timbre/log timbre/*config* ~level :format
|
||||
(timbre/log1-macro timbre/*config* ~level :f
|
||||
["Profiling: %s\n%s" (fq-keyword ~id) (format-stats stats#)]
|
||||
{:profile-stats stats#}))
|
||||
result#))
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
?ns-str nil ; No support
|
||||
?file nil ; ''
|
||||
?line nil ; ''
|
||||
msg-type :print ; No support for pre-msg raw args
|
||||
msg-type :p ; No support for pre-msg raw args
|
||||
]
|
||||
(timbre/log* config level ?ns-str ?file ?line msg-type [message]))))
|
||||
(timbre/log1-fn config level ?ns-str ?file ?line msg-type [message]))))
|
||||
|
||||
(deftype LoggerFactory []
|
||||
clojure.tools.logging.impl/LoggerFactory
|
||||
|
|
Loading…
Reference in New Issue