Liking cljdoc? Tell your friends :D

Taoensso open source
API | Slack channel | Latest release: v1.2.0 (2026-07-25)

Clj tests Cljs tests Graal tests bb tests

Trove

Modern logging facade for Clojure/Script

Trove is a minimal, modern alternative to tools.logging that supports:

  • Both traditional and structured logging.
  • Both Clojure and ClojureScript.
  • Richer filtering capabilities (by namespace, id, level, data, etc.).
  • Dynamic context for correlating related logs, etc.

It's intended mostly for library authors that want to emit rich logging without forcing their users to adopt any particular backend.

Trove is TINY (0 deps, ~250 loc), fast, and highly flexible.

Why structured logging?

  • Traditional logging outputs strings (messages).
  • Structured logging in contrast outputs data. It retains rich data types and (nested) structures throughout the logging pipeline from logging callsite → filters → middleware → handlers.

A data-oriented pipeline can make a huge difference - supporting easier filtering, transformation, and analysis. It’s also usually faster, since you only pay for serialization if/when you need it. In a lot of cases you can avoid serialization altogether if your final target (DB, etc.) supports the relevant types.

The structured (data-oriented) approach is inherently more flexible, faster, and well suited to the tools and idioms offered by Clojure and ClojureScript.

For end users

If a library you use depends on Trove, you'll automatically get sensible library logging out-the-box (to *out* or the JS console).

This just works - no need for any config, or even a logging library.

But you may prefer to configure Trove to instead funnel logs to your preferred logging backend.

Choose a backend

Trove provides out-the-box support for Telemere, Timbre, μ/log, tools.logging, and SLF4J.

Call trove/set-log-fn! as you like:

(ns my-ns
  (:require
   [taoensso.trove.x] ; x ∈ #{console telemere timbre mulog tools-logging slf4j} (default console)
   [taoensso.trove :as trove]))

(trove/set-log-fn! (taoensso.trove.x/get-log-fn {:bridge-ctx? true/false}))
(trove/set-log-fn! nil) ; To noop all `trove/log!` calls

Use {:bridge-ctx? true} if you'd like to allow library authors to update your backend's native context when relevant. Requires Telemere, Timbre (except on Babashka), μ/log, or SLF4J with an MDC-capable provider.

You can also easily write your own log-fn - see trove/*log-fn* for details.

For library authors

  1. Include the (tiny) dependency in your library deps.
  2. Use trove/log! to make your logging calls.

Trove uses the same map-based logging API as Telemere:

(ns my-ns (:require [taoensso.trove :as trove]))

(trove/log! {:level :info, :id :auth/login, :data {:user-id 1234}, :msg "User logged in!"})

Which expands to roughly:

(when-let [log-fn trove/*log-fn*] ; Chosen backend fn
  (log-fn "my-ns" [line column] :info :auth/login ; Callsite info
    {:msg "User logged in!", :data {:user-id 1234}})) ; Payload

The end user's chosen backend takes care of filtering and output.

What about expensive data?

Structured logging sometimes involves expensive data collection or transformation, e.g.:

(trove/log! {:id ::my-event, :data (expensive) ...})

That's why Trove automatically delays payload values that need runtime evaluation, allowing the backend to apply filtering before paying realization costs. See *log-fn* for payload details.

Dynamic context

A context map may be attached to trove/log! output via trove/*ctx*:

(trove/with-ctx+ {:workflow/step "fetch-page"}
  (trove/log! {:id :ingest/fetched, :data {:n 42}}))

Utils:

log! also takes :ctx and :ctx+ options to replace or update the context for a single call.

Bridging context to the backend (advanced)

The above context belongs to Trove, so affects only trove/log! calls.

Some backends have their own equivalent context, which you can also offer to update if end-users opt-in:

(trove/with-ctx+ {:workflow/step "fetch-page"}
  (trove/with-ctx-bridge ; Merge Trove context into native backend context
    (fetch-page)))

For custom backend authors

Custom backends can add bridge support with trove/add-ctx-bridge.

Funding

You can help support continued work on this project and others, thank you!! 🙏

License

Copyright © 2026 Peter Taoussanis.
Licensed under EPL 1.0 (same as Clojure).

Can you improve this documentation? These fine people already did:
Peter Taoussanis & Michiel Borkent
Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close