♻️ Replace mount with integrant.

This commit is contained in:
Andrey Antukh 2020-12-24 14:32:19 +01:00 committed by Alonso Torres
parent 31d7aacec1
commit 9f12456456
76 changed files with 2403 additions and 2215 deletions

View file

@ -5,9 +5,18 @@
;; This Source Code Form is "Incompatible With Secondary Licenses", as
;; defined by the Mozilla Public License, v. 2.0.
;;
;; Copyright (c) 2020 UXBOX Labs SL
;; Copyright (c) 2020 Andrey Antukh <niwi@niwi.nz>
(ns app.metrics
(:require
[app.common.exceptions :as ex]
[app.util.time :as dt]
[app.worker]
[clojure.tools.logging :as log]
[clojure.spec.alpha :as s]
[cuerdas.core :as str]
[integrant.core :as ig]
[next.jdbc :as jdbc])
(:import
io.prometheus.client.CollectorRegistry
io.prometheus.client.Counter
@ -17,28 +26,91 @@
io.prometheus.client.hotspot.DefaultExports
java.io.StringWriter))
(defn- create-registry
(declare instrument-vars!)
(declare instrument)
(declare create-registry)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Entry Point
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn- instrument-jdbc!
[registry]
(instrument-vars!
[#'next.jdbc/execute-one!
#'next.jdbc/execute!]
{:registry registry
:type :counter
:name "database_query_counter"
:help "An absolute counter of database queries."}))
(defn- instrument-workers!
[registry]
(instrument-vars!
[#'app.worker/run-task]
{:registry registry
:type :summary
:name "worker_task_checkout_millis"
:help "Latency measured between scheduld_at and execution time."
:wrap (fn [rootf mobj]
(let [mdata (meta rootf)
origf (::original mdata rootf)]
(with-meta
(fn [tasks item]
(let [now (inst-ms (dt/now))
sat (inst-ms (:scheduled-at item))]
(mobj :observe (- now sat))
(origf tasks item)))
{::original origf})))}))
(defn- handler
[registry request]
(let [samples (.metricFamilySamples ^CollectorRegistry registry)
writer (StringWriter.)]
(TextFormat/write004 writer samples)
{:headers {"content-type" TextFormat/CONTENT_TYPE_004}
:body (.toString writer)}))
(defmethod ig/init-key ::metrics
[_ opts]
(log/infof "Initializing prometheus registry and instrumentation.")
(let [registry (create-registry)]
(instrument-workers! registry)
(instrument-jdbc! registry)
{:handler (partial handler registry)
:registry registry}))
(s/def ::handler fn?)
(s/def ::registry #(instance? CollectorRegistry %))
(s/def ::metrics
(s/keys :req-un [::registry ::handler]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Implementation
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn create-registry
[]
(let [registry (CollectorRegistry.)]
(DefaultExports/register registry)
;; (DefaultExports/register registry)
registry))
(defonce registry (create-registry))
(defonce cache (atom {}))
(defmacro with-measure
[sym expr teardown]
`(let [~sym (System/nanoTime)]
[& {:keys [expr cb]}]
`(let [start# (System/nanoTime)
tdown# ~cb]
(try
~expr
(finally
(let [~sym (/ (- (System/nanoTime) ~sym) 1000000)]
~teardown)))))
(tdown# (/ (- (System/nanoTime) start#) 1000000))))))
(defn make-counter
[{:keys [id help] :as props}]
(let [instance (doto (Counter/build)
(.name id)
[{:keys [name help registry reg] :as props}]
(let [registry (or registry reg)
instance (doto (Counter/build)
(.name name)
(.help help))
instance (.register instance registry)]
(reify
@ -47,36 +119,16 @@
clojure.lang.IFn
(invoke [_ cmd]
(.inc ^Counter instance))
(invoke [_ cmd val]
(case cmd
:wrap (fn
([a]
(.inc ^Counter instance)
(val a))
([a b]
(.inc ^Counter instance)
(val a b))
([a b c]
(.inc ^Counter instance)
(val a b c)))
(throw (IllegalArgumentException. "invalid arguments")))))))
(defn counter
[{:keys [id] :as props}]
(or (get @cache id)
(let [v (make-counter props)]
(swap! cache assoc id v)
v)))
(.inc ^Counter instance)))))
(defn make-gauge
[{:keys [id help] :as props}]
(let [instance (doto (Gauge/build)
(.name id)
[{:keys [name help registry reg] :as props}]
(let [registry (or registry reg)
instance (doto (Gauge/build)
(.name name)
(.help help))
instance (.register instance registry)]
(reify
clojure.lang.IDeref
(deref [_] instance)
@ -87,92 +139,92 @@
:inc (.inc ^Gauge instance)
:dec (.dec ^Gauge instance))))))
(defn gauge
[{:keys [id] :as props}]
(or (get @cache id)
(let [v (make-gauge props)]
(swap! cache assoc id v)
v)))
(defn make-summary
[{:keys [id help] :as props}]
(let [instance (doto (Summary/build)
(.name id)
[{:keys [name help registry reg] :as props}]
(let [registry (or registry reg)
instance (doto (Summary/build)
(.name name)
(.help help)
(.quantile 0.5 0.05)
(.quantile 0.9 0.01)
(.quantile 0.99 0.001))
instance (.register instance registry)]
instance (.register instance registry)]
(reify
clojure.lang.IDeref
(deref [_] instance)
clojure.lang.IFn
(invoke [_ val]
(.observe ^Summary instance val))
(invoke [_ cmd val]
(case cmd
:wrap (fn
([a]
(with-measure $$
(val a)
(.observe ^Summary instance $$)))
([a b]
(with-measure $$
(val a b)
(.observe ^Summary instance $$)))
([a b c]
(with-measure $$
(val a b c)
(.observe ^Summary instance $$))))
(.observe ^Summary instance val)))))
(throw (IllegalArgumentException. "invalid arguments")))))))
(defn summary
[{:keys [id] :as props}]
(or (get @cache id)
(let [v (make-summary props)]
(swap! cache assoc id v)
v)))
(defn wrap-summary
[f props]
(let [sm (summary props)]
(sm :wrap f)))
(defn create
[{:keys [type name] :as props}]
(case type
:counter (make-counter props)
:gauge (make-gauge props)
:summary (make-summary props)))
(defn wrap-counter
[f props]
(let [cnt (counter props)]
(cnt :wrap f)))
[rootf mobj]
(let [mdata (meta rootf)
origf (::original mdata rootf)]
(with-meta
(fn
([a]
(mobj :inc)
(origf a))
([a b]
(mobj :inc)
(origf a b))
([a b & more]
(mobj :inc)
(apply origf a b more)))
(assoc mdata ::original origf))))
(defn instrument-with-counter!
[{:keys [var] :as props}]
(let [cnt (counter props)
vars (if (var? var) [var] var)]
(doseq [var vars]
(alter-var-root var (fn [root]
(let [mdata (meta root)
original (::counter-original mdata root)]
(with-meta
(cnt :wrap original)
(assoc mdata ::counter-original original))))))))
(defn wrap-summary
[rootf mobj]
(let [mdata (meta rootf)
origf (::original mdata rootf)]
(with-meta
(fn
([a]
(with-measure
:expr (origf a)
:cb #(mobj :observe %)))
([a b]
(with-measure
:expr (origf a b)
:cb #(mobj :observe %)))
([a b & more]
(with-measure
:expr (apply origf a b more)
:cb #(mobj :observe %))))
(assoc mdata ::original origf))))
(defn instrument-with-summary!
[{:keys [var] :as props}]
(let [sm (summary props)]
(alter-var-root var (fn [root]
(let [mdata (meta root)
original (::summary-original mdata root)]
(with-meta
(sm :wrap original)
(assoc mdata ::summary-original original)))))))
(defn instrument-vars!
[vars {:keys [wrap] :as props}]
(let [obj (create props)]
(cond
(instance? Counter @obj)
(doseq [var vars]
(alter-var-root var (or wrap wrap-counter) obj))
(defn dump
[& _args]
(let [samples (.metricFamilySamples ^CollectorRegistry registry)
writer (StringWriter.)]
(TextFormat/write004 writer samples)
{:headers {"content-type" TextFormat/CONTENT_TYPE_004}
:body (.toString writer)}))
(instance? Summary @obj)
(doseq [var vars]
(alter-var-root var (or wrap wrap-summary) obj))
:else
(ex/raise :type :not-implemented))))
(defn instrument
[f {:keys [wrap] :as props}]
(let [obj (create props)]
(cond
(instance? Counter @obj)
((or wrap wrap-counter) f obj)
(instance? Summary @obj)
((or wrap wrap-summary) f obj)
:else
(ex/raise :type :not-implemented))))