Utilities and DSL for logging on top of Timbre with support for Riemann, Logstash, and more.
If you just want to get going, here is a minimal working example on how to start logging events.
- Add `active-logger` and `active-clojure` to your `deps.edn`:
{:deps {de.active-group/active-clojure {:mvn/version "0.35.0"} de.active-group/active-logger {:git/url "https://github.com/active-group/active-logger" :sha "d53a0a55211ec6a8aed0e3315e5dc7679f0f3f3e"}}}
- Define the configuration to use and initialize the logging backend.
(ns my.app (:require [active.clojure.config :as active-config] [active.clojure.logger.event :as event-logger] [active.clojure.logger.config.timbre :as timbre-config])) (def config-map {:timbre-config {:level :debug ;; Log everything that is at least a :debug message. :appenders {;; Print messages to stdout/stderr. :println '(println) ;; Write messages to a file. :spit '(spit "/tmp/my-app.log") ;; Submit messages to a logstash instance. :logstash '(logstash "localhost" 4660)}}}) (def schema (active-config/schema "Configuration schema." timbre-config/timbre-config-section)) (def config (active-config/make-configuration schema [] config-map)) ;; Initialize the event-logger. (-> config (active-config/section-subconfig timbre-config/timbre-config-section) timbre-config/configure-events-logging event-logger/set-global-log-events-config!)
- Start logging some events:
(ns my.app (:require ... [active.clojure.logger.event :as event-logger])) (event-logger/log-event! :info "We are live!")
active-logger
is intended to be used alongside =active-clojure= and follows
the same naming scheme (all active-logger
namespaces can be found under
active.clojure.logger
).
There are two basic ways to do logging with active-logger
: Effectful and
monadic.
In general, both of theses options are available for each logging function in
active-logger
.
Effectful logging refers to logging functions that immediately execute.
Usually they are signified by a bang (!
) at the end of the var’s name
(i. e. active.clojure.logger.event/log-event!
).
In any non-monadic execution context, use these functions for logging,
metrics, etc.
Monadic logging refers to logging functions that can be used to formulate the intent on logging at this location when executing a monadic program. The log function will only be executed when the monadic program is run.
Monadic in this context means programs defined using active.clojure.monad
.
(ns my.ns
(:require [active.clojure.config :as active-config]
[active.clojure.logger.config.timbre :as timbre-config]
[active.clojure.logger.event :as event-logger]
[active.clojure.monad :as monad :refer [monadic]]))
;; NOTE: Initialize as shown in TL;DR section.
;; Effectful logging
(let [res (+ 2 2)]
(event-logger/log-event! :trace (str "res =" res))
res)
;; 2020-07-11 15:19:02.659 host INFO [my.ns] TRACE - res = 4
;; => 4
;; Monadic logging
(def prog (monadic [res (monad/return 4)]
(event-logger/log-event :trace (str "res =" res))
(monad/return 4)))
(monad/run-free-reader-state-exception
event-logger/log-events-command-config
prog)
;; 2020-07-11 15:19:02.659 host INFO [my.ns] TRACE - res = 4
;; => 4
active-logger
includes several different entities that can be logged.
Events are reports of things that the system did that may be of interest
for later perusal by system administrator in case of failures or by
developers.
Each event carries a namespace saying where the event came from, and a
level that specifies how “important” the event is.
Functions to log events can be found in active.clojure.logger.event
.
Metrics can be used to log metrics for specified parts of your system.
Functions to log events can be found in active.clojure.logger.metric
.
Timed metrics can be used to log timing characteristics specified parts of
your system.
Functions to log events can be found in active.clojure.logger.timed-metric
.
State changes are for monitoring the live operation of a system.
They announce for a certain system component its state, its service.
Functions to log events can be found in active.clojure.logger.state-change
.
active-logger
comes with two basic configuration sections: Timbre and Riemann.
For more information on active.clojure.config
, refer to =active-clojure=’s documentation on the topic.
In general, to provide a configuration means to supply a map that contains
only keys and values according to some schema defined as a
active.clojure.config/schema
and consumed by
active.clojure.config/make-configuration
.
There are lots of configuration options to define how the event logger should behave. For a full list of options, refer to the respective sources.
Here, we will cover the most important options:
default: :debug
The minimum level a message must have to be printed.
Possible values are #{:trace :debug :info :warn :error :fatal :report}
.
default: {:println (println)}
Defines how messages are printed (stdout
, to a file, …).
An appender spec is a list starting with one of
{spit, rotor, logstash, println}
,
followed by keyword parameters corresponding to the respective appender.
Multiple appenders can be configured and active at the same time. A full example of an appender configuration might look like this:
{:appenders {:split (spit {:fname "/tmp/app.log"})
:riemann (riemann {:host "localhost"
:port 5555})
:println (println)}}
Specifies an appender that writes to a file, specified via the :fname
setting.
Example: {:spit (spit {:fname "my.log"})}
Specifies an appender that writes to a file and rotates the file when it reaches a given file size. It accepts the following settings:
option | description | default |
---|---|---|
:path | Path to log file. file, historical versions are suffixed with a 3-digit index. | "./timbre-rotor.log" |
:max-size | Maximum size of a log file in bytes. Log files are rotated when they exceed this size. | 1.048.576 bytes (1~MB) |
:backlog | Number of rotated logs to keep. | 5 |
Example:
{:rotor (rotor {:path "/tmp/project.log"
:max-size 1073741824
:backlog 999})}
Specifies an appender that will print regular log entries to stdout, errors to stderr.
Example: {:println (println)}
Specifies an appender that writes to a Logstash instance.
It takes two arguments: the host name, and the port number of the Logstash instance.
Example: {:logstash (logstash "localhost" 4660)}
Specifies an appender that writes to a Riemann instance. It accepts the following settings:
option | description | default |
---|---|---|
:host | The host Riemann is served on. | “localhost” |
:port | The host Riemann is listening on. | 5555 |
Example
{:riemann (riemann {:host "localhost"
:port 5555})}
It is possible to ignore specific namespaces in the log-output.
ns-blacklist
’s value it a sequence of glob-patterns.
Matches will be ignored.
Example: {:ns-blacklist ["my.project.internal.*"]}
Converse of ns-blacklist
: All specified patterns are included in the log
output, everything else is ignored.
Example: {:ns-whitelist ["nothing.else.matters"]}
Section containing three settings related to how timestamps are formatted in logs:
option | description |
---|---|
:pattern | Pattern for the timestamp (see SimpleDateFormat) |
:locale | This is an IETF BCP 47 language tag string specifying the locale such as "de-DE" or "en-US" or :jvm-default . |
:timezone | This is an ID for the time zone relative to which log entry dates should formatted. This can be a full name such as "Germany/Berlin" , or a custom ID such as "GMT-8:00" . The value may also be :jvm-default for the default time zone, and :utc for UTC. |
Here are the configuration settings for Riemann. They happen in the
:riemann
section:
option | description | default |
---|---|---|
:host | String specifying the host where Riemann runs. | "127.0.0.1 |
:port | Port where Riemann runs. | 5555 |
:tls? | Specifies whether the communication with Riemann should use TLS. It can be true or false | false |
:key | If :tls? is true, use the specified TLS key-file. | - |
:cert | If :tls? is true, use the specified TSL cert-file. | - |
:ca-cert | If :tls? is true, use the specified TSL CA cert-file. | - |
Copyright © 2020 Active Group GmbH
This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0.
This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version, with the GNU Classpath Exception which is available at https://www.gnu.org/software/classpath/license.html.