mirror of https://github.com/status-im/timbre.git
Update official appenders
This commit is contained in:
parent
17c6986087
commit
014faa7bab
|
@ -49,7 +49,7 @@
|
|||
#+clj (force hostname_) #+clj " "
|
||||
(str/upper-case (name level))
|
||||
" [" (or ?ns-str "?ns") "] - " (force msg_)
|
||||
(when-let [err (force ?err_)] (str "\n" (stacktrace err))))))
|
||||
(when-let [err (force ?err_)] (str "\n" (stacktrace err opts))))))
|
||||
|
||||
(declare default-err default-out ensure-spit-dir-exists!)
|
||||
|
||||
|
@ -149,7 +149,10 @@
|
|||
(infof "Hello %s" "world :-)"))
|
||||
|
||||
(enc/defonce* ^:dynamic *config* example-config)
|
||||
(defmacro with-config [config & body] `(binding [*config* ~config] ~@body))
|
||||
(defmacro with-config [config & body] `(binding [*config* ~config] ~@body))
|
||||
(defmacro with-merged-config [config & body]
|
||||
`(binding [*config* (enc/nested-merge *config* ~config)] ~@body))
|
||||
|
||||
(defn swap-config! [f]
|
||||
#+cljs (set! *config* (f *config*))
|
||||
#+clj (alter-var-root #'*config* f))
|
||||
|
@ -165,7 +168,7 @@
|
|||
|
||||
;;;; Levels
|
||||
|
||||
(def ^:private ordered-levels [:trace :debug :info :warn :error :fatal :report])
|
||||
(def ordered-levels [:trace :debug :info :warn :error :fatal :report])
|
||||
(def ^:private scored-levels (zipmap ordered-levels (next (range))))
|
||||
(def ^:private valid-level
|
||||
(let [valid-level-set (set ordered-levels)]
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
{:author "Peter Taoussanis"}
|
||||
(:require [taoensso.carmine :as car]
|
||||
[taoensso.nippy :as nippy]
|
||||
[taoensso.timbre :as timbre]))
|
||||
[taoensso.timbre :as timbre]
|
||||
[taoensso.encore :as enc :refer (have have?)]))
|
||||
|
||||
(defn- sha48
|
||||
"Truncated 160bit SHA hash (48bit Long). Redis can store small collections of
|
||||
|
@ -15,51 +16,56 @@
|
|||
|
||||
(comment (sha48 {:key "I'm gonna get hashed!"}))
|
||||
|
||||
(defn default-keyfn [level] {:pre [(string? level)]}
|
||||
(format "carmine:timbre:default:%s" level))
|
||||
(defn default-keyfn [level] {:pre [(have? string? level)]}
|
||||
(str "carmine:timbre:default:" level))
|
||||
|
||||
(defn make-carmine-appender
|
||||
"Alpha - subject to change!
|
||||
Returns a Carmine Redis appender:
|
||||
* All raw logging args are preserved in serialized form (even Throwables!).
|
||||
* Only the most recent instance of each unique entry is kept (hash fn used
|
||||
(defn make-appender
|
||||
"Returns a Carmine Redis appender (experimental, subject to change):
|
||||
* All raw logging args are preserved in serialized form (even Throwables!).
|
||||
* Only the most recent instance of each unique entry is kept (hash fn used
|
||||
to determine uniqueness is configurable).
|
||||
* Configurable number of entries to keep per logging level.
|
||||
* Log is just a value: a vector of Clojure maps: query+manipulate with
|
||||
standard seq fns: group-by hostname, sort/filter by ns & severity, explore
|
||||
exception stacktraces, filter by raw arguments, etc. Datomic and `core.logic`
|
||||
also offer interesting opportunities here.
|
||||
* Configurable number of entries to keep per logging level.
|
||||
* Log is just a value: a vector of Clojure maps: query+manipulate with
|
||||
standard seq fns: group-by hostname, sort/filter by ns & severity, explore
|
||||
exception stacktraces, filter by raw arguments, etc. Datomic and `core.logic`
|
||||
also offer interesting opportunities here.
|
||||
|
||||
See accompanying `query-entries` fn to return deserialized log entries."
|
||||
[& [appender-opts {:keys [conn-opts keyfn args-hash-fn nentries-by-level]
|
||||
:or {keyfn default-keyfn
|
||||
args-hash-fn timbre/default-args-hash-fn
|
||||
nentries-by-level {:trace 50
|
||||
:debug 50
|
||||
:info 50
|
||||
:warn 100
|
||||
:error 100
|
||||
:fatal 100
|
||||
:report 100}}
|
||||
:as opts}]]
|
||||
{:pre [(string? (keyfn "test"))
|
||||
(every? #(contains? nentries-by-level %) timbre/levels-ordered)
|
||||
(every? #(and (integer? %) (<= 0 % 100000)) (vals nentries-by-level))]}
|
||||
[& [appender-config
|
||||
{:keys [conn-opts keyfn data-hash-fn nentries-by-level]
|
||||
:or {keyfn default-keyfn
|
||||
data-hash-fn timbre/default-data-hash-fn
|
||||
nentries-by-level {:trace 50
|
||||
:debug 50
|
||||
:info 50
|
||||
:warn 100
|
||||
:error 100
|
||||
:fatal 100
|
||||
:report 100}}
|
||||
:as make-config}]]
|
||||
{:pre [(have? string? (keyfn "test"))
|
||||
(have? [:ks>= timbre/ordered-levels] nentries-by-level)
|
||||
(have? [:and integer? #(<= 0 % 100000)] :in (vals nentries-by-level))]}
|
||||
|
||||
(let [default-appender-opts {:enabled? true :min-level nil}]
|
||||
(merge default-appender-opts appender-opts
|
||||
(let [default-appender-config {:enabled? true :min-level nil}]
|
||||
(merge default-appender-config appender-config
|
||||
{:fn
|
||||
(fn [{:keys [level instant] :as apfn-args}]
|
||||
(let [entry-hash (sha48 (args-hash-fn apfn-args))
|
||||
entry (select-keys apfn-args [:hostname :ns :args :throwable
|
||||
:profile-stats])
|
||||
(fn [data]
|
||||
(let [{:keys [level instant]} data
|
||||
entry-hash (sha48 (data-hash-fn data))
|
||||
entry {:?ns-str (:?ns-str data)
|
||||
:hostname (force (:hostname_ data))
|
||||
:vargs (force (:vargs_ data))
|
||||
:?err (force (:?err_ data))
|
||||
:profile-stats (:profile-stats data)}
|
||||
|
||||
k-zset (keyfn (name level))
|
||||
k-hash (str k-zset ":entries")
|
||||
udt (.getTime ^java.util.Date instant) ; Use as zscore
|
||||
nmax-entries (nentries-by-level level)]
|
||||
|
||||
(when (> nmax-entries 0)
|
||||
(car/wcar (or conn-opts (:conn opts)) ; :conn is Deprecated
|
||||
(car/wcar conn-opts
|
||||
(binding [nippy/*final-freeze-fallback* nippy/freeze-fallback-as-str]
|
||||
(car/hset k-hash entry-hash entry))
|
||||
(car/zadd k-zset udt entry-hash)
|
||||
|
@ -91,7 +97,7 @@
|
|||
maps. Normal sequence fns can be used to query/transform entries. Datomic and
|
||||
core.logic are also useful!"
|
||||
[conn-opts level & [n asc? keyfn]]
|
||||
{:pre [(or (nil? n) (and (integer? n) (<= 1 n 100000)))]}
|
||||
{:pre [(have? [:or nil? [:and integer? #(<= 1 % 100000)]] n)]}
|
||||
(let [keyfn (or keyfn default-keyfn)
|
||||
k-zset (keyfn (name level))
|
||||
k-hash (str k-zset ":entries")
|
||||
|
@ -125,9 +131,8 @@
|
|||
;;;; Dev/tests
|
||||
|
||||
(comment
|
||||
(timbre/log {:timestamp-pattern "yyyy-MMM-dd HH:mm:ss ZZ"
|
||||
:appenders {:carmine (make-carmine-appender)}}
|
||||
:info "Hello1" "Hello2")
|
||||
(timbre/with-merged-config {:appenders {:carmine (make-appender)}}
|
||||
(timbre/info "Hello1" "Hello2"))
|
||||
|
||||
(car/wcar {} (car/keys (default-keyfn "*")))
|
||||
(count (car/wcar {} (car/hgetall (default-keyfn "info:entries"))))
|
||||
|
|
|
@ -3,13 +3,8 @@
|
|||
{:author "Peter Taoussanis"}
|
||||
(:require [clojure.string :as str]
|
||||
[postal.core :as postal]
|
||||
[taoensso.timbre :as timbre]))
|
||||
|
||||
(defn- str-trunc [^String s max-len]
|
||||
(if (<= (.length s) max-len) s
|
||||
(.substring s 0 max-len)))
|
||||
|
||||
(comment (str-trunc "Hello this is a long string" 5))
|
||||
[taoensso.timbre :as timbre]
|
||||
[taoensso.encore :as enc :refer (have have?)]))
|
||||
|
||||
(defn make-postal-appender
|
||||
"Returns a Postal email appender.
|
||||
|
@ -20,31 +15,32 @@
|
|||
{:postal-config
|
||||
^{:host \"mail.isp.net\" :user \"jsmith\" :pass \"sekrat!!1\"}
|
||||
{:from \"Bob's logger <me@draines.com>\" :to \"foo@example.com\"}})"
|
||||
[& [appender-opts {:keys [postal-config subject-len body-fn]
|
||||
:or {subject-len 150
|
||||
body-fn (fn [output] [{:type "text/plain; charset=utf-8"
|
||||
:content output}])}}]]
|
||||
|
||||
(let [default-appender-opts
|
||||
[& [appender-config make-config]]
|
||||
(let [{:keys [postal-config subject-len body-fn]
|
||||
:or {subject-len 150
|
||||
body-fn (fn [output] [{:type "text/plain; charset=utf-8"
|
||||
:content output}])}}
|
||||
make-config
|
||||
|
||||
default-appender-config
|
||||
{:enabled? true
|
||||
:min-level :warn
|
||||
:async? true ; Slow!
|
||||
:rate-limit [5 (* 1000 60 2)] ; 5 calls / 2 mins
|
||||
;; TODO These opts are deprecated!
|
||||
:fmt-output-opts {:no-fonts? true} ; Disable ANSI-escaped stuff
|
||||
}]
|
||||
:rate-limit [[5 (enc/ms :mins 2)]
|
||||
[50 (enc/ms :hours 24)]]}]
|
||||
|
||||
(merge default-appender-opts appender-opts
|
||||
(merge default-appender-config appender-config
|
||||
{:fn
|
||||
(fn [{:keys [ap-config output]}]
|
||||
(when-let [postal-config (or postal-config (:postal ap-config))]
|
||||
(postal/send-message
|
||||
(assoc postal-config
|
||||
:subject (-> (str output)
|
||||
(str/trim)
|
||||
(str-trunc subject-len)
|
||||
(str/replace #"\s+" " "))
|
||||
:body (body-fn output)))))})))
|
||||
|
||||
(def postal-appender "DEPRECATED: Use `make-postal-appender` instead."
|
||||
(make-postal-appender))
|
||||
(fn [data]
|
||||
(let [{:keys [output-fn appender-opts]} data
|
||||
{:keys [no-fonts?]} appender-opts]
|
||||
(when-let [postal-config (or postal-config (:postal appender-opts))]
|
||||
(let [output (str (output-fn data {:stacktrace-fonts {}}))]
|
||||
(postal/send-message
|
||||
(assoc postal-config
|
||||
:subject (-> output
|
||||
(str/trim)
|
||||
(str/replace #"\s+" " ")
|
||||
(enc/substr 0 subject-len))
|
||||
:body (body-fn output)))))))})))
|
||||
|
|
Loading…
Reference in New Issue