On Jul 23, 2014, at 7:11 PM, Jonah Benton <jo...@jonah.com> wrote:
> Sean Corfield has a great example of writing a log4j logging backend in 
> clojure:
> 
> http://corfield.org/blog/post.cfm/real-world-clojure-logging

Thanx for the referral. That made me go back and look at what that code has 
evolved into today... Despite the copyright date, we haven't actually touched 
this code for well over a year now!

One thing we decided to do was move just the dbappender.clj to a separate file 
and AOT that, minimizing the code that the compiler might transitively drag in. 
Then we lein install the logging appender and depend on it from our main 
project.

The delay / require / resolve construct seems a bit of a nasty hack so feedback 
on how to achieve that more elegantly is welcome.

We also isolated the hooks into that main project as two logging calls: one 
which writes structured data to MongoDB and one which writes flat data to MySQL:

;; copyright (c) 2012-2014 world singles llc
;;
;; custom log appender that writes (non-DEBUG) log data to the log table

(ns worldsingles.logging.dbappender
  (:import org.apache.log4j.Level
           org.apache.log4j.spi.LoggingEvent)
  (:gen-class :name worldsingles.logging.DBLogger
              :extends org.apache.log4j.AppenderSkeleton))

(def ^:private resolve-log-structured-data
  "Dynamically resolve worldsingles.logging.core/log-structured-data.
   We use delay to ensure we only require / resolve once."
  (delay
   (do
     (require 'worldsingles.logging.core)
     (resolve (symbol "worldsingles.logging.core/log-structured-data")))))

(def ^:private resolve-log-table-data
  "Dynamically resolve worldsingles.logging.core/log-table-data.
   We use delay to ensure we only require / resolve once."
  (delay
   (do
     (require 'worldsingles.logging.core)
     (resolve (symbol "worldsingles.logging.core/log-table-data")))))

;; implement void AppenderSkeleton.append(LoggingEvent event)
(defn -append
  "Append non-DEBUG events to MySQL and/or MongoDB as appropriate."
  [_ ^LoggingEvent event]
  (when (.isGreaterOrEqual (.getLevel event) Level/INFO) 
    (let [msg (.getMessage event)]
      (@resolve-log-structured-data msg)
      (when (and (map? msg) (= (:logtype msg) "action"))
        (@resolve-log-table-data msg)))))

;; implement void Appender.close()
(defn -close [_])

;; implement boolean Appender.requiresLayout()
(defn -requiresLayout [_] false)

Sean Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/

"Perfection is the enemy of the good."
-- Gustave Flaubert, French realist novelist (1821-1880)



Attachment: signature.asc
Description: Message signed with OpenPGP using GPGMail

Reply via email to