🎉 Add prometheus metrics.

This commit is contained in:
Andrey Antukh 2020-05-16 20:38:35 +02:00
parent ccb79f7188
commit b532e74310
20 changed files with 359 additions and 82 deletions

View file

@ -9,11 +9,15 @@
;; Logging ;; Logging
org.clojure/tools.logging {:mvn/version "1.1.0"} org.clojure/tools.logging {:mvn/version "1.1.0"}
org.apache.logging.log4j/log4j-api {:mvn/version "2.13.2"} org.apache.logging.log4j/log4j-api {:mvn/version "2.13.3"}
org.apache.logging.log4j/log4j-core {:mvn/version "2.13.2"} org.apache.logging.log4j/log4j-core {:mvn/version "2.13.3"}
org.apache.logging.log4j/log4j-web {:mvn/version "2.13.2"} org.apache.logging.log4j/log4j-web {:mvn/version "2.13.3"}
org.apache.logging.log4j/log4j-jul {:mvn/version "2.13.2"} org.apache.logging.log4j/log4j-jul {:mvn/version "2.13.3"}
org.apache.logging.log4j/log4j-slf4j-impl {:mvn/version "2.13.2"} org.apache.logging.log4j/log4j-slf4j-impl {:mvn/version "2.13.3"}
io.prometheus/simpleclient {:mvn/version "0.9.0"}
io.prometheus/simpleclient_hotspot {:mvn/version "0.9.0"}
io.prometheus/simpleclient_httpserver {:mvn/version "0.9.0"}
expound/expound {:mvn/version "0.8.4"} expound/expound {:mvn/version "0.8.4"}
instaparse/instaparse {:mvn/version "1.4.10"} instaparse/instaparse {:mvn/version "1.4.10"}
@ -26,7 +30,7 @@
seancorfield/next.jdbc {:mvn/version "1.0.424"} seancorfield/next.jdbc {:mvn/version "1.0.424"}
metosin/reitit-ring {:mvn/version "0.4.2"} metosin/reitit-ring {:mvn/version "0.4.2"}
org.postgresql/postgresql {:mvn/version "42.2.12"} org.postgresql/postgresql {:mvn/version "42.2.12"}
com.zaxxer/HikariCP {:mvn/version "3.4.3"} com.zaxxer/HikariCP {:mvn/version "3.4.5"}
funcool/datoteka {:mvn/version "1.2.0"} funcool/datoteka {:mvn/version "1.2.0"}
funcool/promesa {:mvn/version "5.1.0"} funcool/promesa {:mvn/version "5.1.0"}
@ -51,7 +55,7 @@
io.aviso/pretty {:mvn/version "0.1.37"} io.aviso/pretty {:mvn/version "0.1.37"}
mount/mount {:mvn/version "0.1.16"} mount/mount {:mvn/version "0.1.16"}
environ/environ {:mvn/version "1.1.0"}} environ/environ {:mvn/version "1.2.0"}}
:paths ["src" "resources" "../common" "common"] :paths ["src" "resources" "../common" "common"]
:aliases :aliases
{:dev {:dev

View file

@ -1,3 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" monitorInterval="60"> <Configuration status="info" monitorInterval="60">
<Appenders> <Appenders>
<Console name="console" target="SYSTEM_OUT"> <Console name="console" target="SYSTEM_OUT">

View file

@ -17,11 +17,13 @@
[next.jdbc.result-set :as jdbc-rs] [next.jdbc.result-set :as jdbc-rs]
[next.jdbc.sql :as jdbc-sql] [next.jdbc.sql :as jdbc-sql]
[next.jdbc.sql.builder :as jdbc-bld] [next.jdbc.sql.builder :as jdbc-bld]
[uxbox.metrics :as mtx]
[uxbox.common.exceptions :as ex] [uxbox.common.exceptions :as ex]
[uxbox.config :as cfg] [uxbox.config :as cfg]
[uxbox.util.data :as data]) [uxbox.util.data :as data])
(:import (:import
org.postgresql.util.PGobject org.postgresql.util.PGobject
com.zaxxer.hikari.metrics.prometheus.PrometheusMetricsTrackerFactory
com.zaxxer.hikari.HikariConfig com.zaxxer.hikari.HikariConfig
com.zaxxer.hikari.HikariDataSource)) com.zaxxer.hikari.HikariDataSource))
@ -30,17 +32,20 @@
(let [dburi (:database-uri cfg) (let [dburi (:database-uri cfg)
username (:database-username cfg) username (:database-username cfg)
password (:database-password cfg) password (:database-password cfg)
config (HikariConfig.)] config (HikariConfig.)
mfactory (PrometheusMetricsTrackerFactory. mtx/registry)]
(doto config (doto config
(.setJdbcUrl (str "jdbc:" dburi)) (.setJdbcUrl (str "jdbc:" dburi))
(.setPoolName "main")
(.setAutoCommit true) (.setAutoCommit true)
(.setReadOnly false) (.setReadOnly false)
(.setConnectionTimeout 30000) (.setConnectionTimeout 30000) ;; 30seg
(.setValidationTimeout 5000) (.setValidationTimeout 5000) ;; 5seg
(.setIdleTimeout 600000) (.setIdleTimeout 900000) ;; 15min
(.setMaxLifetime 1800000) (.setMaxLifetime 900000) ;; 15min
(.setMinimumIdle 10) (.setMinimumIdle 5)
(.setMaximumPoolSize 20)) (.setMaximumPoolSize 10)
(.setMetricsTrackerFactory mfactory))
(when username (.setUsername config username)) (when username (.setUsername config username))
(when password (.setPassword config password)) (when password (.setPassword config password))
config)) config))
@ -127,3 +132,11 @@
(= typ "jsonb")) (= typ "jsonb"))
(json/read-str val) (json/read-str val)
val))) val)))
;; Instrumentation
(mtx/instrument-with-counter!
{:var [#'jdbc/execute-one!
#'jdbc/execute!]
:id "database__query_counter"
:help "An absolute counter of database queries."})

View file

@ -17,12 +17,14 @@
[uxbox.http.middleware :as middleware] [uxbox.http.middleware :as middleware]
[uxbox.http.session :as session] [uxbox.http.session :as session]
[uxbox.http.ws :as ws] [uxbox.http.ws :as ws]
[uxbox.metrics :as mtx]
[uxbox.services.notifications :as usn])) [uxbox.services.notifications :as usn]))
(defn- create-router (defn- create-router
[] []
(rring/router (rring/router
[["/api" {:middleware [[middleware/format-response-body] [["/metrics" {:get mtx/dump}]
["/api" {:middleware [[middleware/format-response-body]
[middleware/errors errors/handle] [middleware/errors errors/handle]
[middleware/parse-request-body] [middleware/parse-request-body]
[middleware/params] [middleware/params]
@ -37,7 +39,6 @@
["/logout" {:handler handlers/logout-handler ["/logout" {:handler handlers/logout-handler
:method :post}] :method :post}]
["/w" {:middleware [session/auth]} ["/w" {:middleware [session/auth]}
["/query/:type" {:get handlers/query-handler}] ["/query/:type" {:get handlers/query-handler}]
["/mutation/:type" {:post handlers/mutation-handler}]]]])) ["/mutation/:type" {:post handlers/mutation-handler}]]]]))
@ -46,8 +47,9 @@
:start (rring/ring-handler :start (rring/ring-handler
(create-router) (create-router)
(constantly {:status 404, :body ""}) (constantly {:status 404, :body ""})
{:middleware [middleware/development-resources {:middleware [[middleware/development-resources]
middleware/development-cors]})) [middleware/development-cors]
[middleware/metrics]]}))
(defn start-server (defn start-server
[cfg app] [cfg app]

View file

@ -9,6 +9,7 @@
(:require (:require
[clojure.tools.logging :as log] [clojure.tools.logging :as log]
[cuerdas.core :as str] [cuerdas.core :as str]
[uxbox.metrics :as mtx]
[io.aviso.exception :as e])) [io.aviso.exception :as e]))
(defmulti handle-exception (defmulti handle-exception

View file

@ -15,6 +15,7 @@
[ring.middleware.multipart-params :refer [wrap-multipart-params]] [ring.middleware.multipart-params :refer [wrap-multipart-params]]
[ring.middleware.params :refer [wrap-params]] [ring.middleware.params :refer [wrap-params]]
[ring.middleware.resource :refer [wrap-resource]] [ring.middleware.resource :refer [wrap-resource]]
[uxbox.metrics :as mtx]
[uxbox.common.exceptions :as ex] [uxbox.common.exceptions :as ex]
[uxbox.config :as cfg] [uxbox.config :as cfg]
[uxbox.util.transit :as t])) [uxbox.util.transit :as t]))
@ -83,6 +84,12 @@
{:name ::errors {:name ::errors
:compile (constantly wrap-errors)}) :compile (constantly wrap-errors)})
(def metrics
{:name ::metrics
:wrap (fn [handler]
(mtx/wrap-counter handler {:id "http__requests_counter"
:help "Absolute http requests counter."}))})
(def cookies (def cookies
{:name ::cookies {:name ::cookies
:compile (constantly wrap-cookies)}) :compile (constantly wrap-cookies)})

