   (:require [com.puppetlabs.utils :as utils]
             [com.puppetlabs.http :as pl-http]
             [ring.util.response :as rr]
+            [clojure.string :as s]
             [clojure.tools.logging :as log])
   (:use [metrics.timers :only (timer time!)]
         [metrics.meters :only (meter mark!)]))

  metric."
  [app prefix storage normalize-uri]
  (fn [req]
    (let [metric-root (str (normalize-uri (:uri req)))
          timer-key   [:timers metric-root]]
      (when-not (get-in @storage timer-key)
        (swap! storage assoc-in timer-key (timer [prefix metric-root "service-time"])))

      (time! (get-in @storage timer-key)

             (let [response  (app req)
                   status    (:status response)
                   meter-key [:meters metric-root status]]
               (when-not (get-in @storage meter-key)
                 (swap! storage assoc-in meter-key (meter [prefix metric-root (str status)] "reqs/s")))
               (mark! (get-in @storage meter-key))
               response)))))

(defmacro wrap-with-metrics
  "Ring middleware that will tack performance counters for each URL.

  `storage`: An atom that will be used to hold references to all
  created metrics.

  `normalize-uri`: A function that takes a URI, and returns a string
  or collection of strings. For each string returned, a timer and
  meter will be created if they don't already exist. To have multiple
  URLs share the same timer/meter, `normalize-uri` should return some
  of the same strings for each URL.

  Metric names (and thus, the strings returned by `normalize-uri`
  cannot contain ':', '=', or ',' characters. They will be replaced
  with '_'."
  [app storage normalize-uri]
  `(let [prefix# ~(str *ns*)]
     (wrap-with-metrics* ~app prefix# ~storage ~normalize-uri)))
