diff --git a/metrics-clojure-ring/src/metrics/ring/expose.clj b/metrics-clojure-ring/src/metrics/ring/expose.clj index c1e5e10..35265f6 100644 --- a/metrics-clojure-ring/src/metrics/ring/expose.clj +++ b/metrics-clojure-ring/src/metrics/ring/expose.clj @@ -114,18 +114,31 @@ (into {} (map #(render-metric % unit-context) (->> registry (all-metrics) (filter-metrics filter)))))) - -(defn serve-metrics - ([request] - (serve-metrics request default-registry)) - ([request registry] - (serve-metrics request registry false)) +(defn- serve-metrics* ([request registry {:keys [pretty-print? filter rate-unit duration-unit]}] (let [metrics-map (render-metrics registry filter (unit/build-options rate-unit duration-unit)) json (generate-string metrics-map {:pretty pretty-print?})] (-> (response json) (header "Content-Type" "application/json"))))) +(defn serve-metrics + ([request] + (let [^String filter (get-in request [:params :filter])] + (serve-metrics* request default-registry {:pretty-print? false + :filter filter + :rate-unit TimeUnit/SECONDS + :duration-unit TimeUnit/NANOSECONDS}))) + ([request respond raise] + (let [^String filter (get-in request [:params :filter])] + (try + (respond + (serve-metrics* request default-registry {:pretty-print? false + :filter filter + :rate-unit TimeUnit/SECONDS + :duration-unit TimeUnit/NANOSECONDS})) + (catch Exception e (raise e)))))) + + (defn expose-metrics-as-json ([handler] (expose-metrics-as-json handler "/metrics")) @@ -134,12 +147,22 @@ ([handler uri registry] (expose-metrics-as-json handler uri registry {:pretty-print? false})) ([handler uri registry opts] - (fn [request] - (let [^String request-uri (:uri request) - ^String filter (get-in request [:params :filter])] - (if (or (.startsWith request-uri (sanitize-uri uri)) - (= request-uri uri)) - (serve-metrics request registry (merge {:filter filter - :rate-unit TimeUnit/SECONDS - :duration-unit TimeUnit/NANOSECONDS} opts)) - (handler request)))))) + (fn + ([request] + (let [^String request-uri (:uri request) + ^String filter (get-in request [:params :filter])] + (if (or (.startsWith request-uri (sanitize-uri uri)) + (= request-uri uri)) + (serve-metrics* request registry (merge {:filter filter + :rate-unit TimeUnit/SECONDS + :duration-unit TimeUnit/NANOSECONDS} opts)) + (handler request)))) + ([request respond raise] + (let [^String request-uri (:uri request) + ^String filter (get-in request [:params :filter])] + (if (or (.startsWith request-uri (sanitize-uri uri)) + (= request-uri uri)) + (serve-metrics* request registry (merge {:filter filter + :rate-unit TimeUnit/SECONDS + :duration-unit TimeUnit/NANOSECONDS} opts)) + (handler request respond raise))))))) diff --git a/metrics-clojure-ring/src/metrics/ring/instrument.clj b/metrics-clojure-ring/src/metrics/ring/instrument.clj index c6719a4..121ebd3 100644 --- a/metrics-clojure-ring/src/metrics/ring/instrument.clj +++ b/metrics-clojure-ring/src/metrics/ring/instrument.clj @@ -2,7 +2,7 @@ (:require [metrics.core :refer [default-registry]] [metrics.counters :refer (counter inc! dec!)] [metrics.meters :refer (meter mark!)] - [metrics.timers :refer (timer time!)] + [metrics.timers :refer (timer time! start stop)] [clojure.string :as string]) (:import [com.codahale.metrics MetricRegistry])) @@ -51,23 +51,31 @@ :times times :request-methods request-methods})) -(defn handle-request [handler metrics request] - (let [{:keys [active-requests requests responses - schemes statuses times request-methods]} metrics] - (inc! active-requests) - (try - (let [request-method (:request-method request) - request-scheme (:scheme request)] - (mark! requests) - (mark-in! request-methods request-method) - (mark-in! schemes request-scheme) - (let [resp (time! (times request-method (times :other)) - (handler request)) - ^{:tag "int"} status-code (or (:status resp) 404)] - (mark! responses) - (mark-in! statuses (int (/ status-code 100))) - resp)) - (finally (dec! active-requests))))) +(defn- time-request [thunk metrics request] + (let [{:keys [active-requests requests responses + schemes statuses times request-methods]} metrics] + (inc! active-requests) + (try + (let [request-method (:request-method request) + request-scheme (:scheme request)] + (mark! requests) + (mark-in! request-methods request-method) + (mark-in! schemes request-scheme) + (let [resp (time! (times request-method (times :other)) + (thunk)) + ^{:tag "int"} status-code (or (:status resp) 404)] + (mark! responses) + (mark-in! statuses (int (/ status-code 100))) + resp)) + (finally (dec! active-requests))))) + +(defn handle-request + ([handler metrics request] + (time-request #(handler request) metrics request)) + ([handler metrics request respond raise] + (try + (time-request #(handler request respond raise) metrics request) + (catch Exception e (raise e))))) (defn metrics-for [metrics-db prefix registry] @@ -87,10 +95,15 @@ ([handler] (instrument handler default-registry)) ([handler ^MetricRegistry reg] - (fn [request] - (handle-request handler - (ring-metrics reg {:prefix []}) - request)))) + (fn + ([request] + (handle-request handler + (ring-metrics reg {:prefix []}) + request)) + ([request respond raise] + (handle-request handler + (ring-metrics reg {:prefix []}) + request respond raise))))) (defn instrument-by "Instrument a ring handler using the metrics returned by the `metrics-for` @@ -107,8 +120,12 @@ (instrument-by handler default-registry metrics-prefix)) ([handler ^MetricRegistry reg metrics-prefix] (let [metrics-db (atom {})] - (fn [request] - (let [prefix (metrics-prefix request)] - (handle-request handler - (metrics-for metrics-db prefix reg) - request)))))) + (fn + ([request] + (handle-request handler + (metrics-for metrics-db (metrics-prefix request) reg) + request)) + ([request respond raise] + (handle-request handler + (metrics-for metrics-db (metrics-prefix request) reg) + request respond raise)))))) diff --git a/metrics-clojure-ring/test/metrics/test/instrument_test.clj b/metrics-clojure-ring/test/metrics/test/instrument_test.clj index b7d7767..14e1f6f 100644 --- a/metrics-clojure-ring/test/metrics/test/instrument_test.clj +++ b/metrics-clojure-ring/test/metrics/test/instrument_test.clj @@ -8,6 +8,9 @@ (def dummy-handler (fn [req] req)) +(def dummy-handler-async (fn [req respond raise] + (respond req))) + (defn tracked? [^MetricRegistry reg metric] (->> (.getMetrics reg) (map (fn [[k v]] k)) @@ -54,6 +57,15 @@ (app (mock/request :get "/yolo" {})) + (doseq [m expected-metrics] + (is (tracked? reg m))))) + + (testing "instrument without custom prefix and async handler" + (let [reg (MetricRegistry. ) + app (instrument dummy-handler-async reg)] + + (app (mock/request :get "/yolo" {}) identity identity) + (doseq [m expected-metrics] (is (tracked? reg m)))))) @@ -64,10 +76,20 @@ (uri-prefix (mock/request :get "/foo/bar/baz"))))) (deftest test-instrument-by-uri-prefix - (let [reg (MetricRegistry.) - app (instrument-by dummy-handler reg uri-prefix)] + (testing "instrument by uri prefix" + (let [reg (MetricRegistry.) + app (instrument-by dummy-handler reg uri-prefix)] - (app (mock/request :get "/yolo" {})) + (app (mock/request :get "/yolo" {})) + + (doseq [m expected-metrics] + (is (tracked? reg (str "yolo." m)))))) - (doseq [m expected-metrics] - (is (tracked? reg (str "yolo." m)))))) + (testing "instrument by uri prefix and async handler" + (let [reg (MetricRegistry.) + app (instrument-by dummy-handler-async reg uri-prefix)] + + (app (mock/request :get "/yolo" {}) identity identity) + + (doseq [m expected-metrics] + (is (tracked? reg (str "yolo." m)))))))