mirror of
https://github.com/penpot/penpot.git
synced 2025-05-06 12:05:54 +02:00
267 lines
8.7 KiB
Clojure
267 lines
8.7 KiB
Clojure
;; This Source Code Form is subject to the terms of the Mozilla Public
|
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
;;
|
|
;; Copyright (c) UXBOX Labs SL
|
|
|
|
(ns app.metrics
|
|
(:refer-clojure :exclude [run!])
|
|
(:require
|
|
[app.common.logging :as l]
|
|
[clojure.spec.alpha :as s]
|
|
[integrant.core :as ig])
|
|
(:import
|
|
io.prometheus.client.CollectorRegistry
|
|
io.prometheus.client.Counter
|
|
io.prometheus.client.Counter$Child
|
|
io.prometheus.client.Gauge
|
|
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$Child
|
|
io.prometheus.client.exporter.common.TextFormat
|
|
io.prometheus.client.hotspot.DefaultExports
|
|
io.prometheus.client.jetty.JettyStatisticsCollector
|
|
org.eclipse.jetty.server.handler.StatisticsHandler
|
|
java.io.StringWriter))
|
|
|
|
(set! *warn-on-reflection* true)
|
|
|
|
(declare create-registry)
|
|
(declare create)
|
|
(declare handler)
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; METRICS SERVICE PROVIDER
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(def default-metrics
|
|
{:update-file-changes
|
|
{:name "rpc_update_file_changes_total"
|
|
:help "A total number of changes submitted to update-file."
|
|
:type :counter}
|
|
|
|
:update-file-bytes-processed
|
|
{:name "rpc_update_file_bytes_processed_total"
|
|
:help "A total number of bytes processed by update-file."
|
|
:type :counter}
|
|
|
|
:rpc-mutation-timing
|
|
{:name "rpc_mutation_timing"
|
|
:help "RPC mutation method call timming."
|
|
:labels ["name"]
|
|
:type :histogram}
|
|
|
|
:rpc-query-timing
|
|
{:name "rpc_query_timing"
|
|
:help "RPC query method call timing."
|
|
:labels ["name"]
|
|
:type :histogram}
|
|
|
|
:websocket-active-connections
|
|
{:name "websocket_active_connections"
|
|
:help "Active websocket connections gauge"
|
|
:type :gauge}
|
|
|
|
:websocket-messages-total
|
|
{:name "websocket_message_total"
|
|
:help "Counter of processed messages."
|
|
:labels ["op"]
|
|
:type :counter}
|
|
|
|
:websocket-session-timing
|
|
{:name "websocket_session_timing"
|
|
:help "Websocket session timing (seconds)."
|
|
:type :summary}
|
|
|
|
:session-update-total
|
|
{:name "http_session_update_total"
|
|
:help "A counter of session update batch events."
|
|
:type :counter}
|
|
|
|
:tasks-timing
|
|
{:name "penpot_tasks_timing"
|
|
:help "Background tasks timing (milliseconds)."
|
|
:labels ["name"]
|
|
:type :summary}
|
|
|
|
:rlimit-queued-submissions
|
|
{:name "penpot_rlimit_queued_submissions"
|
|
:help "Current number of queued submissions on RLIMIT."
|
|
:labels ["name"]
|
|
:type :gauge}
|
|
|
|
:rlimit-used-permits
|
|
{:name "penpot_rlimit_used_permits"
|
|
:help "Current number of used permits on RLIMIT."
|
|
:labels ["name"]
|
|
:type :gauge}
|
|
|
|
:rlimit-acquires-total
|
|
{:name "penpot_rlimit_acquires_total"
|
|
:help "Total number of acquire operations on RLIMIT."
|
|
:labels ["name"]
|
|
:type :counter}
|
|
|
|
:executors-active-threads
|
|
{:name "penpot_executors_active_threads"
|
|
:help "Current number of threads available in the executor service."
|
|
:labels ["name"]
|
|
:type :gauge}
|
|
|
|
:executors-running-threads
|
|
{:name "penpot_executors_running_threads"
|
|
:help "Current number of threads with state RUNNING."
|
|
:labels ["name"]
|
|
:type :gauge}
|
|
|
|
:executors-queued-submissions
|
|
{:name "penpot_executors_queued_submissions"
|
|
:help "Current number of queued submissions."
|
|
:labels ["name"]
|
|
:type :gauge}})
|
|
|
|
(defmethod ig/init-key ::metrics
|
|
[_ _]
|
|
(l/info :action "initialize metrics")
|
|
(let [registry (create-registry)
|
|
definitions (reduce-kv (fn [res k v]
|
|
(->> (assoc v :registry registry)
|
|
(create)
|
|
(assoc res k)))
|
|
{}
|
|
default-metrics)]
|
|
{:handler (partial handler registry)
|
|
:definitions definitions
|
|
:registry registry}))
|
|
|
|
(s/def ::handler fn?)
|
|
(s/def ::registry #(instance? CollectorRegistry %))
|
|
(s/def ::metrics
|
|
(s/keys :req-un [::registry ::handler]))
|
|
|
|
(defn- handler
|
|
[registry _ respond _]
|
|
(let [samples (.metricFamilySamples ^CollectorRegistry registry)
|
|
writer (StringWriter.)]
|
|
(TextFormat/write004 writer samples)
|
|
(respond {:headers {"content-type" TextFormat/CONTENT_TYPE_004}
|
|
:body (.toString writer)})))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Implementation
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(def default-empty-labels (into-array String []))
|
|
|
|
(def default-quantiles
|
|
[[0.5 0.01]
|
|
[0.90 0.01]
|
|
[0.99 0.001]])
|
|
|
|
(def default-histogram-buckets
|
|
[1 5 10 25 50 75 100 250 500 750 1000 2500 5000 7500])
|
|
|
|
(defn run!
|
|
[{:keys [definitions]} {:keys [id] :as params}]
|
|
(when-let [mobj (get definitions id)]
|
|
((::fn mobj) params)
|
|
true))
|
|
|
|
(defn create-registry
|
|
[]
|
|
(let [registry (CollectorRegistry.)]
|
|
(DefaultExports/register registry)
|
|
registry))
|
|
|
|
(defn- is-array?
|
|
[o]
|
|
(let [oc (class o)]
|
|
(and (.isArray ^Class oc)
|
|
(= (.getComponentType oc) String))))
|
|
|
|
(defn make-counter
|
|
[{:keys [name help registry reg labels] :as props}]
|
|
(let [registry (or registry reg)
|
|
instance (.. (Counter/build)
|
|
(name name)
|
|
(help help))
|
|
_ (when (seq labels)
|
|
(.labelNames instance (into-array String labels)))
|
|
instance (.register instance registry)]
|
|
|
|
{::instance instance
|
|
::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
|
|
[{:keys [name help registry reg labels] :as props}]
|
|
(let [registry (or registry reg)
|
|
instance (.. (Gauge/build)
|
|
(name name)
|
|
(help help))
|
|
_ (when (seq 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
|
|
[{:keys [name help registry reg labels max-age quantiles buckets]
|
|
:or {max-age 3600 buckets 12 quantiles default-quantiles} :as props}]
|
|
(let [registry (or registry reg)
|
|
builder (doto (Summary/build)
|
|
(.name name)
|
|
(.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
|
|
::fn (fn [{: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)))}))
|
|
|
|
(defn make-histogram
|
|
[{:keys [name help registry reg labels buckets]
|
|
:or {buckets default-histogram-buckets}}]
|
|
(let [registry (or registry reg)
|
|
instance (doto (Histogram/build)
|
|
(.name name)
|
|
(.help help)
|
|
(.buckets (into-array Double/TYPE buckets)))
|
|
_ (when (seq labels)
|
|
(.labelNames instance (into-array String labels)))
|
|
instance (.register instance registry)]
|
|
|
|
{::instance instance
|
|
::fn (fn [{: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)))}))
|
|
|
|
(defn create
|
|
[{:keys [type] :as props}]
|
|
(case type
|
|
:counter (make-counter props)
|
|
:gauge (make-gauge props)
|
|
:summary (make-summary props)
|
|
:histogram (make-histogram props)))
|
|
|
|
(defn instrument-jetty!
|
|
[^CollectorRegistry registry ^StatisticsHandler handler]
|
|
(doto (JettyStatisticsCollector. handler)
|
|
(.register registry))
|
|
nil)
|
|
|