timbre/README.md

360 lines
14 KiB
Markdown
Raw Normal View History

2016-01-14 05:17:22 +00:00
<a href="https://www.taoensso.com" title="More stuff by @ptaoussanis at www.taoensso.com">
2016-01-14 07:18:33 +00:00
<img src="https://www.taoensso.com/taoensso-open-source.png" alt="Taoensso open-source" width="400"/></a>
2016-01-14 05:17:22 +00:00
**[CHANGELOG]** | [API] | current [Break Version]:
```clojure
2017-04-15 11:09:53 +00:00
[com.taoensso/timbre "4.10.0"] ; Please check CHANGELOG for details
```
2016-06-17 14:15:14 +00:00
> Please consider helping to [support my continued open-source Clojure/Script work]?
>
> Even small contributions can add up + make a big difference to help sustain my time writing, maintaining, and supporting Timbre and other Clojure/Script libraries. **Thank you!**
>
> \- Peter Taoussanis
2016-03-10 07:10:01 +00:00
2016-01-14 05:17:22 +00:00
# Timbre
## A pure Clojure/Script logging library
2012-07-13 10:37:40 +00:00
2016-06-17 14:15:14 +00:00
Java logging is a Kafkaesque mess of complexity that buys you _nothing_. It can be comically hard to get even the simplest logging working, and it just gets worse at scale.
2015-05-26 05:43:22 +00:00
2016-06-17 14:15:14 +00:00
Timbre offers an **all Clojure/Script** alternative that's fast, deeply flexible, easy to configure, and that **works out the box**. No XML.
Supports optional interop with [tools.logging](https://github.com/ptaoussanis/timbre/blob/master/src/taoensso/timbre/tools/logging.clj) and [log4j/logback/slf4j](https://github.com/fzakaria/slf4j-timbre).
Happy hacking!
2016-01-14 05:17:22 +00:00
## Features
2016-06-17 14:15:14 +00:00
* Full **Clojure** + **ClojureScript** support (v4+).
* No XML or properties files. **A single, simple config map**, and you're set.
* Simple, flexible **fn appender model** with **middleware**.
* **Great performance** at any scale.
* Filter logging by levels, **namespace whitelist/blacklist patterns**, and more.
* **Zero overhead** with **complete Clj+Cljs elision** for compile-time level/ns filters.
* Useful built-in appenders for **out-the-box** Clj+Cljs logging.
* Powerful, easy-to-configure **rate limits** and **async logging**.
* [Logs as Clojure values][] (v3+).
* Small, simple, cross-platform codebase.
2014-04-03 10:06:45 +00:00
## 3rd-party tools, appenders, etc.
2015-12-22 06:17:13 +00:00
Link | Description
------------------------ | -----------------------------------------------------
[@fzakaria/slf4j-timbre] | Route log4j/logback/sfl4j log output to Timbre
2016-06-17 14:15:14 +00:00
[@palletops/log-config] | Library to help manage Timbre logging config
2015-12-22 06:17:13 +00:00
Your link here? | **PR's welcome!**
2014-04-03 10:06:45 +00:00
2013-06-01 12:41:07 +00:00
## Getting started
2016-01-14 05:17:22 +00:00
Add the necessary dependency to your project:
```clojure
2017-04-15 11:09:53 +00:00
[com.taoensso/timbre "4.10.0"]
2016-01-14 05:17:22 +00:00
```
2016-01-14 05:17:22 +00:00
And setup your namespace imports:
```clojure
2016-01-14 05:17:22 +00:00
(ns my-clj-ns ; Clojure namespace
(:require
[taoensso.timbre :as timbre
:refer [log trace debug info warn error fatal report
2015-06-13 12:25:30 +00:00
logf tracef debugf infof warnf errorf fatalf reportf
spy get-env]]))
2016-01-14 05:17:22 +00:00
(ns my-cljs-ns ; ; ClojureScript namespace
(:require
[taoensso.timbre :as timbre
:refer-macros [log trace debug info warn error fatal report
2015-06-13 12:25:30 +00:00
logf tracef debugf infof warnf errorf fatalf reportf
spy get-env]]))
```
2016-06-17 14:15:14 +00:00
> You can also call `(timbre/refer-timbre)` to configure Clj ns referrals **automatically**.
2015-05-26 05:43:22 +00:00
2012-11-04 16:43:55 +00:00
### Logging
2015-05-29 05:37:52 +00:00
By default, Timbre gives you basic `println` and `js/console` (v4+) output at a `:debug` log level:
```clojure
2013-11-30 13:19:56 +00:00
(info "This will print") => nil
2015-06-13 12:25:30 +00:00
%> 15-Jun-13 19:18:33 localhost INFO [my-app.core] - This will print
2013-11-30 13:19:56 +00:00
(spy :info (* 5 4 3 2 1)) => 120
2015-06-13 12:25:30 +00:00
%> 15-Jun-13 19:19:13 localhost INFO [my-app.core] - (* 5 4 3 2 1) => 120
(defn my-mult [x y] (info "Lexical env:" (get-env)) (* x y)) => #'my-mult
(my-mult 4 7) => 28
%> 15-Jun-13 19:21:53 localhost INFO [my-app.core] - Lexical env: {x 4, y 7}
2015-05-26 14:43:28 +00:00
(trace "This won't print due to insufficient log level") => nil
```
2016-01-30 03:42:50 +00:00
First-argument exceptions generate a nicely cleaned-up stack trace using [io.aviso.exception][] (Clj only):
```clojure
(info (Exception. "Oh noes") "arg1" "arg2")
2015-06-13 12:25:30 +00:00
%> 15-Jun-13 19:22:55 localhost INFO [my-app.core] - arg1 arg2
2018-10-26 11:38:24 +00:00
java.lang.Exception: Oh noes
2015-06-13 12:25:30 +00:00
<Stacktrace>
```
2016-01-14 05:17:22 +00:00
Other utils include: `log-errors`, `log-and-rethrow-errors`, `logged-future`, and `handle-uncaught-jvm-exceptions!` (please see the [API] for details).
2015-09-28 12:03:11 +00:00
#### Disabling stacktrace colors
ANSI colors are enabled by default for stacktraces. To turn these off (e.g. for log files or emails), you can add the following entry to your top-level config **or** individual appender map/s:
```clojure
:output-fn (partial timbre/default-output-fn {:stacktrace-fonts {}})
```
2016-06-17 14:15:14 +00:00
And/or you can set the `TIMBRE_DEFAULT_STACKTRACE_FONTS` environment variable (supports edn).
2016-07-19 04:42:03 +00:00
### Data flow
Timbre's inherently a very simple design, no magic. It's just Clojure data and functions:
1. Unfiltered logging calls generate a **data map**: `{:level _ :?ns-str _ ...}`
2. The resulting data map passes through any **middleware fns**, `(fn [data]) -> ?data`
3. The resulting data map is sent to all **appender fns**, `(fn [data]) -> ?effects`
### Configuration
2016-07-19 04:42:03 +00:00
This is the biggest win over Java logging IMO.
**All** of Timbre's behaviour is controlled through a single, simple Clojure map.
2015-05-26 05:43:22 +00:00
2016-02-27 02:30:50 +00:00
> See `timbre/example-config` for Timbre's default config map
2013-11-30 13:19:56 +00:00
```clojure
(def example-config
2016-02-27 02:30:50 +00:00
"An example Timbre v4 config map.
2015-05-26 05:43:22 +00:00
APPENDERS
An appender is a map with keys:
:min-level ; Level keyword, or nil (=> no minimum level)
:enabled? ;
:async? ; Dispatch using agent? Useful for slow appenders (clj only)
2015-05-26 05:43:22 +00:00
:rate-limit ; [[ncalls-limit window-ms] <...>], or nil
:output-fn ; Optional override for inherited (fn [data]) -> string
:timestamp-opts ; Optional override for inherited {:pattern _ :locale _ :timezone _} (clj only)
2016-06-10 04:43:44 +00:00
:ns-whitelist ; Optional, stacks with active config's whitelist
:ns-blacklist ; Optional, stacks with active config's blacklist
:fn ; (fn [data]) -> side effects, with keys described below
2015-05-26 05:43:22 +00:00
An appender's fn takes a single data map with keys:
:config ; Entire config map (this map, etc.)
2015-05-26 14:43:28 +00:00
:appender-id ; Id of appender currently dispatching
:appender ; Entire map of appender currently dispatching
2015-05-26 05:43:22 +00:00
:instant ; Platform date (java.util.Date or js/Date)
:level ; Keyword
2015-05-26 14:43:28 +00:00
:error-level? ; Is level e/o #{:error :fatal}?
2016-02-27 02:30:50 +00:00
:?ns-str ; String, or nil
:?file ; String, or nil
2015-05-26 05:43:22 +00:00
:?line ; Integer, or nil ; Waiting on CLJ-865
:?err ; First-arg platform error, or nil
:vargs ; Vector of raw args
:output_ ; Forceable - final formatted output string created
; by calling (output-fn <this-data-map>)
:msg_ ; Forceable - args as a string
:timestamp_ ; Forceable - string (clj only)
:hostname_ ; Forceable - string (clj only)
:output-fn ; (fn [data]) -> formatted output string
; (see `default-output-fn` for details)
:context ; *context* value at log time (see `with-context`)
2015-05-26 05:43:22 +00:00
**NB** - any keys not specifically documented here should be
considered private / subject to change without notice.
2015-05-26 05:43:22 +00:00
MIDDLEWARE
Middleware are simple (fn [data]) -> ?data fns (applied left->right) that
transform the data map dispatched to appender fns. If any middleware
returns nil, NO dispatch will occur (i.e. the event will be filtered).
2015-05-26 05:43:22 +00:00
The `example-config` source code contains further settings and details.
2013-11-30 13:19:56 +00:00
See also `set-config!`, `merge-config!`, `set-level!`."
2015-05-26 07:28:07 +00:00
{:level :debug ; e/o #{:trace :debug :info :warn :error :fatal :report}
;; Control log filtering by namespaces/patterns. Useful for turning off
;; logging in noisy libraries, etc.:
2015-05-26 15:40:56 +00:00
:ns-whitelist [] #_["my-app.foo-ns"]
:ns-blacklist [] #_["taoensso.*"]
2015-05-26 07:28:07 +00:00
:middleware [] ; (fns [data]) -> ?data, applied left->right
;; Clj only:
:timestamp-opts default-timestamp-opts ; {:pattern _ :locale _ :timezone _}
:output-fn default-output-fn ; (fn [data]) -> string
2015-05-26 07:28:07 +00:00
:appenders
2016-02-27 02:30:50 +00:00
{;; The standard println appender:
;; :println (println-appender {:stream :auto})
:an-example-custom-println-appender
;; Inline appender definition (just a map):
{:enabled? true
:async? false
:min-level nil
:rate-limit [[1 250] [10 5000]] ; 1/250ms, 10/5s
:output-fn :inherit
:fn ; Appender's (fn [data]) -> side effects
(fn [data]
2016-06-17 14:15:14 +00:00
(let [{:keys [output_]} data
formatted-output-str (force output_)]
2016-02-27 02:30:50 +00:00
(println formatted-output-str)))}}})
2012-07-03 09:30:50 +00:00
```
2013-11-30 13:19:56 +00:00
A few things to note:
2016-06-17 14:15:14 +00:00
2016-01-14 05:17:22 +00:00
* Appenders are _trivial_ to write & configure - **they're just fns**. It's Timbre's job to dispatch useful args to appenders when appropriate, it's their job to do something interesting with them.
* Being 'just fns', appenders have basically limitless potential: write to your database, send a message over the network, check some other state (e.g. environment config) before making a choice, etc.
2015-05-29 05:37:52 +00:00
#### Log levels and ns filters
2015-05-26 14:43:28 +00:00
The **log level** may be set:
2016-06-17 14:15:14 +00:00
* At compile-time: (`TIMBRE_LEVEL` environment variable).
* Statically using: `timbre/set-level!`/`timbre/merge-level!`.
* Dynamically using: `timbre/with-level`.
2015-05-26 11:15:28 +00:00
2015-05-29 05:37:52 +00:00
The **ns filters** may be set:
2016-06-17 14:15:14 +00:00
* At compile-time: (`TIMBRE_NS_WHITELIST`, `TIMBRE_NS_BLACKLIST` env vars).
* Statically using: `timbre/set-config!`/`timbre/merge-config!`.
* Dynamically using: `timbre/with-config`.
2015-05-29 05:37:52 +00:00
2015-07-29 06:42:19 +00:00
There are also variants of the core logging macros that take an **explicit config arg**:
2016-06-17 14:15:14 +00:00
2015-07-29 06:42:19 +00:00
```clojure
(timbre/log* <config-map> <level> <& args>) ; or
(timbre/logf* <config-map> <level> <& args>)
```
2013-11-30 10:03:04 +00:00
2015-05-29 05:37:52 +00:00
Logging calls excluded by a compile-time option (e.g. during Cljs compilation) will be **entirely elided from your codebase**, e.g.:
2016-06-17 14:15:14 +00:00
2015-05-29 05:37:52 +00:00
```bash
#!/bin/bash
# edn values welcome:
export TIMBRE_LEVEL=':warn' # Elide all lower logging calls
export TIMBRE_NS_WHITELIST='["my-app.*"]' # Elide all other ns logging calls
export TIMBRE_NS_BLACKLIST='["my-app.foo" "my-app.bar.*"]'
lein cljsbuild once # Compile js with appropriate logging calls excluded
lein uberjar # Compile jar ''
```
2013-06-01 12:41:07 +00:00
### Built-in appenders
#### Basic file appender
```clojure
;; (:require [taoensso.timbre.appenders.core :as appenders]) ; Add to ns
(timbre/merge-config!
{:appenders {:spit (appenders/spit-appender {:fname "/path/my-file.log"})}})
;; (timbre/merge-config! {:appenders {:spit {:enabled? false}}} ; To disable
;; (timbre/merge-config! {:appenders {:spit nil}} ; To remove entirely
```
2016-01-14 05:17:22 +00:00
#### Redis ([Carmine]) appender (v3+)
```clojure
2016-01-14 05:17:22 +00:00
;; [com.taoensso/carmine <latest-version>] ; Add to project.clj deps
;; (:require [taoensso.timbre.appenders (carmine :as car-appender)]) ; Add to ns
(timbre/merge-config! {:appenders {:carmine (car-appender/carmine-appender)}})
```
This gives us a high-performance Redis appender:
2016-06-17 14:15:14 +00:00
* **All raw logging args are preserved** in serialized form (even errors).
* Configurable number of entries to keep per log level.
* Only the most recent instance of each **unique entry** is kept.
* Resulting **log is just a Clojure value**: a vector of log entries (maps).
Clojure has a rich selection of built-in and 3rd party tools for querying values like this.
See also `car-appender/query-entries`.
2016-01-14 05:17:22 +00:00
#### Email ([Postal]) appender
```clojure
2016-01-14 05:17:22 +00:00
;; [com.draines/postal <latest-version>] ; Add to project.clj deps
2013-05-15 09:41:41 +00:00
;; (:require [taoensso.timbre.appenders (postal :as postal-appender)]) ; Add to ns
2015-05-26 05:43:22 +00:00
(timbre/merge-config!
{:appenders
{:postal
(postal-appender/postal-appender
^{:host "mail.isp.net" :user "jsmith" :pass "sekrat!!1"}
{:from "me@draines.com" :to "foo@example.com"})}})
```
2013-11-30 13:19:56 +00:00
#### Other included appenders
2016-06-17 14:15:14 +00:00
A number of 3rd-party appenders are included out-the-box [here](https://github.com/ptaoussanis/timbre/tree/master/src/taoensso/timbre/appenders/3rd_party). **Please see the relevant docstring for details**. Thanks goes to the respective authors!
2016-06-17 14:15:14 +00:00
Just give me a shout if you've got an appender you'd like to have added.
## Profiling
2016-07-11 08:12:37 +00:00
As of v4.6.0, Timbre's profiling features have been enhanced and exported to a dedicated profiling library called [Tufte].
2016-07-11 08:12:37 +00:00
Timbre's old profiling features **will be kept for backwards compatibility** throughout v4.x, but future development will be focused exclusively on Tufte.
2016-07-11 08:12:37 +00:00
Tufte has out-the-box support for integration with Timbre, and [migration](https://github.com/ptaoussanis/tufte#how-does-tufte-compare-to-the-profiling-in-timbre) is usually simple.
2016-07-11 08:12:37 +00:00
Sorry for the inconvenience!
2016-01-14 05:17:22 +00:00
## This project supports the ![ClojureWerkz-logo] goals
2013-06-01 12:41:07 +00:00
2016-06-17 14:15:14 +00:00
[ClojureWerkz] is a growing collection of open-source, **batteries-included Clojure libraries** that emphasise modern targets, great documentation, and thorough testing.
2012-06-16 06:53:38 +00:00
2016-01-14 05:17:22 +00:00
## Contacting me / contributions
2012-11-05 17:48:42 +00:00
2016-01-14 05:17:22 +00:00
Please use the project's [GitHub issues page] for all questions, ideas, etc. **Pull requests welcome**. See the project's [GitHub contributors page] for a list of contributors.
2014-02-25 07:38:19 +00:00
2016-01-14 05:17:22 +00:00
Otherwise, you can reach me at [Taoensso.com]. Happy hacking!
2016-01-14 05:17:22 +00:00
\- [Peter Taoussanis]
## License
2016-01-14 05:17:22 +00:00
Distributed under the [EPL v1.0] \(same as Clojure).
Copyright &copy; 2015-2016 [Peter Taoussanis].
2014-02-22 18:32:35 +00:00
2016-01-14 05:17:22 +00:00
<!--- Standard links -->
[Taoensso.com]: https://www.taoensso.com
[Peter Taoussanis]: https://www.taoensso.com
[@ptaoussanis]: https://www.taoensso.com
[More by @ptaoussanis]: https://www.taoensso.com
2015-03-20 08:20:23 +00:00
[Break Version]: https://github.com/ptaoussanis/encore/blob/master/BREAK-VERSIONING.md
2016-06-17 14:15:14 +00:00
[support my continued open-source Clojure/Script work]: http://taoensso.com/clojure/backers
2015-12-22 06:17:13 +00:00
2016-01-14 05:17:22 +00:00
<!--- Standard links (repo specific) -->
[CHANGELOG]: https://github.com/ptaoussanis/timbre/releases
[API]: http://ptaoussanis.github.io/timbre/
[GitHub issues page]: https://github.com/ptaoussanis/timbre/issues
[GitHub contributors page]: https://github.com/ptaoussanis/timbre/graphs/contributors
[EPL v1.0]: https://raw.githubusercontent.com/ptaoussanis/timbre/master/LICENSE
[Hero]: https://raw.githubusercontent.com/ptaoussanis/timbre/master/hero.png "Title"
<!--- Unique links -->
2016-06-17 14:15:14 +00:00
[logging profiler]: #profiling
2016-01-14 05:17:22 +00:00
[Logs as Clojure values]: #redis-carmine-appender-v3
2015-12-22 06:17:13 +00:00
[@palletops/log-config]: https://github.com/palletops/log-config
[@fzakaria/slf4j-timbre]: https://github.com/fzakaria/slf4j-timbre
2016-01-14 05:17:22 +00:00
[io.aviso.exception]: https://github.com/AvisoNovate/pretty
[Carmine]: https://github.com/ptaoussanis/carmine
2016-07-11 08:12:37 +00:00
[Tufte]: https://github.com/ptaoussanis/tufte
2016-01-14 05:17:22 +00:00
[Postal]: https://github.com/drewr/postal
[ClojureWerkz-logo]: https://raw.github.com/clojurewerkz/clojurewerkz.org/master/assets/images/logos/clojurewerkz_long_h_50.png
2016-01-26 13:42:25 +00:00
[ClojureWerkz]: http://clojurewerkz.org/