blackwater

0.0.8


Pretty logging for SQL queries in JDBC for Clojure

dependencies

org.clojure/clojure
1.5.1
clj-time
0.6.0
robert/hooke
1.3.0
org.clojure/java.jdbc
0.3.0-alpha4
korma
0.3.0-RC5
myguidingstar/clansi
1.3.0



(this space intentionally left almost blank)
 
(ns black.water.jdbc
  (:require [clojure.java.jdbc :as j]
            [robert.hooke :refer [add-hook]]
            [clojure.java.jdbc.sql :as s]
            [clansi.core :refer :all]
            [black.water.log :refer [log-sql]]
            [clj-time.core :as time]))
(def extract-transaction? #'j/extract-transaction?)

Hook for c.j.j query, destructures sql from arguments and times the run-time, sending the results to the log fn.

(defn query-hook
  [f & args]
  (let [start (time/now)
        result (apply f args)
        end (time/now)
        time-taken (time/in-millis (time/interval start end))]
    (log-sql (first (second args)) time-taken)
    result))

Hook for c.j.j execute!

(defn execute-hook
  [f & args]
  (let [start (time/now)
        result (apply f args)
        end (time/now)
        time-taken (time/in-millis (time/interval start end))]
    (log-sql (clojure.string/join " | " (second args)) time-taken)
    result))

Hook for c.j.j insert!

(defn insert-hook
  [f & args]
  (let [start (time/now)
        [db table & options] args
        [transaction? maps-or-cols-and-values-etc] (extract-transaction? options)
        stmts (apply s/insert table maps-or-cols-and-values-etc)
        result (apply f args)
        end (time/now)
        time-taken (time/in-millis (time/interval start end))]
    (log-sql (clojure.string/join " | " (first stmts)) time-taken)
    result))

decorate c.j.j/query, wraps the fn var.

(defn decorate-query!
  []
  (add-hook #'j/query #'query-hook))

decorate c.j.j/insert!, wraps the fn var.

(defn decorate-insert!
  []
  (add-hook #'j/insert! #'insert-hook))

decorate c.j.j/execute!, wraps the fn var.

(defn decorate-execute!
  []
  (add-hook #'j/execute! #'execute-hook))

Hooks into clojure.java.jdbc to log queries, inserts, and execute

(defn decorate-cjj!
  []
  (decorate-query!)
  (decorate-insert!)
  (decorate-execute!))
 
(ns black.water.korma
  (:require [clojure.java.jdbc :as j]
            [robert.hooke :refer [add-hook]]
            [korma.db :as kdb]
            [korma.core :as kc]
            [clansi.core :refer :all]
            [black.water.log :refer [log-sql]]
            [clj-time.core :as time]))

Hook for korma, mercifully the library has a universal, singular function where all queries eventually end up. <3

(defn korma-hook
  [f & args]
  (let [start (time/now)
        result (apply f args)
        end (time/now)
        time-taken (time/in-millis (time/interval start end))]
    (log-sql (:sql-str (first args)) time-taken)
    result))

Hooks into Korma to log SQL that gets executed.

(defn decorate-korma!
  []
  (add-hook #'kdb/exec-sql #'korma-hook))
 
(ns black.water.log
  (:require [clansi.core :refer :all]
            [clj-time.core :as time]))

Color global variables, rebind as thou wilt.

(def sql-color :green)
(def time-color :red)
(def logga nil)
(defn set-logger! [fun]
  (alter-var-root
   (var logga)
   (fn [f]
     fun)))
(defn sanitize [sql]
  (let [single-line (apply str (replace {\newline " "} sql))]
    (clojure.string/replace
     single-line #" {2,}"
                  " ")))

Given the sql string and the milliseconds it took to execute, print a (possibly) colorized readout of the string and the millis.

(defn log-sql
  [sql millis]
  (let [clean-sql (sanitize sql)
        formatted (str (style clean-sql sql-color)
                       "| took:"
                       (style millis time-color)
                       "ms")]
    (if (and logga (fn? logga))
      (logga clean-sql millis)
      (println formatted))))