Datahike uses org.replikativ/logging for all logging. This library wraps
taoensso/trove, a lightweight logging facade that lets
you bring your own backend (console, SLF4J/Logback, Timbre, Telemere, or any custom function).
As a library, Datahike does not force any logging implementation on users. By default, trove
logs to stdout via its built-in console backend. Your application can replace this with any
backend (Timbre, SLF4J, etc.) by calling trove/set-log-fn!.
Every log call in Datahike uses a namespaced keyword ID as its first argument, following
the :datahike/component pattern. This enables reliable filtering and analysis:
(require '[replikativ.logging :as log])
;; ID + data map (preferred for variable data)
(log/info :datahike/connect {:config config})
;; ID + message string (for human-readable context)
(log/debug :datahike/writer-closed "Writer thread gracefully closed")
;; ID + message + data map
(log/warn :datahike/tx-queue-pressure "Queue >90% full" {:count n :size size})
Install a log backend via taoensso.trove/set-log-fn!. The function receives
[ns coords level id lazy_] on each log event.
(require '[taoensso.trove :as trove]
'[taoensso.trove.console :as trove-console])
;; Log to stdout at :info level and above
(trove/set-log-fn! (trove-console/get-log-fn {:min-level :info}))
(defn make-stderr-log-fn [min-level]
(let [console-fn (trove-console/get-log-fn {:min-level min-level})]
(fn [ns coords level id lazy_]
(binding [*out* *err*]
(console-fn ns coords level id lazy_)))))
(trove/set-log-fn! (make-stderr-log-fn :info))
(trove/set-log-fn!
(fn [ns coords level id lazy_]
(let [data (force lazy_)]
;; Send to your logging system
(my-logger/log level id data))))
Previous versions of Datahike used taoensso/timbre directly. If you had Timbre configuration
in your application (appenders, level settings, etc.), here is how to migrate.
If you want to keep using Timbre and all its appenders, add com.taoensso/timbre to your own
deps.edn and route Datahike's log output through it:
(require '[taoensso.trove :as trove]
'[taoensso.trove.timbre]) ;; ships with trove
(trove/set-log-fn! (taoensso.trove.timbre/get-log-fn))
All Datahike log events will now flow through your Timbre configuration — appenders, level
filters, and middleware all work as before. Your existing timbre/merge-config! calls continue
to apply.
timbre/set-level!Timbre's global level control is replaced by installing a log function with a :min-level:
;; Before (Timbre)
(timbre/set-level! :warn)
;; After (trove console backend)
(require '[taoensso.trove :as trove]
'[taoensso.trove.console :as trove-console])
(trove/set-log-fn! (trove-console/get-log-fn {:min-level :warn}))
timbre/merge-config! with appendersIf you used custom Timbre appenders (e.g. file rotation, JSON output), you have two options:
Keep Timbre — use the taoensso.trove.timbre backend (see above) and keep your existing
appender configuration unchanged.
Drop Timbre — write a custom log function that does what your appender did. For example, a simple file logger:
(require '[taoensso.trove :as trove])
(import '[java.io FileWriter])
(let [writer (FileWriter. "/var/log/datahike.log" true)]
(trove/set-log-fn!
(fn [ns coords level id lazy_]
(when (>= (.indexOf [:trace :debug :info :warn :error] level)
(.indexOf [:trace :debug :info :warn :error] :info))
(let [{:keys [msg data error]} (force lazy_)]
(locking writer
(.write writer (str (java.time.Instant/now) " " level " " id " " (or msg data) "\n"))
(.flush writer)))))))
Datahike uses the log/raise macro to log an error and throw an ExceptionInfo in one step.
The signature takes any number of message string fragments followed by a data map:
(log/raise "Attribute " attr " is not defined in schema"
{:attribute attr :error :schema/missing})
This logs at :error level (with source coordinates for CLJ-865 workaround) and throws:
(ex-info "Attribute :foo is not defined in schema"
{:attribute :foo :error :schema/missing})
The data map typically contains an :error or :type key describing the error category, plus
contextual keys like :value, :attribute, or :binding.
Contributors should use log/raise for all error paths instead of bare throw.
Can you improve this documentation? These fine people already did:
Timo Kramer, Judith & Christian WeilbachEdit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |