Merge remote-tracking branch 'origin/staging' into develop

This commit is contained in:
Andrey Antukh 2021-12-27 09:50:15 +01:00
commit 2d118ecc65
20 changed files with 191 additions and 303 deletions

View file

@ -3,7 +3,8 @@
rumext.alpha/defc clojure.core/defn rumext.alpha/defc clojure.core/defn
rumext.alpha/fnc clojure.core/fn rumext.alpha/fnc clojure.core/fn
app.common.data/export clojure.core/def app.common.data/export clojure.core/def
app.db/with-atomic clojure.core/with-open} app.db/with-atomic clojure.core/with-open
app.common.logging/with-context clojure.core/do}
:hooks :hooks
{:analyze-call {:analyze-call

View file

@ -74,5 +74,3 @@
;; (prn "==============" rtype (into {} ?meta)) ;; (prn "==============" rtype (into {} ?meta))
;; (prn (api/sexpr result)) ;; (prn (api/sexpr result))
{:node result})) {:node result}))

View file

@ -33,7 +33,6 @@
metosin/reitit-ring {:mvn/version "0.5.15"} metosin/reitit-ring {:mvn/version "0.5.15"}
org.postgresql/postgresql {:mvn/version "42.2.23"} org.postgresql/postgresql {:mvn/version "42.2.23"}
com.zaxxer/HikariCP {:mvn/version "5.0.0"} com.zaxxer/HikariCP {:mvn/version "5.0.0"}
funcool/datoteka {:mvn/version "2.0.0"} funcool/datoteka {:mvn/version "2.0.0"}
buddy/buddy-core {:mvn/version "1.10.1"} buddy/buddy-core {:mvn/version "1.10.1"}
@ -50,9 +49,7 @@
io.sentry/sentry {:mvn/version "5.1.2"} io.sentry/sentry {:mvn/version "5.1.2"}
;; Pretty Print specs ;; Pretty Print specs
fipp/fipp {:mvn/version "0.6.24"}
pretty-spec/pretty-spec {:mvn/version "0.1.4"} pretty-spec/pretty-spec {:mvn/version "0.1.4"}
software.amazon.awssdk/s3 {:mvn/version "2.17.40"}} software.amazon.awssdk/s3 {:mvn/version "2.17.40"}}
:paths ["src" "resources"] :paths ["src" "resources"]

View file

@ -104,7 +104,8 @@
:v4 (humanize (alength (blob/encode data {:version 4}))) :v4 (humanize (alength (blob/encode data {:version 4})))
}]))) }])))
(defonce debug-tap
;; ;; (def contents (read-string (slurp (io/resource "bool-contents-1.edn")))) (do
;; (def pre-data (datoteka.core/slurp-bytes (io/resource "file-data-sample"))) (add-tap #(locking debug-tap
;; (def data (blob/decode pre-data)) (prn "tap debug:" %)))
1))

View file

@ -130,10 +130,10 @@
</div> </div>
{% endif %} {% endif %}
{% if error %} {% if hint %}
<div class="table-row"> <div class="table-row">
<div class="table-key">HINT: </div> <div class="table-key">HINT: </div>
<div class="table-val">{{error.message}}</div> <div class="table-val">{{hint}}</div>
</div> </div>
{% endif %} {% endif %}
@ -163,25 +163,39 @@
</div> </div>
{% endif %} {% endif %}
{% if explain %}
<div id="explain" class="table-row multiline">
<div class="table-key">EXPLAIN: </div>
<div class="table-val">
<pre>{{explain}}</pre>
</div>
</div>
{% endif %}
{% if data %} {% if data %}
<div id="edata" class="table-row multiline"> <div id="edata" class="table-row multiline">
<div class="table-key">EDATA: </div> <div class="table-key">ERROR DATA: </div>
<div class="table-val"> <div class="table-val">
<pre>{{data}}</pre> <pre>{{data}}</pre>
</div> </div>
</div> </div>
{% endif %} {% endif %}
{% if error %} {% if spec-problems %}
<div id="edata" class="table-row multiline">
<div class="table-key">SPEC PROBLEMS: </div>
<div class="table-val">
<pre>{{spec-problems}}</pre>
</div>
</div>
{% endif %}
{% if cause %}
<div id="trace" class="table-row multiline">
<div class="table-key">TRACE:</div>
<div class="table-val">
<pre>{{cause}}</pre>
</div>
</div>
{% elif trace %}
<div id="trace" class="table-row multiline">
<div class="table-key">TRACE:</div>
<div class="table-val">
<pre>{{trace}}</pre>
</div>
</div>
{% elif error %}
<div id="trace" class="table-row multiline"> <div id="trace" class="table-row multiline">
<div class="table-key">TRACE:</div> <div class="table-key">TRACE:</div>
<div class="table-val"> <div class="table-val">

View file

@ -2,7 +2,7 @@
<Configuration status="info" monitorInterval="30"> <Configuration status="info" monitorInterval="30">
<Appenders> <Appenders>
<Console name="console" target="SYSTEM_OUT"> <Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{YYYY-MM-dd HH:mm:ss.SSS}] [%t] %level{length=1} %logger{36} - %msg%n"/> <PatternLayout pattern="[%d{YYYY-MM-dd HH:mm:ss.SSS}] %level{length=1} %logger{36} - %msg%n"/>
</Console> </Console>
<RollingFile name="main" fileName="logs/main.log" filePattern="logs/main-%i.log"> <RollingFile name="main" fileName="logs/main.log" filePattern="logs/main-%i.log">

View file

@ -2,7 +2,6 @@
export PENPOT_FLAGS="enable-asserts enable-audit-log $PENPOT_FLAGS" export PENPOT_FLAGS="enable-asserts enable-audit-log $PENPOT_FLAGS"
#-J-Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
export OPTIONS=" export OPTIONS="
-A:jmx-remote:dev \ -A:jmx-remote:dev \

View file

@ -90,20 +90,9 @@
(try (try
(handler request) (handler request)
(catch Throwable e (catch Throwable e
(try (l/with-context (errors/get-error-context request e)
(let [cdata (errors/get-error-context request e)] (l/error :hint (ex-message e) :cause e)
(l/update-thread-context! cdata) {:status 500 :body "internal server error"}))))))
(l/error :hint "unhandled exception"
:message (ex-message e)
:error-id (str (:id cdata))
:cause e))
{:status 500 :body "internal server error"}
(catch Throwable e
(l/error :hint "unhandled exception"
:message (ex-message e)
:cause e)
{:status 500 :body "internal server error"})))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Http Main Handler (Router) ;; Http Main Handler (Router)

View file

@ -7,11 +7,11 @@
(ns app.http.errors (ns app.http.errors
"A errors handling for the http server." "A errors handling for the http server."
(:require (:require
[app.common.data :as d]
[app.common.exceptions :as ex] [app.common.exceptions :as ex]
[app.common.logging :as l] [app.common.logging :as l]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[clojure.pprint] [clojure.pprint]
[clojure.spec.alpha :as s]
[cuerdas.core :as str])) [cuerdas.core :as str]))
(defn- parse-client-ip (defn- parse-client-ip
@ -20,44 +20,24 @@
(get headers "x-real-ip") (get headers "x-real-ip")
(get request :remote-addr))) (get request :remote-addr)))
(defn- simple-prune
([s] (simple-prune s (* 1024 1024)))
([s max-length]
(if (> (count s) max-length)
(str (subs s 0 max-length) " [...]")
s)))
(defn- stringify-data
[data]
(binding [clojure.pprint/*print-right-margin* 200]
(let [result (with-out-str (clojure.pprint/pprint data))]
(simple-prune result (* 1024 1024)))))
(defn get-error-context (defn get-error-context
[request error] [request error]
(let [data (ex-data error)] (let [data (ex-data error)]
(d/without-nils
(merge (merge
{:id (str (uuid/next)) {:id (uuid/next)
:path (str (:uri request)) :path (:uri request)
:method (name (:request-method request)) :method (:request-method request)
:hint (or (:hint data) (ex-message error)) :hint (or (:hint data) (ex-message error))
:params (stringify-data (:params request)) :params (l/stringify-data (:params request))
:data (stringify-data (dissoc data :explain)) :spec-problems (some-> data ::s/problems)
:ip-addr (parse-client-ip request) :ip-addr (parse-client-ip request)
:explain (str/prune (:explain data) (* 1024 1024) "[...]")} :profile-id (:profile-id request)}
(when-let [id (:profile-id request)]
{:profile-id id})
(let [headers (:headers request)] (let [headers (:headers request)]
{:user-agent (get headers "user-agent") {:user-agent (get headers "user-agent")
:frontend-version (get headers "x-frontend-version" "unknown")}) :frontend-version (get headers "x-frontend-version" "unknown")})
(when (map? data) (dissoc data ::s/problems))))
{:error-type (:type data)
:error-code (:code data)})))))
(defmulti handle-exception (defmulti handle-exception
(fn [err & _rest] (fn [err & _rest]
@ -85,21 +65,17 @@
(:explain edata) (:explain edata)
"</pre>\n")} "</pre>\n")}
{:status 400 {:status 400
:body (dissoc edata :data)}))) :body (dissoc edata ::s/problems)})))
(defmethod handle-exception :assertion (defmethod handle-exception :assertion
[error request] [error request]
(let [edata (ex-data error) (let [edata (ex-data error)]
cdata (get-error-context request error)] (l/with-context (get-error-context request error)
(l/update-thread-context! cdata) (l/error :hint (ex-message error) :cause error))
(l/error :hint "internal error: assertion"
:error-id (str (:id cdata))
:cause error)
{:status 500 {:status 500
:body {:type :server-error :body {:type :server-error
:code :assertion :code :assertion
:data (dissoc edata :data)}})) :data (dissoc edata ::s/problems)}}))
(defmethod handle-exception :not-found (defmethod handle-exception :not-found
[err _] [err _]
@ -116,12 +92,10 @@
(if (and (ex/exception? (:rollback edata)) (if (and (ex/exception? (:rollback edata))
(ex/exception? (:handling edata))) (ex/exception? (:handling edata)))
(handle-exception (:handling edata) request) (handle-exception (:handling edata) request)
(let [cdata (get-error-context request error)] (do
(l/update-thread-context! cdata) (l/with-context (get-error-context request error)
(l/error :hint "internal error" (l/error :hint (ex-message error) :cause error))
:error-message (ex-message error)
:error-id (str (:id cdata))
:cause error)
{:status 500 {:status 500
:body {:type :server-error :body {:type :server-error
:code :unexpected :code :unexpected
@ -130,15 +104,13 @@
(defmethod handle-exception org.postgresql.util.PSQLException (defmethod handle-exception org.postgresql.util.PSQLException
[error request] [error request]
(let [cdata (get-error-context request error) (let [state (.getSQLState ^java.sql.SQLException error)]
state (.getSQLState ^java.sql.SQLException error)]
(l/update-thread-context! cdata) (l/with-context (get-error-context request error)
(l/error :hint "psql exception" (l/error :hint "psql exception"
:error-message (ex-message error) :error-message (ex-message error)
:error-id (str (:id cdata)) :state state
:sql-state state :cause error))
:cause error)
(cond (cond
(= state "57014") (= state "57014")

View file

@ -73,11 +73,7 @@
(if-let [{:keys [id profile-id] :as session} (retrieve-from-request cfg request)] (if-let [{:keys [id profile-id] :as session} (retrieve-from-request cfg request)]
(do (do
(a/>!! (::events-ch cfg) id) (a/>!! (::events-ch cfg) id)
(l/update-thread-context! {:profile-id profile-id}) (handler (assoc request :profile-id profile-id)))
(-> request
(assoc :profile-id profile-id)
(assoc :session-id id)
(handler)))
(handler request)))) (handler request))))
;; --- STATE INIT: SESSION ;; --- STATE INIT: SESSION

View file

@ -36,7 +36,7 @@
(db/insert! conn :server-error-report (db/insert! conn :server-error-report
{:id id :content (db/tjson event)}))) {:id id :content (db/tjson event)})))
(defn- parse-context (defn- parse-event-data
[event] [event]
(reduce-kv (reduce-kv
(fn [acc k v] (fn [acc k v]
@ -46,12 +46,11 @@
(str/blank? v) acc (str/blank? v) acc
:else (assoc acc k v))) :else (assoc acc k v)))
{} {}
(:context event))) event))
(defn parse-event (defn parse-event
[event] [event]
(-> (parse-context event) (-> (parse-event-data event)
(merge (dissoc event :context))
(assoc :tenant (cf/get :tenant)) (assoc :tenant (cf/get :tenant))
(assoc :host (cf/get :host)) (assoc :host (cf/get :host))
(assoc :public-uri (cf/get :public-uri)) (assoc :public-uri (cf/get :public-uri))
@ -62,6 +61,7 @@
(aa/with-thread executor (aa/with-thread executor
(try (try
(let [event (parse-event event)] (let [event (parse-event event)]
(l/debug :hint "registering error on database" :id (:id event))
(persist-on-database! cfg event)) (persist-on-database! cfg event))
(catch Exception e (catch Exception e
(l/warn :hint "unexpected exception on database error logger" (l/warn :hint "unexpected exception on database error logger"
@ -74,7 +74,8 @@
[_ {:keys [receiver] :as cfg}] [_ {:keys [receiver] :as cfg}]
(l/info :msg "initializing database error persistence") (l/info :msg "initializing database error persistence")
(let [output (a/chan (a/sliding-buffer 128) (let [output (a/chan (a/sliding-buffer 128)
(filter #(= (:level %) "error")))] (filter (fn [event]
(= (:logger/level event) "error"))))]
(receiver :sub output) (receiver :sub output)
(a/go-loop [] (a/go-loop []
(let [msg (a/<! output)] (let [msg (a/<! output)]

View file

@ -92,19 +92,15 @@
(defn- prepare (defn- prepare
[event] [event]
(if (s/valid? ::log4j-event event) (if (s/valid? ::log4j-event event)
(merge (merge {:message (:message event)
{:logger (:logger-name event)
:level (str/lower (:level event))
:thread (:thread event)
:created-at (dt/instant (:time-millis event)) :created-at (dt/instant (:time-millis event))
:message (:message event)} :logger/name (:logger-name event)
(when-let [ctx (:context-map event)] :logger/level (str/lower (:level event))}
{:context ctx})
(when-let [thrown (:thrown event)] (when-let [thrown (:thrown event)]
{:error {:trace (:extended-stack-trace thrown)})
{:class (:name thrown)
:message (:message thrown) (:context-map event))
:trace (:extended-stack-trace thrown)}}))
(do (do
(l/warn :hint "invalid event" :event event) (l/warn :hint "invalid event" :event event)
nil))) nil)))

View file

@ -266,13 +266,8 @@
(= ::noop (:strategy edata)) (= ::noop (:strategy edata))
(assoc :inc-by 0)) (assoc :inc-by 0))
(l/with-context (get-error-context error item)
(let [cdata (get-error-context error item)] (l/error :cause error :hint "unhandled exception on task")
(l/update-thread-context! cdata)
(l/error :cause error
:hint "unhandled exception on task"
:id (:id cdata))
(if (>= (:retry-num item) (:max-retries item)) (if (>= (:retry-num item) (:max-retries item))
{:status :failed :task item :error error} {:status :failed :task item :error error}
{:status :retry :task item :error error}))))) {:status :retry :task item :error error})))))

View file

@ -33,7 +33,8 @@
com.sun.mail/jakarta.mail {:mvn/version "2.0.1"} com.sun.mail/jakarta.mail {:mvn/version "2.0.1"}
;; exception printing ;; exception printing
io.aviso/pretty {:mvn/version "1.1"} fipp/fipp {:mvn/version "0.6.24"}
io.aviso/pretty {:mvn/version "0.1.37"}
environ/environ {:mvn/version "1.2.0"}} environ/environ {:mvn/version "1.2.0"}}
:paths ["src"] :paths ["src"]
:aliases :aliases

View file

@ -9,17 +9,24 @@
[app.common.exceptions :as ex] [app.common.exceptions :as ex]
[clojure.pprint :refer [pprint]] [clojure.pprint :refer [pprint]]
[cuerdas.core :as str] [cuerdas.core :as str]
#?(:clj [io.aviso.exception :as ie])
#?(:cljs [goog.log :as glog])) #?(:cljs [goog.log :as glog]))
#?(:cljs (:require-macros [app.common.logging])) #?(:cljs (:require-macros [app.common.logging])
#?(:clj :clj (:import
(:import
org.apache.logging.log4j.Level org.apache.logging.log4j.Level
org.apache.logging.log4j.LogManager org.apache.logging.log4j.LogManager
org.apache.logging.log4j.Logger org.apache.logging.log4j.Logger
org.apache.logging.log4j.ThreadContext org.apache.logging.log4j.ThreadContext
org.apache.logging.log4j.CloseableThreadContext
org.apache.logging.log4j.message.MapMessage org.apache.logging.log4j.message.MapMessage
org.apache.logging.log4j.spi.LoggerContext))) org.apache.logging.log4j.spi.LoggerContext)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; CLJ Specific
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#?(:clj (set! *warn-on-reflection* true))
#?(:clj #?(:clj
(defn build-map-message (defn build-map-message
[m] [m]
@ -34,11 +41,63 @@
(def logging-agent (def logging-agent
(agent nil :error-mode :continue))) (agent nil :error-mode :continue)))
(defn- simple-prune
([s] (simple-prune s (* 1024 1024)))
([s max-length]
(if (> (count s) max-length)
(str (subs s 0 max-length) " [...]")
s)))
#?(:clj
(defn stringify-data
[val]
(cond
(instance? clojure.lang.Named val)
(name val)
(instance? Throwable val)
(binding [ie/*app-frame-names* [#"app.*"]
ie/*fonts* nil
ie/*traditional* true]
(ie/format-exception val nil))
(string? val)
val
(coll? val)
(binding [clojure.pprint/*print-right-margin* 120]
(-> (with-out-str (pprint val))
(simple-prune (* 1024 1024 3))))
:else
(str val))))
#?(:clj
(defn data->context-map
^java.util.Map
[data]
(into {}
(comp (filter second)
(map (fn [[key val]]
[(stringify-data key)
(stringify-data val)])))
data)))
#?(:clj
(defmacro with-context
[data & body]
`(let [data# (data->context-map ~data)]
(with-open [closeable# (CloseableThreadContext/putAll data#)]
~@body))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Common
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn get-logger (defn get-logger
[lname] [lname]
#?(:clj (.getLogger ^LoggerContext logger-context ^String lname) #?(:clj (.getLogger ^LoggerContext logger-context ^String lname)
:cljs :cljs (glog/getLogger
(glog/getLogger
(cond (cond
(string? lname) lname (string? lname) lname
(= lname :root) "" (= lname :root) ""
@ -98,7 +157,7 @@
(.isEnabled ^Logger logger ^Level level))) (.isEnabled ^Logger logger ^Level level)))
(defmacro log (defmacro log
[& {:keys [level cause ::logger ::async ::raw] :as props}] [& {:keys [level cause ::logger ::async ::raw] :or {async true} :as props}]
(if (:ns &env) ; CLJS (if (:ns &env) ; CLJS
`(write-log! ~(or logger (str *ns*)) `(write-log! ~(or logger (str *ns*))
~level ~level
@ -112,10 +171,12 @@
~level-sym (get-level ~level)] ~level-sym (get-level ~level)]
(if (enabled? ~logger-sym ~level-sym) (if (enabled? ~logger-sym ~level-sym)
~(if async ~(if async
`(send-off logging-agent `(let [cdata# (ThreadContext/getImmutableContext)]
(send-off logging-agent
(fn [_#] (fn [_#]
(let [message# (or ~raw (build-map-message ~props))] (with-context (into {:cause ~cause} cdata#)
(write-log! ~logger-sym ~level-sym ~cause message#)))) (->> (or ~raw (build-map-message ~props))
(write-log! ~logger-sym ~level-sym ~cause))))))
`(let [message# (or ~raw (build-map-message ~props))] `(let [message# (or ~raw (build-map-message ~props))]
(write-log! ~logger-sym ~level-sym ~cause message#)))))))) (write-log! ~logger-sym ~level-sym ~cause message#))))))))
@ -147,24 +208,6 @@
(when (:ns &env) (when (:ns &env)
`(set-level* ~n ~level)))) `(set-level* ~n ~level))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; CLJ Specific
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#?(:clj
(defn update-thread-context!
[data]
(run! (fn [[key val]]
(ThreadContext/put
(name key)
(cond
(coll? val)
(binding [clojure.pprint/*print-right-margin* 120]
(with-out-str (pprint val)))
(instance? clojure.lang.Named val) (name val)
:else (str val))))
data)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; CLJS Specific ;; CLJS Specific
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -213,7 +256,6 @@
(some-> (get-logger name) (some-> (get-logger name)
(glog/setLevel (get-level lvl))))) (glog/setLevel (get-level lvl)))))
#?(:cljs #?(:cljs
(defn set-levels! (defn set-levels!
[lvls] [lvls]

View file

@ -208,30 +208,30 @@
;; --- Macros ;; --- Macros
(defn spec-assert* (defn spec-assert*
[spec x message context] [spec val hint ctx]
(if (s/valid? spec x) (if (s/valid? spec val)
x val
(let [data (s/explain-data spec x) (let [data (s/explain-data spec val)]
explain (with-out-str (s/explain-out data))]
(ex/raise :type :assertion (ex/raise :type :assertion
:code :spec-validation :code :spec-validation
:hint message :hint hint
:data data :ctx ctx
:explain explain ::s/problems (::s/problems data)))))
:context context
#?@(:cljs [:stack (.-stack (ex-info message {}))])))))
(defmacro assert (defmacro assert
"Development only assertion macro." "Development only assertion macro."
[spec x] [spec x]
(when *assert* (when *assert*
(let [nsdata (:ns &env) (let [nsdata (:ns &env)
context (when nsdata context (if nsdata
{:ns (str (:name nsdata)) {:ns (str (:name nsdata))
:name (pr-str spec) :name (pr-str spec)
:line (:line &env) :line (:line &env)
:file (:file (:meta nsdata))}) :file (:file (:meta nsdata))}
(let [mdata (meta &form)]
{:ns (str (ns-name *ns*))
:name (pr-str spec)
:line (:line mdata)}))
message (str "spec assert: '" (pr-str spec) "'")] message (str "spec assert: '" (pr-str spec) "'")]
`(spec-assert* ~spec ~x ~message ~context)))) `(spec-assert* ~spec ~x ~message ~context))))
@ -253,12 +253,9 @@
[spec data] [spec data]
(let [result (s/conform spec data)] (let [result (s/conform spec data)]
(when (= result ::s/invalid) (when (= result ::s/invalid)
(let [data (s/explain-data spec data) (let [data (s/explain-data spec data)]
explain (with-out-str
(s/explain-out data))]
(throw (ex/error :type :validation (throw (ex/error :type :validation
:code :spec-validation :code :spec-validation
:explain explain
:data data)))) :data data))))
result)) result))

View file

@ -22,7 +22,8 @@
:main-opts ["-m" "antq.core"]} :main-opts ["-m" "antq.core"]}
:dev :dev
{:extra-deps {:extra-paths ["dev"]
:extra-deps
{thheller/shadow-cljs {:mvn/version "2.16.6"} {thheller/shadow-cljs {:mvn/version "2.16.6"}
cider/cider-nrepl {:mvn/version "0.27.2"}}} cider/cider-nrepl {:mvn/version "0.27.2"}}}

View file

@ -1,112 +0,0 @@
(ns bench.core
(:require [kdtree.core :as k]
[intervaltree.core :as it]
[cljs.pprint :refer (pprint)]
[cljs.nodejs :as node]))
(enable-console-print!)
;; --- Index Initialization Benchmark
(defn- bench-init-10000
[]
(println "1000x1000,10 -> 10000 points")
(time
(k/generate 1000 1000 10 10)))
(defn- bench-init-250000
[]
(time
(k/generate 5000 5000 10 10)))
(defn bench-init
[]
(bench-init-10000)
(bench-init-10000)
(bench-init-250000)
(bench-init-250000)
(bench-init-10000)
(bench-init-10000)
(bench-init-250000)
(bench-init-250000))
;; --- Nearest Search Benchmark
(defn- bench-knn-160000
[]
(let [tree (k/create)]
(k/setup tree 4000 4000 10 10)
(println "KNN Search (160000 points) 1000 times")
(time
(dotimes [i 1000]
(let [pt #js [(rand-int 400)
(rand-int 400)]]
(k/nearest tree pt 2))))))
(defn- bench-knn-360000
[]
(let [tree (k/create)]
(k/initialize tree 6000 6000 10 10)
(println "KNN Search (360000 points) 1000 times")
(time
(dotimes [i 1000]
(let [pt #js [(rand-int 600)
(rand-int 600)]]
(k/nearest tree pt 2))))))
(defn bench-knn
[]
(bench-knn-160000)
(bench-knn-360000))
;; --- Accuracy tests
(defn test-accuracy
[]
(let [tree (k/create)]
(k/setup tree 4000 4000 20 20)
(print "[1742 1419]")
(pprint (js->clj (k/nearest tree #js [1742 1419] 6)))
(print "[1742 1420]")
(pprint (js->clj (k/nearest tree #js [1742 1420] 6)))
))
(defn test-interval
[]
(let [tree (it/create)]
(it/add tree #js [1 5])
(it/add tree #js [5 7])
(it/add tree #js [-4 -1])
(it/add tree #js [-10 -3])
(it/add tree #js [-20 -10])
(it/add tree #js [20 30])
(it/add tree #js [3 9])
(it/add tree #js [100 200])
(it/add tree #js [1000 2000])
(it/add tree #js [6 9])
(js/console.dir tree #js {"depth" nil})
(js/console.log "contains", 4, (it/contains tree 4))
(js/console.log "contains", 0, (it/contains tree 0))
))
(defn main
[& [type]]
(cond
(= type "kd-init")
(bench-init)
(= type "kd-search")
(bench-knn)
(= type "kd-test")
(test-accuracy)
(= type "interval")
(test-interval)
:else
(println "not implemented")))
(set! *main-cli-fn* main)

View file

@ -0,0 +1,5 @@
(ns cljs.user)
(defn hello
[]
(js/console.log "hello"))

View file

@ -81,10 +81,7 @@
(js/console.group "Validation Error:") (js/console.group "Validation Error:")
(ex/ignoring (ex/ignoring
(js/console.info (js/console.info
(with-out-str (with-out-str (pprint error))))
(pprint (dissoc error :explain))))
(when-let [explain (:explain error)]
(js/console.error explain)))
(js/console.groupEnd "Validation Error:")) (js/console.groupEnd "Validation Error:"))
@ -138,8 +135,7 @@
(defmethod ptk/handle-error :server-error (defmethod ptk/handle-error :server-error
[{:keys [data hint] :as error}] [{:keys [data hint] :as error}]
(let [hint (or hint (:hint data) (:message data)) (let [hint (or hint (:hint data) (:message data))
info (with-out-str (pprint (dissoc data :explain))) info (with-out-str (pprint data))
expl (:explain data)
msg (str "Internal Server Error: " hint)] msg (str "Internal Server Error: " hint)]
(ts/schedule (ts/schedule
@ -150,7 +146,6 @@
(js/console.group msg) (js/console.group msg)
(js/console.info info) (js/console.info info)
(when expl (js/console.error expl))
(js/console.groupEnd msg))) (js/console.groupEnd msg)))
(defn on-unhandled-error (defn on-unhandled-error