mirror of
https://github.com/status-im/timbre.git
synced 2025-01-27 12:16:17 +00:00
Added time-format and locale shared-config options.
* Also updated README. Signed-off-by: Peter Taoussanis <p.taoussanis@gmail.com>
This commit is contained in:
parent
5fbbe9bfb5
commit
dde1b89b03
14
README.md
14
README.md
@ -8,7 +8,7 @@ Timbre is an attempt to make **simple logging simple** and more **complex loggin
|
||||
|
||||
## What's In The Box?
|
||||
* Small, uncomplicated **all-Clojure** library.
|
||||
* **Map-based config**: no arcane XML or properties files.
|
||||
* **Super-simple map-based config**: no arcane XML or properties files.
|
||||
* Decent performance (**low overhead**).
|
||||
* Flexible **fn-centric appender model**.
|
||||
* Sensible built-in appenders including simple **email appender**.
|
||||
@ -71,6 +71,15 @@ Easily adjust the current logging level:
|
||||
(timbre/set-level! :warn)
|
||||
```
|
||||
|
||||
And the default instant formatting for log messages:
|
||||
|
||||
```clojure
|
||||
(timbre/set-config! [:shared-appender-config :instant-pattern]
|
||||
"yyyy-MMM-dd HH:mm:ss ZZ")
|
||||
(timbre/set-config! [:shared-appender-config :locale]
|
||||
(java.util.Locale/GERMAN))
|
||||
```
|
||||
|
||||
Enable the standard [Postal](https://github.com/drewr/postal)-based email appender:
|
||||
|
||||
```clojure
|
||||
@ -105,7 +114,8 @@ Writing a custom appender is easy:
|
||||
:enabled? true
|
||||
:async? false
|
||||
:max-message-per-msecs nil ; No rate limiting
|
||||
:fn (fn [{:keys [ap-config level error? instant ns message more] :as args}]
|
||||
:fn (fn [{:keys [ap-config level error? instant instant-formatter
|
||||
ns message more] :as args}]
|
||||
(when-not (:production-mode? ap-config)
|
||||
(apply println instant "Hello world!" message more)))
|
||||
```
|
||||
|
@ -3,23 +3,18 @@
|
||||
{:author "Peter Taoussanis"}
|
||||
(:require [clojure.string :as str]
|
||||
[clj-stacktrace.repl :as stacktrace]
|
||||
[postal.core :as postal]))
|
||||
|
||||
;;;; Appender-fn helpers
|
||||
|
||||
(defn instant-str
|
||||
"2012-May-26 15:26:06:081 +0700"
|
||||
[instant]
|
||||
(format "%1$tY-%1$tb-%1$td %1$tH:%1$tM:%1$tS:%1$tL %1tz" instant))
|
||||
|
||||
(defn prefixed-message
|
||||
"2012-May-26 15:26:06:081 +0700 LEVEL [ns] - message"
|
||||
[level instant ns message]
|
||||
(str (instant-str instant) " " (-> level name str/upper-case)
|
||||
" [" ns "] - " message))
|
||||
[postal.core :as postal])
|
||||
(:import [java.util Date Locale]
|
||||
[java.text SimpleDateFormat]))
|
||||
|
||||
;;;; Default configuration and appenders
|
||||
|
||||
(defn prefixed-message
|
||||
"<formatted-instant> LEVEL [ns] - message"
|
||||
[{:keys [level instant instant-formatter ns message]}]
|
||||
(str (instant-formatter instant) " " (-> level name str/upper-case)
|
||||
" [" ns "] - " message))
|
||||
|
||||
(def config
|
||||
"This map atom controls everything about the way Timbre operates. In
|
||||
particular note the flexibility to add arbitrary appenders.
|
||||
@ -28,7 +23,8 @@
|
||||
:doc, :min-level, :enabled?, :async?, :max-message-per-msecs, :fn?
|
||||
|
||||
An appender's fn takes a single map argument with keys:
|
||||
:ap-config, :level, :error?, :instant, :ns, :message, :more
|
||||
:ap-config, :level, :error?, :instant, :instant-formatter, :ns,
|
||||
:message, :more
|
||||
|
||||
See source code for examples."
|
||||
(atom {:current-level :debug
|
||||
@ -38,36 +34,37 @@
|
||||
{:doc "Prints everything to *out*."
|
||||
:min-level :debug :enabled? false :async? false
|
||||
:max-message-per-msecs nil
|
||||
:fn (fn [{:keys [level instant ns message more]}]
|
||||
(apply println (prefixed-message level instant ns message)
|
||||
more))}
|
||||
:fn (fn [{:keys [level instant ns message more] :as args}]
|
||||
(apply println (prefixed-message args) more))}
|
||||
|
||||
:standard-out-or-err
|
||||
{:doc "Prints to *out* or *err* as appropriate. Enabled by default."
|
||||
:min-level :debug :enabled? true :async? false
|
||||
:max-message-per-msecs nil
|
||||
:fn (fn [{:keys [level error? instant ns message more]}]
|
||||
:fn (fn [{:keys [level error? instant ns message more] :as args}]
|
||||
(binding [*out* (if error? *err* *out*)]
|
||||
(apply println (prefixed-message level instant ns message)
|
||||
more)))}
|
||||
(apply println (prefixed-message args) more)))}
|
||||
|
||||
:postal
|
||||
{:doc (str "Sends an email using com.draines/postal.\n"
|
||||
"Needs :postal config map in :shared-appender-config.")
|
||||
:min-level :error :enabled? false :async? true
|
||||
:max-message-per-msecs (* 60 60 2)
|
||||
:fn (fn [{:keys [ap-config level instant ns message more]}]
|
||||
:fn (fn [{:keys [ap-config level instant ns message more] :as args}]
|
||||
(when-let [postal-config (:postal ap-config)]
|
||||
(postal/send-message
|
||||
(assoc postal-config
|
||||
:subject (prefixed-message level instant ns message)
|
||||
:subject (prefixed-message args)
|
||||
:body (if (seq more) (str/join " " more)
|
||||
"<no additional arguments>")))))}}
|
||||
|
||||
;; Example :postal map:
|
||||
:shared-appender-config
|
||||
{:instant-pattern "yyyy-MMM-dd HH:mm:ss ZZ" ; SimpleDateFormat pattern
|
||||
:locale nil ; A Locale object, or nil
|
||||
;; A Postal message map, or nil.
|
||||
;; ^{:host "mail.isp.net" :user "jsmith" :pass "sekrat!!1"}
|
||||
;; {:from "me@draines.com" :to "foo@example.com"}
|
||||
:shared-appender-config {:postal nil}}))
|
||||
:postal nil}}))
|
||||
|
||||
(defn set-config! [ks val] (swap! config assoc-in ks val))
|
||||
(defn set-level! [level] (set-config! [:current-level] level))
|
||||
@ -83,16 +80,32 @@
|
||||
(defn sufficient-level?
|
||||
[level] (>= (compare-levels level (:current-level @config)) 0))
|
||||
|
||||
;;;; Appender-fn decoration: flood control, async, etc.
|
||||
;;;; Appender-fn decoration
|
||||
|
||||
(defn- make-instant-formatter
|
||||
"Returns unary fn to format an instant using given pattern string and optional
|
||||
locale."
|
||||
[^String pattern ^Locale locale]
|
||||
(let [format (if locale
|
||||
(SimpleDateFormat. pattern locale)
|
||||
(SimpleDateFormat. pattern))]
|
||||
(fn [^Date instant] (.format ^SimpleDateFormat format instant))))
|
||||
|
||||
(comment ((make-instant-formatter "yyyy-MMM-dd" nil) (Date.)))
|
||||
|
||||
(defn- wrap-appender-fn
|
||||
"Wraps compile-time appender fn with additional capabilities controlled by
|
||||
compile-time config."
|
||||
[appender-id {apfn :fn :keys [async? max-message-per-msecs] :as appender}]
|
||||
(->
|
||||
;; Wrap to add shared appender config to args
|
||||
;; Wrap to add compile-time stuff to runtime appender arguments
|
||||
(fn [apfn-args]
|
||||
(apfn (assoc apfn-args :ap-config (@config :shared-appender-config))))
|
||||
(let [{:keys [instant-pattern locale] :as ap-config}
|
||||
(@config :shared-appender-config)]
|
||||
(apfn (assoc apfn-args
|
||||
:ap-config ap-config ; Shared appender config map
|
||||
:instant-formatter
|
||||
(make-instant-formatter instant-pattern locale)))))
|
||||
|
||||
;; Wrap for asynchronicity support
|
||||
((fn [apfn]
|
||||
@ -189,7 +202,7 @@
|
||||
appender-args#
|
||||
{:level level#
|
||||
:error? (>= (compare-levels level# :error) 0)
|
||||
:instant (java.util.Date.)
|
||||
:instant (Date.)
|
||||
:ns (str ~*ns*)
|
||||
:message (if has-throwable?# (or (first xs#) x1#) x1#)
|
||||
:more (if has-throwable?#
|
||||
|
Loading…
x
Reference in New Issue
Block a user