README.md 5.44 KB
Newer Older
1 2
# Envelope

Kjetil Thuen's avatar
Kjetil Thuen committed
3
![LogDiffuser](https://gitlab.nsd.no/clojure/envelope/raw/master/log-diffuser.png)
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

`Envelope` is a thin wrapper around
[`taoensso.timbre`](https://github.com/ptaoussanis/timbre) with built in
settings for logging to NSD's ELK stack and transparent interop with various
logging packages. It can be used from Clojure and ClojureScript.


## Value proposition

Choosing and configuring a logging framework on the JVM can be a headache.

Once a framework has been chosen, you need to consider the logging format. At
NSD we use an ELK stack to handle centralized logging, and we have a [common
schema](https://gitlab.nsd.no/nsd-commons/log-schema) defining how the log
entries should look.

This package has everything set up out of the box. No need to struggle with XML
files or letting your third party dependencies dictate what logging framework
to use. Just require `Envelope` and start logging.
Kjetil Thuen's avatar
Kjetil Thuen committed
23 24 25 26


## Usage

27 28 29 30 31 32
First of all; If your project is a library, you probably don't want `Envelope`; Just
use [clojure/tools.logging](https://github.com/clojure/tools.logging) and let
your consumers worry about formatting and appenders and all that jazz.

If your project is an application, add `Envelope` to your dependency graph:

33 34 35
```
[no.nsd.envelope "0.1.0"]
```
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110

And use it like this:

```clojure
(ns no.nsd.your-app
  (:require [no.nsd.envelope :as log))

(defn -main
 [& args]
 (log/init! {:service-name "your-app" :service-version "1.0.0"}
 (log/debug "Hello NSD ELK format")))
```

`Timbre`'s macros `trace`, `debug`, `info`, `warn`, `error`, `fatal`, `report`,
`spy`, and `with-context`  are exposed as top-level macros in `Envelope`.


### Setup

While Envelope will work without any configuration, you will probably want to
at least tell it about the name and version of your application. The `init!`
function takes an optional map with these values, in addition to other things
you might want to tweak.

Any field supported by `Timbre` can be set. Note that setting the `:output-fn`
and `timestamp-opts` fields will not have any effect when `:log-to-elk` is true
(which is the default). In addition to the `Timbre` fields, `Envelope` supports
the following fields:

```clojure
 {; Value for the serviceName field. Default: "Unknown"
  :service-name "my-logging-app"

  ; Value for the serviceVersion field. Default "0.0.0"
  :service-version "1.0.0"

  ; Whether you want to log to ELK. Default is true. When false you will get a simpler,
  ; easy to read text format with colorized stack traces.
  :log-to-elk false

  ; Value for the serviceStack field. Default "development"
  :service-stack "prod"

  ; Same as Tibres :log-level field, but with default value depending on :log-to-elk. If
  ; not set, it will be :info when :log-to-elk is true and :debug when :log-to-elk is false
  :log-level :debug}
```

See the [Timbre
documentation](https://github.com/ptaoussanis/timbre#configuration) for
information about all the fields supported by `Timbre`.

You can change these settings at any time (runtime, no need to restart) by
passing a config map to `merge-config!`.:

```
user> (no.nsd.envelope/init! {:log-to-elk false :level :warn})
nil
user> (no.nsd.envelope/info "Hi?")
nil
user> (no.nsd.envelope/merge-config! {:level :debug})
{:log-to-elk false, :service-name "Unknown", :service-version "0.0.0", :console-time-pattern "HH:mm:ss.SSS", :level :debug}
user> (no.nsd.envelope/info "Hi?")
13:18:50.286 INFO Hi?
nil
user>
```


### Interop with other logging frameworks

If you depend on third party code that use `clojure/tools.logging`, `slf4j`, `jcl`,
`log4j` or `jul` for logging, those log entries will be consumed by `Envelope` and
injected into your log. You don't need to do anything for this to work.

Kjetil Thuen's avatar
Kjetil Thuen committed
111 112 113 114 115
**Note**: Some libraries (datomic peer being one of these) will look at your
dependency graph and try redirect their log output to known log targets they
find there. If you are seeing some components not using `envelope`, try using
`:exclusions` in your dependency graph to remove transient dependencies to
`slf4j`, `logback` and other logging frameworks.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172


### Context

`Timbre`'s `with-context` is exposed as a top-level symbol in `Envelope`. The
preset ELK format will output the `xRequestId` and `thread` fields when
`:x-request-id` or `:thread` are set in the context. The default non-elk
(console) format will print the x-request-id field when present. Consider the
following:

```clojure
(ns no.nsd.your-app
  (:require [no.nsd.envelope :as log))

(defn get-number
  []
  (log/debug "Getting number")
  2)

(defn do-something
  []
  (log/debug "Doing something")
  (+ 2 (get-number)))

(defn start
  []
  (log/debug "App started")
  (log/with-context {:x-request-id "My request-id"
                     :thread       (.getName (Thread/currentThread))}
      (do-something))
  (log/debug "App finished"))

(defn -main
  [& args]
  (log/init!)
  (start!))
```

The above code will produce log entries like this:

```
10:45:13.855 DEBUG App started
10:45:13.856 [My request-id] DEBUG Doing something
10:45:13.857 [My request-id] DEBUG Getting number
10:45:13.857 DEBUG App finished
```

### More fancy usage
If you need to use any of the more esoteric functionality from `Timbre`, you can
just call its functions or macros:

```clojure
(taoensso.timbre/logf :warn "Explicitly using the timbre logf macro")
```

There is no need to add a dependency to `Timbre`, since it is pulled in by
`Envelope`.
Kjetil Thuen's avatar
Kjetil Thuen committed
173 174 175

## License

176
Copyright © 2018 NSD
Kjetil Thuen's avatar
Kjetil Thuen committed
177 178 179

Distributed under the Eclipse Public License either version 1.0 or (at
your option) any later version.