Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Clojure logging API
Clojure CSS JavaScript
Fetching latest commit...
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.

Logger4clj 0.2

Clojure Logging API

A fast, versatile and distinctly-Clojurish logging API.

Available in leiningen via clojars:

  [logger4clj "0.2"]

Read the Logger4clj Manual for an in-depth introduction.

Additionally, API documentation is available under /doc, generated using Codox, however I haven't figured out how to make github serve the pages as html here :(

Features 0.3 (Not Yet Released)

  • Backwards compatibility broken!
  • def-logger now produces a logging-macro instead of a logging-function; s-expression to be logged is not executed unless the minimum log level for all consumers is such that the result of the s-expression will be used
  • logging messages can now have format parameters; the message should be followed by a vector of replacements
  • can now log the originating namespace
  • back-end rewritten using Lamina to simplify the coding of the dataflow from producers to consumers; this will allow an easier implementation of more features from the wishlist

Features 0.2

  • File appender supports time- or size-based rollover
  • File appender can clean up old logs
  • File and console appenders accept numerous 'formatters': xml, yaml, json, clojure or formatted string text
  • file name and line number of log statement now log-able
  • category is now the namespace in which the logger was defined, instead of the logger name

Features 0.1

  • Mostly-pure Clojure and a single source file (requires only clojure.core and JDK6)
  • Loggers may be 'chained/bound together' (see second example below)
  • Log messages are passed to a blocking queue, where separate thread(s) will handle expensive I/O operations
  • No external 'properties' configurations; clojure code externalizes nicely by itself!
  • Different log levels (:trace :debug, :info, :warning, :error, :fatal)
  • Comes with two appenders (file and console), but custom appenders are easy to create

Wish List

  • Expanded documentation
  • clojure/java.jdbc-based database logging appender
  • Message bundles for externalizing messages e.g. (log :error :invalid-parm-error parm)
  • Allow binding with more than one appender per bound logger
  • Allow suppression of loggers that are bound to bound loggers (:suppress tag under bind-logger clause?)
  • new logging statement for allowing the value of an inner expression to be logged and then returned from the logging statement, i.e. for benchmarking
  • abstract the 'logging-level' model into a something configurable and more sophisticated; use traditional logging levels as default
  • custom message handlers to permit logging and transformation of arbitrary EDN data


Basic Example:

In the first example, a logger is created with a file-appender and used to write various log messages to a file. An appender is 'registered' and then the 'with-appender' tells the logger to use that appender. You'll see why these are separate statements later.

    (ns mypackage.myfile
        [logger4clj.appenders :as apps]))

    (def-logger my-logger
      ;; create the appender
      (register-appender :file-appender
        (apps/create-file-appender "/home/johnd/logs/mylog.log"))

      ;; use the appender with my-logger
        [:file-appender :error])

      (my-logger :info "Program is starting...")

      (println (+ 1 1))

      (catch Exception e
        (my-logger :error "An error occurred!" e)))

More Complicated Example:

The following demonstrates a logger being defined in some third-party API and then being 'bound' to a logger defined by the client program.

Note that the def-logger in the second namespace registers two appenders and then binds the API's logger (some-api-logger) to itself, using one of its registered appenders to capture some-api-logger's messages. Following that, it calls 'with-appenders' to use both appenders for itself as well.

file one
    (ns com.some-company.some-api

    ;; just create a plain logger with no appenders, without starting it    
    (def-logger some-api-logger)

    ;; use it
    (defn my-func 
        [x y]
          (/ x (- y 1))
          (catch ArithmeticException e
              (some-api-logger :error "The value of y cannot be 1" e))))

    ;; do other stuff
file two
    (ns com.another-company.some-program
        [com.some-company.some-api :as some-api]
        [logger4clj.appenders :as apps]
        [logger4clj.formatters :as frms]))

    (def-logger my-logger
      (register-appender :console
          ;; add a formatter instead of using default
          :formatter (frms/create-line-formatter 
                        "${ts:HH:mm:ss.SSSZ} -  (${fn}:${ln}) ${msg}${n}"))

      (register-appender :log-file
          ;; format log msgs as XML
          :formatter (frms/create-xml-formatter)))

      ;; use the :log-file appender to write messages from some-api-logger
      ;;   and set the log level to :error for some-api-logger 
      (bind-logger some-api/some-api-logger
        :with-appender [:log-file :error])

      ;; for my-logger, append to both console and the log file
        [:log-file :info]
        [:console :debug])

      ;; don't forget to start the logger - this will start the queue reading
      ;;    threads. You can also stop it if you want, but that's not necessary

    ;; use the logger 
    (my-logger :info "Logger has been initialized and started!")

    ;;the bound-logger (some-api-logger) is now active for logging
    (some-api/my-func 10 1)

    ;; do other stuff

Note that it's possible to chain an arbitary number of loggers together; lower-level loggers may even define their own appenders and start themselves before being bound a client.


Source Copyright © 2013 Joe Kauzlarich. Distributed under the Eclipse Public License, the same as Clojure uses. See the file COPYING.

Something went wrong with that request. Please try again.