♻️ Refactor metrics namespace

This commit is contained in:
Andrey Antukh 2022-08-30 19:32:35 +02:00
parent ec3651d85b
commit fd973d87fd
4 changed files with 185 additions and 145 deletions

View file

@ -150,7 +150,7 @@
;; When metrics namespace is provided ;; When metrics namespace is provided
(when metrics (when metrics
(->> (:registry metrics) (->> (::mtx/registry metrics)
(PrometheusMetricsTrackerFactory.) (PrometheusMetricsTrackerFactory.)
(.setMetricsTrackerFactory config))) (.setMetricsTrackerFactory config)))

View file

@ -151,7 +151,7 @@
[middleware/errors errors/handle] [middleware/errors errors/handle]
[middleware/restrict-methods]]} [middleware/restrict-methods]]}
["/metrics" {:handler (:handler metrics)}] ["/metrics" {:handler (::mtx/handler metrics)}]
["/assets" {:middleware [(:middleware session)]} ["/assets" {:middleware [(:middleware session)]}
["/by-id/:id" {:handler (:objects-handler assets)}] ["/by-id/:id" {:handler (:objects-handler assets)}]
["/by-file-media-id/:id" {:handler (:file-objects-handler assets)}] ["/by-file-media-id/:id" {:handler (:file-objects-handler assets)}]

View file

@ -8,6 +8,8 @@
(:refer-clojure :exclude [run!]) (:refer-clojure :exclude [run!])
(:require (:require
[app.common.logging :as l] [app.common.logging :as l]
[app.common.spec :as us]
[app.metrics.definition :as-alias mdef]
[clojure.spec.alpha :as s] [clojure.spec.alpha :as s]
[integrant.core :as ig]) [integrant.core :as ig])
(:import (:import
@ -16,11 +18,12 @@
io.prometheus.client.Counter$Child io.prometheus.client.Counter$Child
io.prometheus.client.Gauge io.prometheus.client.Gauge
io.prometheus.client.Gauge$Child io.prometheus.client.Gauge$Child
io.prometheus.client.Summary
io.prometheus.client.Summary$Child
io.prometheus.client.Summary$Builder
io.prometheus.client.Histogram io.prometheus.client.Histogram
io.prometheus.client.Histogram$Child io.prometheus.client.Histogram$Child
io.prometheus.client.SimpleCollector
io.prometheus.client.Summary
io.prometheus.client.Summary$Builder
io.prometheus.client.Summary$Child
io.prometheus.client.exporter.common.TextFormat io.prometheus.client.exporter.common.TextFormat
io.prometheus.client.hotspot.DefaultExports io.prometheus.client.hotspot.DefaultExports
java.io.StringWriter)) java.io.StringWriter))
@ -28,7 +31,7 @@
(set! *warn-on-reflection* true) (set! *warn-on-reflection* true)
(declare create-registry) (declare create-registry)
(declare create) (declare create-collector)
(declare handler) (declare handler)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -37,128 +40,151 @@
(def default-metrics (def default-metrics
{:update-file-changes {:update-file-changes
{:name "penpot_rpc_update_file_changes_total" {::mdef/name "penpot_rpc_update_file_changes_total"
:help "A total number of changes submitted to update-file." ::mdef/help "A total number of changes submitted to update-file."
:type :counter} ::mdef/type :counter}
:update-file-bytes-processed :update-file-bytes-processed
{:name "penpot_rpc_update_file_bytes_processed_total" {::mdef/name "penpot_rpc_update_file_bytes_processed_total"
:help "A total number of bytes processed by update-file." ::mdef/help "A total number of bytes processed by update-file."
:type :counter} ::mdef/type :counter}
:rpc-mutation-timing :rpc-mutation-timing
{:name "penpot_rpc_mutation_timing" {::mdef/name "penpot_rpc_mutation_timing"
:help "RPC mutation method call timming." ::mdef/help "RPC mutation method call timming."
:labels ["name"] ::mdef/labels ["name"]
:type :histogram} ::mdef/type :histogram}
:rpc-command-timing :rpc-command-timing
{:name "penpot_rpc_command_timing" {::mdef/name "penpot_rpc_command_timing"
:help "RPC command method call timming." ::mdef/help "RPC command method call timming."
:labels ["name"] ::mdef/labels ["name"]
:type :histogram} ::mdef/type :histogram}
:rpc-query-timing :rpc-query-timing
{:name "penpot_rpc_query_timing" {::mdef/name "penpot_rpc_query_timing"
:help "RPC query method call timing." ::mdef/help "RPC query method call timing."
:labels ["name"] ::mdef/labels ["name"]
:type :histogram} ::mdef/type :histogram}
:websocket-active-connections :websocket-active-connections
{:name "penpot_websocket_active_connections" {::mdef/name "penpot_websocket_active_connections"
:help "Active websocket connections gauge" ::mdef/help "Active websocket connections gauge"
:type :gauge} ::mdef/type :gauge}
:websocket-messages-total :websocket-messages-total
{:name "penpot_websocket_message_total" {::mdef/name "penpot_websocket_message_total"
:help "Counter of processed messages." ::mdef/help "Counter of processed messages."
:labels ["op"] ::mdef/labels ["op"]
:type :counter} ::mdef/type :counter}
:websocket-session-timing :websocket-session-timing
{:name "penpot_websocket_session_timing" {::mdef/name "penpot_websocket_session_timing"
:help "Websocket session timing (seconds)." ::mdef/help "Websocket session timing (seconds)."
:type :summary} ::mdef/type :summary}
:session-update-total :session-update-total
{:name "penpot_http_session_update_total" {::mdef/name "penpot_http_session_update_total"
:help "A counter of session update batch events." ::mdef/help "A counter of session update batch events."
:type :counter} ::mdef/type :counter}
:tasks-timing :tasks-timing
{:name "penpot_tasks_timing" {::mdef/name "penpot_tasks_timing"
:help "Background tasks timing (milliseconds)." ::mdef/help "Background tasks timing (milliseconds)."
:labels ["name"] ::mdef/labels ["name"]
:type :summary} ::mdef/type :summary}
:redis-eval-timing :redis-eval-timing
{:name "penpot_redis_eval_timing" {::mdef/name "penpot_redis_eval_timing"
:help "Redis EVAL commands execution timings (ms)" ::mdef/help "Redis EVAL commands execution timings (ms)"
:labels ["name"] ::mdef/labels ["name"]
:type :summary} ::mdef/type :summary}
:rpc-semaphore-queued-submissions :rpc-semaphore-queued-submissions
{:name "penpot_rpc_semaphore_queued_submissions" {::mdef/name "penpot_rpc_semaphore_queued_submissions"
:help "Current number of queued submissions on RPC-SEMAPHORE." ::mdef/help "Current number of queued submissions on RPC-SEMAPHORE."
:labels ["name"] ::mdef/labels ["name"]
:type :gauge} ::mdef/type :gauge}
:rpc-semaphore-used-permits :rpc-semaphore-used-permits
{:name "penpot_rpc_semaphore_used_permits" {::mdef/name "penpot_rpc_semaphore_used_permits"
:help "Current number of used permits on RPC-SEMAPHORE." ::mdef/help "Current number of used permits on RPC-SEMAPHORE."
:labels ["name"] ::mdef/labels ["name"]
:type :gauge} ::mdef/type :gauge}
:rpc-semaphore-acquires-total :rpc-semaphore-acquires-total
{:name "penpot_rpc_semaphore_acquires_total" {::mdef/name "penpot_rpc_semaphore_acquires_total"
:help "Total number of acquire operations on RPC-SEMAPHORE." ::mdef/help "Total number of acquire operations on RPC-SEMAPHORE."
:labels ["name"] ::mdef/labels ["name"]
:type :counter} ::mdef/type :counter}
:executors-active-threads :executors-active-threads
{:name "penpot_executors_active_threads" {::mdef/name "penpot_executors_active_threads"
:help "Current number of threads available in the executor service." ::mdef/help "Current number of threads available in the executor service."
:labels ["name"] ::mdef/labels ["name"]
:type :gauge} ::mdef/type :gauge}
:executors-completed-tasks :executors-completed-tasks
{:name "penpot_executors_completed_tasks_total" {::mdef/name "penpot_executors_completed_tasks_total"
:help "Aproximate number of completed tasks by the executor." ::mdef/help "Aproximate number of completed tasks by the executor."
:labels ["name"] ::mdef/labels ["name"]
:type :counter} ::mdef/type :counter}
:executors-running-threads :executors-running-threads
{:name "penpot_executors_running_threads" {::mdef/name "penpot_executors_running_threads"
:help "Current number of threads with state RUNNING." ::mdef/help "Current number of threads with state RUNNING."
:labels ["name"] ::mdef/labels ["name"]
:type :gauge} ::mdef/type :gauge}
:executors-queued-submissions :executors-queued-submissions
{:name "penpot_executors_queued_submissions" {::mdef/name "penpot_executors_queued_submissions"
:help "Current number of queued submissions." ::mdef/help "Current number of queued submissions."
:labels ["name"] ::mdef/labels ["name"]
:type :gauge}}) ::mdef/type :gauge}})
(s/def ::mdef/name string?)
(s/def ::mdef/help string?)
(s/def ::mdef/labels (s/every string? :kind vector?))
(s/def ::mdef/type #{:gauge :counter :summary :histogram})
(s/def ::mdef/instance
#(instance? SimpleCollector %))
(s/def ::mdef/definition
(s/keys :req [::mdef/name
::mdef/help
::mdef/type]
:opt [::mdef/labels
::mdef/instance]))
(s/def ::definitions
(s/map-of keyword? ::mdef/definition))
(s/def ::registry
#(instance? CollectorRegistry %))
(s/def ::handler fn?)
(s/def ::metrics
(s/keys :req [::registry
::handler
::definitions]))
(defmethod ig/init-key ::metrics (defmethod ig/init-key ::metrics
[_ _] [_ _]
(l/info :action "initialize metrics") (l/info :action "initialize metrics")
(let [registry (create-registry) (let [registry (create-registry)
definitions (reduce-kv (fn [res k v] definitions (reduce-kv (fn [res k v]
(->> (assoc v :registry registry) (->> (assoc v ::registry registry)
(create) (create-collector)
(assoc res k))) (assoc res k)))
{} {}
default-metrics)] default-metrics)]
{:handler (partial handler registry)
:definitions definitions
:registry registry}))
(us/verify! ::definitions definitions)
;; TODO: revisit {::handler (partial handler registry)
(s/def ::handler fn?) ::definitions definitions
(s/def ::registry #(instance? CollectorRegistry %)) ::registry registry}))
(s/def ::metrics
(s/keys :req-un [::registry ::handler]))
(defn- handler (defn- handler
[registry _ respond _] [registry _ respond _]
@ -182,13 +208,16 @@
(def default-histogram-buckets (def default-histogram-buckets
[1 5 10 25 50 75 100 250 500 750 1000 2500 5000 7500]) [1 5 10 25 50 75 100 250 500 750 1000 2500 5000 7500])
(defmulti run-collector! (fn [mdef _] (::mdef/type mdef)))
(defmulti create-collector ::mdef/type)
(defn run! (defn run!
[{:keys [definitions]} {:keys [id] :as params}] [{:keys [::definitions]} {:keys [id] :as params}]
(when-let [mobj (get definitions id)] (when-let [mobj (get definitions id)]
((::fn mobj) params) (run-collector! mobj params)
true)) true))
(defn create-registry (defn- create-registry
[] []
(let [registry (CollectorRegistry.)] (let [registry (CollectorRegistry.)]
(DefaultExports/register registry) (DefaultExports/register registry)
@ -200,79 +229,89 @@
(and (.isArray ^Class oc) (and (.isArray ^Class oc)
(= (.getComponentType oc) String)))) (= (.getComponentType oc) String))))
(defn make-counter (defmethod run-collector! :counter
[{:keys [name help registry reg labels] :as props}] [{:keys [::mdef/instance]} {:keys [inc labels] :or {inc 1 labels default-empty-labels}}]
(let [instance (.labels instance (if (is-array? labels) labels (into-array String labels)))]
(.inc ^Counter$Child instance (double inc))))
(defmethod run-collector! :gauge
[{:keys [::mdef/instance]} {:keys [inc dec labels val] :or {labels default-empty-labels}}]
(let [instance (.labels ^Gauge instance (if (is-array? labels) labels (into-array String labels)))]
(cond (number? inc) (.inc ^Gauge$Child instance (double inc))
(number? dec) (.dec ^Gauge$Child instance (double dec))
(number? val) (.set ^Gauge$Child instance (double val)))))
(defmethod run-collector! :summary
[{:keys [::mdef/instance]} {:keys [val labels] :or {labels default-empty-labels}}]
(let [instance (.labels ^Summary instance (if (is-array? labels) labels (into-array String labels)))]
(.observe ^Summary$Child instance val)))
(defmethod run-collector! :histogram
[{:keys [::mdef/instance]} {:keys [val labels] :or {labels default-empty-labels}}]
(let [instance (.labels ^Histogram instance (if (is-array? labels) labels (into-array String labels)))]
(.observe ^Histogram$Child instance val)))
(defmethod create-collector :counter
[{::mdef/keys [name help reg labels]
::keys [registry]
:as props}]
(let [registry (or registry reg) (let [registry (or registry reg)
instance (.. (Counter/build) instance (.. (Counter/build)
(name name) (name name)
(help help)) (help help))]
_ (when (seq labels) (when (seq labels)
(.labelNames instance (into-array String labels))) (.labelNames instance (into-array String labels)))
instance (.register instance registry)]
{::instance instance (assoc props ::mdef/instance (.register instance registry))))
::fn (fn [{:keys [inc labels] :or {inc 1 labels default-empty-labels}}]
(let [instance (.labels instance (if (is-array? labels) labels (into-array String labels)))]
(.inc ^Counter$Child instance (double inc))))}))
(defn make-gauge (defmethod create-collector :gauge
[{:keys [name help registry reg labels] :as props}] [{::mdef/keys [name help reg labels]
::keys [registry]
:as props}]
(let [registry (or registry reg) (let [registry (or registry reg)
instance (.. (Gauge/build) instance (.. (Gauge/build)
(name name) (name name)
(help help)) (help help))]
_ (when (seq labels) (when (seq labels)
(.labelNames instance (into-array String labels))) (.labelNames instance (into-array String labels)))
instance (.register instance registry)]
{::instance instance
::fn (fn [{:keys [inc dec labels val] :or {labels default-empty-labels}}]
(let [instance (.labels ^Gauge instance (if (is-array? labels) labels (into-array String labels)))]
(cond (number? inc) (.inc ^Gauge$Child instance (double inc))
(number? dec) (.dec ^Gauge$Child instance (double dec))
(number? val) (.set ^Gauge$Child instance (double val)))))}))
(defn make-summary (assoc props ::mdef/instance (.register instance registry))))
[{:keys [name help registry reg labels max-age quantiles buckets]
:or {max-age 3600 buckets 12 quantiles default-quantiles} :as props}] (defmethod create-collector :summary
[{::mdef/keys [name help reg labels max-age quantiles buckets]
::keys [registry]
:or {max-age 3600 buckets 12 quantiles default-quantiles}
:as props}]
(let [registry (or registry reg) (let [registry (or registry reg)
builder (doto (Summary/build) builder (doto (Summary/build)
(.name name) (.name name)
(.help help)) (.help help))]
_ (when (seq quantiles)
(.maxAgeSeconds ^Summary$Builder builder ^long max-age)
(.ageBuckets ^Summary$Builder builder buckets))
_ (doseq [[q e] quantiles]
(.quantile ^Summary$Builder builder q e))
_ (when (seq labels)
(.labelNames ^Summary$Builder builder (into-array String labels)))
instance (.register ^Summary$Builder builder registry)]
{::instance instance (when (seq quantiles)
::fn (fn [{:keys [val labels] :or {labels default-empty-labels}}] (.maxAgeSeconds ^Summary$Builder builder ^long max-age)
(let [instance (.labels ^Summary instance (if (is-array? labels) labels (into-array String labels)))] (.ageBuckets ^Summary$Builder builder buckets))
(.observe ^Summary$Child instance val)))}))
(defn make-histogram (doseq [[q e] quantiles]
[{:keys [name help registry reg labels buckets] (.quantile ^Summary$Builder builder q e))
:or {buckets default-histogram-buckets}}]
(when (seq labels)
(.labelNames ^Summary$Builder builder (into-array String labels)))
(assoc props ::mdef/instance (.register ^Summary$Builder builder registry))))
(defmethod create-collector :histogram
[{::mdef/keys [name help reg labels buckets]
::keys [registry]
:or {buckets default-histogram-buckets}
:as props}]
(let [registry (or registry reg) (let [registry (or registry reg)
instance (doto (Histogram/build) instance (doto (Histogram/build)
(.name name) (.name name)
(.help help) (.help help)
(.buckets (into-array Double/TYPE buckets))) (.buckets (into-array Double/TYPE buckets)))]
_ (when (seq labels)
(.labelNames instance (into-array String labels)))
instance (.register instance registry)]
{::instance instance (when (seq labels)
::fn (fn [{:keys [val labels] :or {labels default-empty-labels}}] (.labelNames instance (into-array String labels)))
(let [instance (.labels ^Histogram instance (if (is-array? labels) labels (into-array String labels)))]
(.observe ^Histogram$Child instance val)))}))
(defn create (assoc props ::mdef/instance (.register instance registry))))
[{:keys [type] :as props}]
(case type
:counter (make-counter props)
:gauge (make-gauge props)
:summary (make-summary props)
:histogram (make-histogram props)))

View file

@ -14,8 +14,8 @@
[app.main.ui.settings.options :refer [options-page]] [app.main.ui.settings.options :refer [options-page]]
[app.main.ui.settings.password :refer [password-page]] [app.main.ui.settings.password :refer [password-page]]
[app.main.ui.settings.profile :refer [profile-page]] [app.main.ui.settings.profile :refer [profile-page]]
[app.main.ui.settings.sidebar :refer [sidebar]] [app.main.ui.settings.sidebar :refer [sidebar]]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[app.util.router :as rt] [app.util.router :as rt]
[rumext.alpha :as mf])) [rumext.alpha :as mf]))
@ -31,10 +31,11 @@
(let [section (get-in route [:data :name]) (let [section (get-in route [:data :name])
profile (mf/deref refs/profile) profile (mf/deref refs/profile)
locale (mf/deref i18n/locale)] locale (mf/deref i18n/locale)]
(mf/use-effect (mf/use-effect
#(when (nil? profile) #(when (nil? profile)
(st/emit! (rt/nav :auth-login)))) (st/emit! (rt/nav :auth-login))))
[:section.dashboard-layout [:section.dashboard-layout
[:& sidebar {:profile profile [:& sidebar {:profile profile
:locale locale :locale locale