|
30 | 30 | (defn- make-latency-collector |
31 | 31 | [labels buckets] |
32 | 32 | (prometheus/histogram |
33 | | - :http/request-latency-seconds |
34 | | - {:description "the response latency for HTTP requests." |
35 | | - :labels (concat [:method :status :statusClass :path] labels) |
36 | | - :buckets buckets})) |
| 33 | + :http/request-latency-seconds |
| 34 | + {:description "the response latency for HTTP requests." |
| 35 | + :labels (concat [:method :status :statusClass :path] labels) |
| 36 | + :buckets buckets})) |
37 | 37 |
|
38 | 38 | (defn- make-count-collector |
39 | 39 | [labels] |
40 | 40 | (prometheus/counter |
41 | | - :http/requests-total |
42 | | - {:description "the total number of HTTP requests processed." |
43 | | - :labels (concat [:method :status :statusClass :path] labels)})) |
| 41 | + :http/requests-total |
| 42 | + {:description "the total number of HTTP requests processed." |
| 43 | + :labels (concat [:method :status :statusClass :path] labels)})) |
44 | 44 |
|
45 | 45 | (defn- make-exception-collector |
46 | 46 | [labels] |
47 | 47 | (ex/exception-counter |
48 | | - :http/exceptions-total |
49 | | - {:description "the total number of exceptions encountered during HTTP processing." |
50 | | - :labels (concat [:method :path] labels)})) |
| 48 | + :http/exceptions-total |
| 49 | + {:description "the total number of exceptions encountered during HTTP processing." |
| 50 | + :labels (concat [:method :path] labels)})) |
51 | 51 |
|
52 | 52 | (defn initialize |
53 | 53 | "Initialize all collectors for Ring handler instrumentation. This includes: |
|
62 | 62 | & [{:keys [latency-histogram-buckets labels] |
63 | 63 | :or {latency-histogram-buckets [0.001 0.005 0.01 0.02 0.05 0.1 0.2 0.3 0.5 0.75 1 5]}}]] |
64 | 64 | (prometheus/register |
65 | | - registry |
66 | | - (make-latency-collector labels latency-histogram-buckets) |
67 | | - (make-count-collector labels) |
68 | | - (make-exception-collector labels))) |
| 65 | + registry |
| 66 | + (make-latency-collector labels latency-histogram-buckets) |
| 67 | + (make-count-collector labels) |
| 68 | + (make-exception-collector labels))) |
69 | 69 |
|
70 | 70 | ;; ## Response |
71 | 71 |
|
|
110 | 110 | (defn- record-metrics! |
111 | 111 | [{:keys [registry] :as options} delta request response] |
112 | 112 | (let [labels (merge |
113 | | - {:status (status response) |
114 | | - :statusClass (status-class response)} |
115 | | - (labels-for options request response)) |
| 113 | + {:status (status response) |
| 114 | + :statusClass (status-class response)} |
| 115 | + (labels-for options request response)) |
116 | 116 | delta-in-seconds (/ delta 1e9)] |
117 | 117 | (-> registry |
118 | 118 | (prometheus/inc :http/requests-total labels) |
|
129 | 129 | (f))) |
130 | 130 |
|
131 | 131 | (defn- run-instrumented |
132 | | - [{:keys [handler exception-status] :as options} request] |
133 | | - (ex/with-exceptions (exception-counter-for options request) |
134 | | - (let [start-time (System/nanoTime) |
135 | | - response (safe exception-status #(handler request)) |
136 | | - delta (- (System/nanoTime) start-time)] |
137 | | - (->> (ensure-response-map response exception-status) |
138 | | - (record-metrics! options delta request)) |
139 | | - (if-not (exception? response) |
140 | | - response |
141 | | - (throw response))))) |
| 132 | + ([{:keys [handler exception-status] :as options} request] |
| 133 | + (ex/with-exceptions (exception-counter-for options request) |
| 134 | + (let [start-time (System/nanoTime) |
| 135 | + response (safe exception-status #(handler request)) |
| 136 | + delta (- (System/nanoTime) start-time)] |
| 137 | + (->> exception-status |
| 138 | + (ensure-response-map response) |
| 139 | + (record-metrics! options delta request)) |
| 140 | + (if-not (exception? response) |
| 141 | + response |
| 142 | + (throw response))))) |
| 143 | + |
| 144 | + ([{:keys [handler exception-status] :as options} request respond raise] |
| 145 | + (let [start-time (System/nanoTime) |
| 146 | + ex-counter (exception-counter-for options request) |
| 147 | + respond-fn #(let [delta (- (System/nanoTime) start-time) |
| 148 | + _ (->> exception-status |
| 149 | + (ensure-response-map %) |
| 150 | + (record-metrics! options delta request))] |
| 151 | + (respond %)) |
| 152 | + raise-fn #(let [delta (- (System/nanoTime) start-time)] |
| 153 | + (when exception-status |
| 154 | + (->> exception-status |
| 155 | + (ensure-response-map %) |
| 156 | + (record-metrics! options delta request))) |
| 157 | + (ex/record-exception! ex-counter %) |
| 158 | + (raise %))] |
| 159 | + (try |
| 160 | + (handler request respond-fn raise-fn) |
| 161 | + (catch Throwable t |
| 162 | + (ex/record-exception! ex-counter t) |
| 163 | + (raise t)))))) |
| 164 | + |
| 165 | +(defn- run-expose |
| 166 | + ([{:keys [path on-request registry handler] :as options} |
| 167 | + {:keys [request-method uri] :as request}] |
| 168 | + (if (= uri path) |
| 169 | + (if (= request-method :get) |
| 170 | + (do |
| 171 | + (on-request registry) |
| 172 | + (metrics-response registry)) |
| 173 | + {:status 405}) |
| 174 | + (handler request))) |
| 175 | + |
| 176 | + ([{:keys [path on-request registry handler] :as options} |
| 177 | + {:keys [request-method uri] :as request} |
| 178 | + respond |
| 179 | + raise] |
| 180 | + (if (= uri path) |
| 181 | + (if (= request-method :get) |
| 182 | + (do |
| 183 | + (on-request registry) |
| 184 | + (respond (metrics-response registry))) |
| 185 | + (respond {:status 405})) |
| 186 | + (handler request respond raise)))) |
| 187 | + |
| 188 | +(defn ring-fn [f options] |
| 189 | + (fn |
| 190 | + ([request] (f options request)) |
| 191 | + ([request respond raise] (f options request respond raise)))) |
142 | 192 |
|
143 | 193 | (defn wrap-instrumentation |
144 | 194 | "Wrap the given Ring handler to write metrics to the given registry: |
|
162 | 212 | [[initialize]]." |
163 | 213 | [handler registry |
164 | 214 | & [{:keys [path-fn label-fn] |
165 | | - :or {path-fn :uri |
166 | | - label-fn (constantly {})} |
167 | | - :as options}]] |
| 215 | + :or {path-fn :uri |
| 216 | + label-fn (constantly {})} |
| 217 | + :as options}]] |
168 | 218 | (let [options (assoc options |
169 | 219 | :path-fn path-fn |
170 | 220 | :label-fn label-fn |
171 | 221 | :registry registry |
172 | 222 | :handler handler)] |
173 | | - #(run-instrumented options %))) |
| 223 | + (ring-fn run-instrumented options))) |
174 | 224 |
|
175 | 225 | ;; ### Metrics Endpoint |
176 | 226 |
|
|
182 | 232 | the Prometheus scraper as a trigger for metrics collection." |
183 | 233 | [handler registry |
184 | 234 | & [{:keys [path on-request] |
185 | | - :or {path "/metrics" |
186 | | - on-request identity}}]] |
187 | | - (fn [{:keys [request-method uri] :as request}] |
188 | | - (if (= uri path) |
189 | | - (if (= request-method :get) |
190 | | - (do |
191 | | - (on-request registry) |
192 | | - (metrics-response registry)) |
193 | | - {:status 405}) |
194 | | - (handler request)))) |
| 235 | + :or {path "/metrics" |
| 236 | + on-request identity} |
| 237 | + :as options}]] |
| 238 | + (let [options (assoc options |
| 239 | + :path path |
| 240 | + :on-request on-request |
| 241 | + :registry registry |
| 242 | + :handler handler)] |
| 243 | + (ring-fn run-expose options))) |
195 | 244 |
|
196 | 245 | ;; ### Compound Middleware |
197 | 246 |
|
|
0 commit comments