mirror of
https://github.com/penpot/penpot.git
synced 2025-07-16 03:55:14 +02:00
♻️ Replace mount with integrant.
This commit is contained in:
parent
31d7aacec1
commit
9f12456456
76 changed files with 2403 additions and 2215 deletions
|
@ -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))))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue