README.md 5.2 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 33 34 35 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 111 112 113 114 115 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
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:

`no.nsd.envelope {:mvn/version 0.1.0}`

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.

*Note*: If any of your dependencies depends on an older
`slf4j-api` than "1.7.14", there might be problems.


### 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
168 169 170

## License

171
Copyright © 2018 NSD
Kjetil Thuen's avatar
Kjetil Thuen committed
172 173 174

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