I'm quite a fan of the Clojure programming language. I recently needed to log things in a webserver project I'm writing. I figured, how hard could it be ? Turns out it was more complicated than I thought.

Clojure.tools.logging is not simple

Clojure usually has some notion of simplicity. The logging part is not from the standard library but is part of org.clojure. But its implementation is not easy from an outsider in the Java ecosystem. It basically adds a nice API that wraps the standard loggers in Java.

Dependencies

You need :

  • clojure.tools.logging for the API wrappers
  • org.slf4j/slf4j-api for the Java API
  • ch.qos.logback/logback-classic for a logger implementation (you can use others)

Then, you can configure your logger using logback.xml file. To do that though, you need this file to be in your classpath. So you need to add your resources folder to your sources so that it's included in your classpath.

Like the following :

{:paths ["src"
         ; We include resources here to make it part of the classpath so that
         ; logback.xml logging config file is present and loaded correctly.
         "resources"]
 :deps {org.clojure/clojure {:mvn/version "1.10.3"}

        ;; Logging
        org.slf4j/slf4j-api {:mvn/version "1.7.30"}
        org.clojure/tools.logging {:mvn/version "1.1.0"}

       ; Logger
        ch.qos.logback/logback-classic {:mvn/version "1.2.3"}}}

Logback.xml configuration

You can configure the logging like the following way (in my case). Note that this can be configured very differently, just that the following covers my main use cases.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

This is a simple logger that just prints to stdout (which is nice in containers/CLI applications) and defaults to printing INFO levels.

Conclusion

It's not very difficult to set logging up in Clojure and it is quite powerful! It's also standardized and easy to tap into the existing ecosystem, which is nice.