How To Add Logging To A Clojure Project

When deploying a Clojure application in a production environment, it is necessary to have logging enabled to be able to, in case of any failure, track down the problem using the logs later.

Clojure inhertis serveral logging frameworks from Java like Log4j and it has its own Clojure'esque wrapper around Java logging API called clojure.tools.logging.

This HowTo will help you get started with a working “loggable” Clojure project. Though the instructions assume that you're using Leiningen for build automation, it can be applied to any Maven based build too.

Setting Up A New Project

This creates a new empty project:
$ lein new app logger1
Generating a project called logger1 based on the 'app' template.

Now edit project.clj to add required dependencies:
(defproject logger1 "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.4.0"] ;; CHANGE Clojure version to 1.4.0
                 ;; LOGGING DEPS
                 [org.clojure/tools.logging "0.2.4"]
                 [org.slf4j/slf4j-log4j12 "1.7.1"]
                 [log4j/log4j "1.2.17" :exclusions [javax.mail/mail
                                                    javax.jms/jms
                                                    com.sun.jmdk/jmxtools
                                                    com.sun.jmx/jmxri]]]
  :main logger1.core)
Run lein deps inside logger1 directory to fetch the dependencies.

Log4j Configuration

 I'm not getting into the details of this rather lengthy and boring topic. Instead I'll provide you with a working configuration that I use -check out Log4j manual if you feel curious though.

Create a file named log4j.properties in src/ with the following contents:
log4j.rootLogger=DEBUG, stdout, R

log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=./log/logger1.log

log4j.appender.R.MaxFileSize=100KB
log4j.appender.R.MaxBackupIndex=20

log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=[%d][%p][%c] %m%n

Here's a brief description: the logger is told that the log level is DEBUG (line 1) , it should send the output to both stdout (line 1) and a rolling file called logger1.log (lines 3 & 4), it should use a new file when the current reaches 100KB (line 6), it should keep 20 log files (line 7) and it should use a certain pattern when writing log entries (lines 9 & 10). Check out Log4j pattern API for a complete description of directives used on line 10.

Using The Logger

The rest is straight forward. All you need to do is to require or use the clojure.tools.logging library.
;; core.clj
;;
(ns logger1.core
  (:require '[clojure.tools.logging :as log])
  (:gen-class))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (log/info "Right here!"
  (println "Hello, World!"))

Run the application using lein run and check out logger1.log inside ./log directory. It should contain something like [2014-09-21 10:02:31,814][INFO][logger1.core] Right there!
That's it! Your tiny application now has a working logger. Most of the times you will use info, debug, error or warn functions but don't forget to take a look at clojure.tools.logging API to see what's possible beyond that.

Comments

Popular posts from this blog

Variables in GNU Make: Simple and Recursive

Checkmate on Your Terms: A Personal Journey with Correspondence Chess

Firefox profiles: Quickly replicate your settings to any machine