View file

@ -0,0 +1,181 @@
;; 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/.
;;
;; 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
(ns uxbox.metrics
(:require
[clojure.tools.logging :as log]
[cuerdas.core :as str])
(:import
io.prometheus.client.CollectorRegistry
io.prometheus.client.Counter
io.prometheus.client.Gauge
io.prometheus.client.Summary
io.prometheus.client.exporter.common.TextFormat
io.prometheus.client.hotspot.DefaultExports
java.io.StringWriter))
(defn- create-registry
[]
(let [registry (CollectorRegistry.)]
(DefaultExports/register registry)
registry))
(defonce registry (create-registry))
(defonce cache (atom {}))
(defmacro with-measure
[sym expr teardown]
`(let [~sym (System/nanoTime)]
(try
~expr
(finally
(let [~sym (/ (- (System/nanoTime) ~sym) 1000000)]
~teardown)))))
(defn make-counter
[{:keys [id help] :as props}]
(let [instance (doto (Counter/build)
(.name id)
(.help help))
instance (.register instance registry)]
(reify
clojure.lang.IDeref
(deref [_] instance)
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)))
(defn make-gauge
[{:keys [id help] :as props}]
(let [instance (doto (Gauge/build)
(.name id)
(.help help))
instance (.register instance registry)]
(reify
clojure.lang.IDeref
(deref [_] instance)
clojure.lang.IFn
(invoke [_ cmd]
(case cmd
: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)
(.help help)
(.quantile 0.5 0.05)
(.quantile 0.9 0.01)
(.quantile 0.99 0.001))
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 $$))))
(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 wrap-counter
[f props]
(let [cnt (counter props)]
(cnt :wrap f)))
(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 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 dump
[& args]
(let [samples (.metricFamilySamples ^CollectorRegistry registry)
writer (StringWriter.)]
(TextFormat/write004 writer samples)
{:headers {"content-type" TextFormat/CONTENT_TYPE_004}
:body (.toString writer)}))

View file

@ -0,0 +1,73 @@
;; 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/.
;;
;; 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
(ns uxbox.services.middleware
"Common middleware for services."
(:require
[clojure.tools.logging :as log]
[clojure.spec.alpha :as s]
[cuerdas.core :as str]
[expound.alpha :as expound]
[uxbox.common.exceptions :as ex]
[uxbox.common.spec :as us]
[uxbox.metrics :as mtx]))
(defn wrap-spec
[handler]
(let [mdata (meta handler)
spec (s/get-spec (:spec mdata))]
(if (nil? spec)
handler
(with-meta
(fn [params]
(let [result (us/conform spec params)]
(handler result)))
(assoc mdata ::wrap-spec true)))))
(defn wrap-error
[handler]
(let [mdata (meta handler)]
(with-meta
(fn [params]
(try
(handler params)
(catch Throwable error
(ex/raise :type :service-error
:name (:spec mdata)
:cause error))))
(assoc mdata ::wrap-error true))))
(defn- get-prefix
[nsname]
(let [[a b c] (str/split nsname ".")]
c))
(defn wrap-metrics
[handler]
(let [mdata (meta handler)
nsname (namespace (:spec mdata))
smname (name (:spec mdata))
prefix (get-prefix nsname)
sname (str prefix "/" smname)
props {:id (str/join "__" [prefix
(str/snake smname)
"response_time"])
:help (str "Service timing measures for: " sname ".")}]
(with-meta
(mtx/wrap-summary handler props)
(assoc mdata ::wrap-metrics true))))
(defn wrap
[handler]
(-> handler
(wrap-spec)
(wrap-error)
(wrap-metrics)))

View file

@ -5,16 +5,16 @@
;; This Source Code Form is "Incompatible With Secondary Licenses", as ;; This Source Code Form is "Incompatible With Secondary Licenses", as
;; defined by the Mozilla Public License, v. 2.0. ;; defined by the Mozilla Public License, v. 2.0.
;; ;;
;; Copyright (c) 2019-2020 Andrey Antukh <niwi@niwi.nz> ;; Copyright (c) 2020 UXBOX Labs SL
(ns uxbox.services.mutations (ns uxbox.services.mutations
(:require (:require
[uxbox.services.middleware :as middleware]
[uxbox.util.dispatcher :as uds])) [uxbox.util.dispatcher :as uds]))
(uds/defservice handle (uds/defservice handle
:dispatch-by ::type :dispatch-by ::type
:wrap [uds/wrap-spec :wrap middleware/wrap)
uds/wrap-error])
(defmacro defmutation (defmacro defmutation
[key & rest] [key & rest]

View file

@ -13,8 +13,9 @@
[ring.adapter.jetty9 :as jetty] [ring.adapter.jetty9 :as jetty]
[uxbox.common.exceptions :as ex] [uxbox.common.exceptions :as ex]
[uxbox.common.uuid :as uuid] [uxbox.common.uuid :as uuid]
[uxbox.redis :as redis]
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.redis :as redis]
[uxbox.metrics :as mtx]
[uxbox.util.time :as dt] [uxbox.util.time :as dt]
[uxbox.util.transit :as t])) [uxbox.util.transit :as t]))
@ -193,11 +194,20 @@
(jetty/send! conn (t/encode-str val)) (jetty/send! conn (t/encode-str val))
(recur))))) (recur)))))
(defonce metrics-active-connections
(mtx/gauge {:id "notificatons__active_connections"
:help "Active connections to the notifications service."}))
(defonce metrics-message-counter
(mtx/counter {:id "notificatons__messages_counter"
:help "A total number of messages handled by the notifications service."}))
(defn websocket (defn websocket
[{:keys [file-id] :as params}] [{:keys [file-id] :as params}]
(let [in (a/chan 32) (let [in (a/chan 32)
out (a/chan 32)] out (a/chan 32)]
{:on-connect (fn [conn] {:on-connect (fn [conn]
(metrics-active-connections :inc)
(let [xf (map t/decode-str) (let [xf (map t/decode-str)
sub (redis/subscribe (str file-id) xf) sub (redis/subscribe (str file-id) xf)
ws (WebSocket. conn in out sub nil params)] ws (WebSocket. conn in out sub nil params)]
@ -207,21 +217,19 @@
(a/close! sub)))) (a/close! sub))))
:on-error (fn [conn e] :on-error (fn [conn e]
;; (prn "websocket" :on-error e)
(a/close! out) (a/close! out)
(a/close! in)) (a/close! in))
:on-close (fn [conn status-code reason] :on-close (fn [conn status-code reason]
;; (prn "websocket" :on-close status-code reason) (metrics-active-connections :dec)
(a/close! out) (a/close! out)
(a/close! in)) (a/close! in))
:on-text (fn [ws message] :on-text (fn [ws message]
(metrics-message-counter :inc)
(let [message (t/decode-str message)] (let [message (t/decode-str message)]
;; (prn "websocket" :on-text message)
(a/>!! in message))) (a/>!! in message)))
:on-bytes (fn [ws bytes offset len] :on-bytes (constantly nil)}))
#_(prn "websocket" :on-bytes bytes))}))

View file

@ -2,16 +2,19 @@
;; License, v. 2.0. If a copy of the MPL was not distributed with this ;; 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/. ;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;; ;;
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz> ;; 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
(ns uxbox.services.queries (ns uxbox.services.queries
(:require (:require
[uxbox.services.middleware :as middleware]
[uxbox.util.dispatcher :as uds])) [uxbox.util.dispatcher :as uds]))
(uds/defservice handle (uds/defservice handle
:dispatch-by ::type :dispatch-by ::type
:wrap [uds/wrap-spec :wrap middleware/wrap)
uds/wrap-error])
(defmacro defquery (defmacro defquery
[key & rest] [key & rest]

View file

@ -10,8 +10,6 @@
(ns uxbox.services.queries.icons (ns uxbox.services.queries.icons
(:require (:require
[clojure.spec.alpha :as s] [clojure.spec.alpha :as s]
[promesa.core :as p]
[promesa.exec :as px]
[uxbox.common.exceptions :as ex] [uxbox.common.exceptions :as ex]
[uxbox.common.spec :as us] [uxbox.common.spec :as us]
[uxbox.common.uuid :as uuid] [uxbox.common.uuid :as uuid]

View file

@ -10,13 +10,12 @@
(ns uxbox.services.queries.images (ns uxbox.services.queries.images
(:require (:require
[clojure.spec.alpha :as s] [clojure.spec.alpha :as s]
[promesa.core :as p]
[uxbox.common.exceptions :as ex] [uxbox.common.exceptions :as ex]
[uxbox.common.spec :as us] [uxbox.common.spec :as us]
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.images :as images] [uxbox.images :as images]
[uxbox.services.queries.teams :as teams] [uxbox.services.queries :as sq]
[uxbox.services.queries :as sq])) [uxbox.services.queries.teams :as teams]))
(s/def ::id ::us/uuid) (s/def ::id ::us/uuid)
(s/def ::name ::us/string) (s/def ::name ::us/string)

View file

@ -16,6 +16,7 @@
[uxbox.common.spec :as us] [uxbox.common.spec :as us]
[uxbox.config :as cfg] [uxbox.config :as cfg]
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.metrics :as mtx]
[uxbox.tasks.sendmail] [uxbox.tasks.sendmail]
[uxbox.tasks.gc] [uxbox.tasks.gc]
[uxbox.tasks.remove-media] [uxbox.tasks.remove-media]
@ -68,3 +69,8 @@
([conn opts] ([conn opts]
(s/assert ::impl/task-options opts) (s/assert ::impl/task-options opts)
(impl/submit! conn opts))) (impl/submit! conn opts)))
(mtx/instrument-with-counter!
{:var #'submit!
:id "tasks__submit_counter"
:help "Absolute task submit counter."})

View file

@ -15,7 +15,7 @@
[uxbox.common.exceptions :as ex] [uxbox.common.exceptions :as ex]
[uxbox.common.spec :as us] [uxbox.common.spec :as us]
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.media :as media] [uxbox.metrics :as mtx]
[uxbox.util.storage :as ust])) [uxbox.util.storage :as ust]))
(s/def ::type keyword?) (s/def ::type keyword?)
@ -36,6 +36,11 @@
(db/with-atomic [conn db/pool] (db/with-atomic [conn db/pool]
(handle-deletion conn props))) (handle-deletion conn props)))
(mtx/instrument-with-summary!
{:var #'handler
:id "tasks__delete_object"
:help "Timing of remove-object task."})
(defmethod handle-deletion :image (defmethod handle-deletion :image
[conn {:keys [id] :as props}] [conn {:keys [id] :as props}]
(let [sql "delete from image where id=? and deleted_at is not null"] (let [sql "delete from image where id=? and deleted_at is not null"]

View file

@ -15,7 +15,7 @@
[uxbox.common.exceptions :as ex] [uxbox.common.exceptions :as ex]
[uxbox.common.spec :as us] [uxbox.common.spec :as us]
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.media :as media] [uxbox.metrics :as mtx]
[uxbox.util.storage :as ust])) [uxbox.util.storage :as ust]))
(declare delete-profile-data) (declare delete-profile-data)
@ -39,6 +39,11 @@
(log/warn "Profile " (:id profile) (log/warn "Profile " (:id profile)
"does not match constraints for deletion"))))) "does not match constraints for deletion")))))
(mtx/instrument-with-summary!
{:var #'handler
:id "tasks__delete_profile"
:help "Timing of delete-profile task."})
(defn- delete-profile-data (defn- delete-profile-data
[conn profile-id] [conn profile-id]
(log/info "Proceding to delete all data related to profile" profile-id) (log/info "Proceding to delete all data related to profile" profile-id)

View file

@ -15,6 +15,7 @@
[uxbox.common.exceptions :as ex] [uxbox.common.exceptions :as ex]
[uxbox.common.spec :as us] [uxbox.common.spec :as us]
[uxbox.media :as media] [uxbox.media :as media]
[uxbox.metrics :as mtx]
[uxbox.util.storage :as ust])) [uxbox.util.storage :as ust]))
(s/def ::path ::us/not-empty-string) (s/def ::path ::us/not-empty-string)
@ -28,3 +29,7 @@
(ust/delete! media/media-storage (:path props)) (ust/delete! media/media-storage (:path props))
(log/debug "Media " (:path props) " removed."))) (log/debug "Media " (:path props) " removed.")))
(mtx/instrument-with-summary!
{:var #'handler
:id "tasks__remove_media"
:help "Timing of remove-media task."})

View file

@ -15,6 +15,7 @@
[uxbox.common.data :as d] [uxbox.common.data :as d]
[uxbox.common.exceptions :as ex] [uxbox.common.exceptions :as ex]
[uxbox.config :as cfg] [uxbox.config :as cfg]
[uxbox.metrics :as mtx]
[uxbox.util.http :as http])) [uxbox.util.http :as http]))
(defmulti sendmail (fn [config email] (:sendmail-backend config))) (defmulti sendmail (fn [config email] (:sendmail-backend config)))
@ -94,3 +95,7 @@
[{:keys [props] :as task}] [{:keys [props] :as task}]
(sendmail cfg/config props)) (sendmail cfg/config props))
(mtx/instrument-with-summary!
{:var #'handler
:id "tasks__sendmail"
:help "Timing of sendmail task."})

View file

@ -20,22 +20,18 @@
(definterface IDispatcher (definterface IDispatcher
(^void add [key f])) (^void add [key f]))
(defn- wrap-handler (deftype Dispatcher [reg attr wrap]
[items handler]
(reduce #(%2 %1) handler items))
(deftype Dispatcher [reg attr wrap-fns]
IDispatcher IDispatcher
(add [this key f] (add [this key f]
(let [f (wrap-handler wrap-fns f)] (.put ^Map reg key (wrap f))
(.put ^Map reg key f) this)
this))
clojure.lang.IDeref clojure.lang.IDeref
(deref [_] (deref [_]
{:registry reg {:registry reg
:attr attr :attr attr
:wrap-fns wrap-fns}) :wrap wrap})
clojure.lang.IFn clojure.lang.IFn
(invoke [_ params] (invoke [_ params]
@ -100,36 +96,3 @@
`(do `(do
(s/assert dispatcher? ~sym) (s/assert dispatcher? ~sym)
(add-method ~sym ~key ~f ~meta)))) (add-method ~sym ~key ~f ~meta))))
(defn wrap-spec
[handler]
(let [mdata (meta handler)
spec (s/get-spec (:spec mdata))]
(if (nil? spec)
handler
(with-meta
(fn [params]
(let [result (s/conform spec params)]
(if (not= result ::s/invalid)
(handler result)
(let [data (s/explain-data spec params)]
(ex/raise :type :validation
:code :spec-validation
:explain (with-out-str
(expound/printer data))
:data (::s/problems data))))))
(assoc mdata ::wrap-spec true)))))
(defn wrap-error
[handler]
(let [mdata (meta handler)]
(with-meta
(fn [params]
(try
(handler params)
(catch Throwable error
(ex/raise :type :service-error
:name (:spec mdata)
:cause error))))
(assoc mdata ::wrap-error true))))

View file

@ -19,11 +19,9 @@
[clojure.repl :refer :all] [clojure.repl :refer :all]
[criterium.core :refer [quick-bench bench with-progress-reporting]] [criterium.core :refer [quick-bench bench with-progress-reporting]]
[clj-kondo.core :as kondo] [clj-kondo.core :as kondo]
[promesa.core :as p]
[promesa.exec :as px]
[uxbox.migrations] [uxbox.migrations]
[uxbox.db :as db] [uxbox.db :as db]
;; [uxbox.redis :as rd] [uxbox.metrics :as mtx]
[uxbox.util.storage :as st] [uxbox.util.storage :as st]
[uxbox.util.time :as tm] [uxbox.util.time :as tm]
[uxbox.util.blob :as blob] [uxbox.util.blob :as blob]