Skip to content


Folders and files

Last commit message
Last commit date

Latest commit


Repository files navigation


Logging macros which delegate to a specific logging implementation, selected at runtime when the namespace is first loaded.


Lastest stable release is 1.3.0

CLI/deps.edn dependency information:

org.clojure/tools.logging {:mvn/version "1.3.0"}


[org.clojure/tools.logging "1.3.0"]




Latest API Documentation

Logging occurs with the log macro, or the level-specific convenience macros (e.g., debug, debugf). Only when the specified logging level is enabled will the message arguments be evaluated and the underlying logging implementation be invoked. By default, that invocation will occur via an agent when inside a running STM transaction.

Namespacing of log entries

Unless otherwise specified, the current namespace (as identified by *ns*) will be used as the "logger name" when interacting with logging implementations. Most logging implementations allow for varying configuration by logger name.

Note: You should configure your logging implementation to display the logger name that was passed to it. If instead the logging implementation performs stack-inspection you'll see some ugly and unhelpful text in your logs.

Redirecting output to logs

You can redirect all java writes of System.out and System.err to the log system by calling log-capture!. To bind *out* and *err* to the log system invoke with-logs. In both cases a logger name must be provided in lieu of using *ns*.


NOTE: Logging configuration (e.g., setting of logging levels, formatting) is specific to the underlying logging implementation, and is out of scope for this library.

Selecting a logging implementation

To control which logging implementation is used, set the system property to the fully-qualified name of a no-arg function that returns an instance of There are a number of factory functions provided in the namespace.

Leiningen example:

:jvm-opts [""]

If the system property is unset, an implementation will be automatically chosen based on whichever of the following implementations is successfully loaded first:

  1. SLF4J
  2. Apache Commons Logging
  3. Log4J 2
  4. Log4J
  5. java.util.logging

The above approach is problematic given that applications often inadvertently pull in multiple logging implementations as transitive dependencies. As such, it is strongly advised that you set the system property.


A simple Log4j2 configuration:

status = warn
monitorInterval = 5

appender.console.type = Console = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %date %level %logger %message%n%throwable

rootLogger.level = info
rootLogger.appenderRef.stdout.ref = STDOUT

Note: The above pattern explicitly uses %throwable so that clojure.lang.ExceptionInfo exceptions will be printed with their data maps. If either %xThrowable (the default) or %rThrowable is used, the data maps will not be printed.


When logging an ex-info exception, why isn't the data map printed?

This is likely because the logging implementation is printing the contents of Throwable.getMessage(), which returns just the message arg to ex-info.

Logging implementations that print the contents of toString() or use Throwable.printStackTrace(...) will end up printing the data map.


  • Chris Dean
  • Phil Hagelberg
  • Richard Newman
  • Sean Corfield
  • Timothy Pratley


Copyright © Rich Hickey, Alex Taggart, and contributors

Licensed under the EPL. (See the file epl.html.)