From e12a6e65a6e95b7d611d8b14f53671f58c18947e Mon Sep 17 00:00:00 2001 From: Andrey Antukh <niwi@niwi.nz> Date: Tue, 6 Apr 2021 23:25:34 +0200 Subject: [PATCH] :recycle: Refactor logging. --- backend/resources/log4j2-devenv.xml | 2 +- backend/scripts/repl | 2 +- backend/src/app/cli/fixtures.clj | 38 +++++--- backend/src/app/cli/manage.clj | 4 +- backend/src/app/cli/migrate_media.clj | 4 +- backend/src/app/db.clj | 6 +- backend/src/app/emails.clj | 6 +- backend/src/app/http.clj | 21 +++-- backend/src/app/http/awsns.clj | 25 ++--- backend/src/app/http/errors.clj | 29 +++--- backend/src/app/http/oauth/github.clj | 8 +- backend/src/app/http/oauth/gitlab.clj | 8 +- backend/src/app/http/oauth/google.clj | 8 +- backend/src/app/http/session.clj | 24 +++-- backend/src/app/loggers/loki.clj | 14 ++- backend/src/app/loggers/mattermost.clj | 15 +-- backend/src/app/loggers/zmq.clj | 4 +- backend/src/app/main.clj | 6 +- backend/src/app/metrics.clj | 6 +- backend/src/app/msgbus.clj | 27 ++++-- backend/src/app/notifications.clj | 25 +++-- backend/src/app/rpc.clj | 10 +- backend/src/app/storage.clj | 18 +++- backend/src/app/svgparse.clj | 5 +- backend/src/app/tasks/delete_object.clj | 8 +- backend/src/app/tasks/delete_profile.clj | 8 +- backend/src/app/tasks/file_media_gc.clj | 15 ++- backend/src/app/tasks/file_xlog_gc.clj | 6 +- backend/src/app/tasks/tasks_gc.clj | 6 +- backend/src/app/util/log4j.clj | 27 ------ backend/src/app/util/logging.clj | 111 +++++++++++++++++++++++ backend/src/app/util/migrations.clj | 6 +- backend/src/app/worker.clj | 74 ++++++++++----- 33 files changed, 383 insertions(+), 193 deletions(-) delete mode 100644 backend/src/app/util/log4j.clj create mode 100644 backend/src/app/util/logging.clj diff --git a/backend/resources/log4j2-devenv.xml b/backend/resources/log4j2-devenv.xml index 3c18f6bd3..7f7ba7b1f 100644 --- a/backend/resources/log4j2-devenv.xml +++ b/backend/resources/log4j2-devenv.xml @@ -6,7 +6,7 @@ </Console> <RollingFile name="main" fileName="logs/main.log" filePattern="logs/main-%i.log"> - <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"/> <Policies> <SizeBasedTriggeringPolicy size="50M"/> </Policies> diff --git a/backend/scripts/repl b/backend/scripts/repl index 6a21835b1..32fd12d42 100755 --- a/backend/scripts/repl +++ b/backend/scripts/repl @@ -2,7 +2,7 @@ export PENPOT_ASSERTS_ENABLED=true -export OPTIONS="-A:jmx-remote:dev -J-Dclojure.tools.logging.factory=clojure.tools.logging.impl/log4j2-factory -J-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager -J-Xms512m -J-Xmx512m -J-Dlog4j2.configurationFile=log4j2-devenv.xml" +export OPTIONS="-A:jmx-remote:dev -J-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager -J-Xms512m -J-Xmx512m -J-Dlog4j2.configurationFile=log4j2-devenv.xml" export OPTIONS_EVAL="nil" # export OPTIONS_EVAL="(set! *warn-on-reflection* true)" diff --git a/backend/src/app/cli/fixtures.clj b/backend/src/app/cli/fixtures.clj index 710d3f1fe..0f2ebd6bd 100644 --- a/backend/src/app/cli/fixtures.clj +++ b/backend/src/app/cli/fixtures.clj @@ -16,8 +16,8 @@ [app.main :as main] [app.rpc.mutations.profile :as profile] [app.util.blob :as blob] + [app.util.logging :as l] [buddy.hashers :as hashers] - [clojure.tools.logging :as log] [integrant.core :as ig])) (defn- mk-uuid @@ -74,7 +74,9 @@ (let [rng (java.util.Random. 1)] (letfn [(create-profile [conn index] (let [id (mk-uuid "profile" index) - _ (log/info "create profile" index id) + _ (l/info :action "create profile" + :index index + :id id) prof (register-profile conn {:id id @@ -90,20 +92,22 @@ prof)) (create-profiles [conn] - (log/info "create profiles") + (l/info :action "create profiles") (collect (partial create-profile conn) (range (:num-profiles opts)))) (create-team [conn index] (let [id (mk-uuid "team" index) name (str "Team" index)] - (log/info "create team" index id) + (l/info :action "create team" + :index index + :id id) (db/insert! conn :team {:id id :name name}) id)) (create-teams [conn] - (log/info "create teams") + (l/info :action "create teams") (collect (partial create-team conn) (range (:num-teams opts)))) @@ -111,7 +115,9 @@ (let [id (mk-uuid "file" project-id index) name (str "file" index) data (cp/make-file-data id)] - (log/info "create file" index id) + (l/info :action "create file" + :index index + :id id) (db/insert! conn :file {:id id :data (blob/encode data) @@ -126,7 +132,7 @@ id)) (create-files [conn owner-id project-id] - (log/info "create files") + (l/info :action "create files") (run! (partial create-file conn owner-id project-id) (range (:num-files-per-project opts)))) @@ -138,7 +144,9 @@ (str "project " index) "Drafts") is-default (nil? index)] - (log/info "create project" index id) + (l/info :action "create project" + :index index + :id id) (db/insert! conn :project {:id id :team-id team-id @@ -153,7 +161,7 @@ id)) (create-projects [conn team-id profile-ids] - (log/info "create projects") + (l/info :action "create projects") (let [owner-id (rng-nth rng profile-ids) project-ids (conj (collect (partial create-project conn team-id owner-id) @@ -170,14 +178,16 @@ :can-edit true})) (setup-team [conn team-id profile-ids] - (log/info "setup team" team-id profile-ids) + (l/info :action "setup team" + :team-id team-id + :profile-ids (pr-str profile-ids)) (assign-profile-to-team conn team-id true (first profile-ids)) (run! (partial assign-profile-to-team conn team-id false) (rest profile-ids)) (create-projects conn team-id profile-ids)) (assign-teams-and-profiles [conn teams profiles] - (log/info "assign teams and profiles") + (l/info :action "assign teams and profiles") (loop [team-id (first teams) teams (rest teams)] (when-not (nil? team-id) @@ -194,7 +204,9 @@ project-id (:default-project-id owner) data (cp/make-file-data id)] - (log/info "create draft file" index id) + (l/info :action "create draft file" + :index index + :id id) (db/insert! conn :file {:id id :data (blob/encode data) @@ -244,6 +256,6 @@ (try (run-in-system system preset) (catch Exception e - (log/errorf e "unhandled exception")) + (l/error :hint "unhandled exception" :cause e)) (finally (ig/halt! system))))) diff --git a/backend/src/app/cli/manage.clj b/backend/src/app/cli/manage.clj index 04216fc22..3ee9ca76d 100644 --- a/backend/src/app/cli/manage.clj +++ b/backend/src/app/cli/manage.clj @@ -14,9 +14,9 @@ [app.main :as main] [app.rpc.mutations.profile :as profile] [app.rpc.queries.profile :refer [retrieve-profile-data-by-email]] + [app.util.logging :as l] [clojure.string :as str] [clojure.tools.cli :refer [parse-opts]] - [clojure.tools.logging :as log] [integrant.core :as ig]) (:import java.io.Console)) @@ -34,7 +34,7 @@ [{:keys [label type] :or {type :text}}] (let [^Console console (System/console)] (when-not console - (log/error "no console found, can proceed") + (l/error :hint "no console found, can proceed") (System/exit 1)) (binding [*out* (.writer console)] diff --git a/backend/src/app/cli/migrate_media.clj b/backend/src/app/cli/migrate_media.clj index 6a0531126..207feff99 100644 --- a/backend/src/app/cli/migrate_media.clj +++ b/backend/src/app/cli/migrate_media.clj @@ -14,7 +14,7 @@ [app.db :as db] [app.main :as main] [app.storage :as sto] - [clojure.tools.logging :as log] + [app.util.logging :as l] [cuerdas.core :as str] [datoteka.core :as fs] [integrant.core :as ig])) @@ -49,7 +49,7 @@ (run-in-system) (ig/halt!)) (catch Exception e - (log/errorf e "Unhandled exception."))))) + (l/error :hint "unhandled exception" :cause e))))) ;; --- IMPL diff --git a/backend/src/app/db.clj b/backend/src/app/db.clj index 29a5627f8..d2b6f7cc1 100644 --- a/backend/src/app/db.clj +++ b/backend/src/app/db.clj @@ -17,11 +17,11 @@ [app.metrics :as mtx] [app.util.json :as json] [app.util.migrations :as mg] + [app.util.logging :as l] [app.util.time :as dt] [app.util.transit :as t] [clojure.java.io :as io] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [integrant.core :as ig] [next.jdbc :as jdbc] [next.jdbc.date-time :as jdbc-dt]) @@ -60,7 +60,9 @@ (defmethod ig/init-key ::pool [_ {:keys [migrations metrics] :as cfg}] - (log/infof "initialize connection pool '%s' with uri '%s'" (name (:name cfg)) (:uri cfg)) + (l/info :action "initialize connection pool" + :name (d/name (:name cfg)) + :uri (:uri cfg)) (instrument-jdbc! (:registry metrics)) (let [pool (create-pool cfg)] (when (seq migrations) diff --git a/backend/src/app/emails.clj b/backend/src/app/emails.clj index dd0fcf4e1..5d832bc47 100644 --- a/backend/src/app/emails.clj +++ b/backend/src/app/emails.clj @@ -15,13 +15,13 @@ [app.db :as db] [app.db.sql :as sql] [app.util.emails :as emails] + [app.util.logging :as l] [app.worker :as wrk] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [integrant.core :as ig])) - ;; --- PUBLIC API + (defn render [email-factory context] (email-factory context)) @@ -181,5 +181,5 @@ (println "******** start email" (:id email) "**********") (println (.toString baos)) (println "******** end email "(:id email) "**********"))] - (log/info out)))) + (l/info :email out)))) diff --git a/backend/src/app/http.clj b/backend/src/app/http.clj index f5cf2d47d..dacd4d050 100644 --- a/backend/src/app/http.clj +++ b/backend/src/app/http.clj @@ -15,7 +15,7 @@ [app.http.errors :as errors] [app.http.middleware :as middleware] [app.metrics :as mtx] - [app.util.log4j :refer [update-thread-context!]] + [app.util.logging :as l] [clojure.spec.alpha :as s] [clojure.tools.logging :as log] [integrant.core :as ig] @@ -44,7 +44,7 @@ (defmethod ig/init-key ::server [_ {:keys [handler router ws port name metrics] :as opts}] - (log/infof "starting '%s' server on port %s." name port) + (l/info :msg "starting http server" :port port :name name) (let [pre-start (fn [^Server server] (let [handler (doto (ErrorHandler.) (.setShowStacks true) @@ -77,7 +77,9 @@ (defmethod ig/halt-key! ::server [_ {:keys [server name port] :as opts}] - (log/infof "stoping '%s' server on port %s." name port) + (l/info :msg "stoping http server" + :name name + :port port) (jetty/stop-server server)) (defn- router-handler @@ -93,11 +95,16 @@ (catch Throwable e (try (let [cdata (errors/get-error-context request e)] - (update-thread-context! cdata) - (log/errorf e "unhandled exception: %s (id: %s)" (ex-message e) (str (:id cdata))) - {:status 500 :body "internal server error"}) + (l/update-thread-context! cdata) + (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 - (log/errorf e "unhandled exception: %s" (ex-message e)) + (l/error :hint "unhandled exception" + :message (ex-message e) + :cause e) {:status 500 :body "internal server error"}))))))) diff --git a/backend/src/app/http/awsns.clj b/backend/src/app/http/awsns.clj index ea47131ce..7dccbb08c 100644 --- a/backend/src/app/http/awsns.clj +++ b/backend/src/app/http/awsns.clj @@ -14,9 +14,9 @@ [app.db :as db] [app.db.sql :as sql] [app.util.http :as http] + [app.util.logging :as l] [clojure.pprint :refer [pprint]] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [cuerdas.core :as str] [integrant.core :as ig] [jsonista.core :as j])) @@ -25,11 +25,6 @@ (declare parse-notification) (declare process-report) -(defn- pprint-report - [message] - (binding [clojure.pprint/*print-right-margin* 120] - (with-out-str (pprint message)))) - (defmethod ig/pre-init-spec ::handler [_] (s/keys :req-un [::db/pool])) @@ -42,19 +37,17 @@ (= mtype "SubscriptionConfirmation") (let [surl (get body "SubscribeURL") stopic (get body "TopicArn")] - (log/infof "subscription received (topic=%s, url=%s)" stopic surl) + (l/info :action "subscription received" :topic stopic :url surl) (http/send! {:uri surl :method :post :timeout 10000})) (= mtype "Notification") (when-let [message (parse-json (get body "Message"))] - ;; (log/infof "Received: %s" (pr-str message)) (let [notification (parse-notification cfg message)] (process-report cfg notification))) :else - (log/warn (str "unexpected data received\n" - (pprint-report body)))) - + (l/warn :hint "unexpected data received" + :report (pr-str body))) {:status 200 :body ""}))) (defn- parse-bounce @@ -184,15 +177,15 @@ (defn- process-report [cfg {:keys [type profile-id] :as report}] - (log/trace (str "procesing report:\n" (pprint-report report))) + (l/trace :action "procesing report" :report (pr-str report)) (cond ;; In this case we receive a bounce/complaint notification without ;; confirmed identity, we just emit a warning but do nothing about ;; it because this is not a normal case. All notifications should ;; come with profile identity. (nil? profile-id) - (log/warn (str "a notification without identity recevied from AWS\n" - (pprint-report report))) + (l/warn :msg "a notification without identity recevied from AWS" + :report (pr-str report)) (= "bounce" type) (register-bounce-for-profile cfg report) @@ -201,7 +194,7 @@ (register-complaint-for-profile cfg report) :else - (log/warn (str "unrecognized report received from AWS\n" - (pprint-report report))))) + (l/warn :msg "unrecognized report received from AWS" + :report (pr-str report)))) diff --git a/backend/src/app/http/errors.clj b/backend/src/app/http/errors.clj index e5e7d6af2..76ca5e638 100644 --- a/backend/src/app/http/errors.clj +++ b/backend/src/app/http/errors.clj @@ -12,8 +12,7 @@ (:require [app.common.exceptions :as ex] [app.common.uuid :as uuid] - [app.util.log4j :refer [update-thread-context!]] - [clojure.tools.logging :as log] + [app.util.logging :as l] [cuerdas.core :as str] [expound.alpha :as expound])) @@ -73,8 +72,11 @@ [error request] (let [edata (ex-data error) cdata (get-error-context request error)] - (update-thread-context! cdata) - (log/errorf error "internal error: assertion (id: %s)" (str (:id cdata))) + (l/update-thread-context! cdata) + (l/error :hint "internal error: assertion" + :error-id (str (:id cdata)) + :cause error) + {:status 500 :body {:type :server-error :data (-> edata @@ -97,10 +99,11 @@ (ex/exception? (:handling edata))) (handle-exception (:handling edata) request) (let [cdata (get-error-context request error)] - (update-thread-context! cdata) - (log/errorf error "internal error: %s (id: %s)" - (ex-message error) - (str (:id cdata))) + (l/update-thread-context! cdata) + (l/error :hint "internal error" + :error-message (ex-message error) + :error-id (str (:id cdata)) + :cause error) {:status 500 :body {:type :server-error :hint (ex-message error) @@ -111,11 +114,11 @@ (let [cdata (get-error-context request error) state (.getSQLState ^java.sql.SQLException error)] - (update-thread-context! cdata) - (log/errorf error "PSQL Exception: %s (id: %s, state: %s)" - (ex-message error) - (str (:id cdata)) - state) + (l/update-thread-context! cdata) + (l/error :hint "psql exception" + :error-message (ex-message error) + :error-id (str (:id cdata)) + :sql-state state) (cond (= state "57014") diff --git a/backend/src/app/http/oauth/github.clj b/backend/src/app/http/oauth/github.clj index 379b9143a..635af416b 100644 --- a/backend/src/app/http/oauth/github.clj +++ b/backend/src/app/http/oauth/github.clj @@ -13,10 +13,10 @@ [app.common.spec :as us] [app.http.oauth.google :as gg] [app.util.http :as http] + [app.util.logging :as l] [app.util.time :as dt] [clojure.data.json :as json] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [integrant.core :as ig] [lambdaisland.uri :as u])) @@ -63,7 +63,8 @@ (get "access_token")))) (catch Exception e - (log/error e "unexpected error on get-access-token") + (l/error :hint "unexpected error on get-access-token" + :cause e) nil))) (defn- get-user-info @@ -80,7 +81,8 @@ :backend "github" :fullname (get data "name")}))) (catch Exception e - (log/error e "unexpected exception on get-user-info") + (l/error :hint "unexpected exception on get-user-info" + :cause e) nil))) (defn- retrieve-info diff --git a/backend/src/app/http/oauth/gitlab.clj b/backend/src/app/http/oauth/gitlab.clj index 4a8b0a7c2..b3d04567e 100644 --- a/backend/src/app/http/oauth/gitlab.clj +++ b/backend/src/app/http/oauth/gitlab.clj @@ -14,10 +14,10 @@ [app.common.spec :as us] [app.http.oauth.google :as gg] [app.util.http :as http] + [app.util.logging :as l] [app.util.time :as dt] [clojure.data.json :as json] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [integrant.core :as ig] [lambdaisland.uri :as u])) @@ -62,7 +62,8 @@ (get "access_token")))) (catch Exception e - (log/error e "unexpected error on get-access-token") + (l/error :hint "unexpected error on get-access-token" + :cause e) nil))) (defn- get-user-info @@ -81,7 +82,8 @@ :fullname (get data "name")}))) (catch Exception e - (log/error e "unexpected exception on get-user-info") + (l/error :hint "unexpected exception on get-user-info" + :cause e) nil))) diff --git a/backend/src/app/http/oauth/google.clj b/backend/src/app/http/oauth/google.clj index ce9211689..aea6e6639 100644 --- a/backend/src/app/http/oauth/google.clj +++ b/backend/src/app/http/oauth/google.clj @@ -12,10 +12,10 @@ [app.common.exceptions :as ex] [app.common.spec :as us] [app.util.http :as http] + [app.util.logging :as l] [app.util.time :as dt] [clojure.data.json :as json] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [integrant.core :as ig] [lambdaisland.uri :as u])) @@ -51,7 +51,8 @@ (-> (json/read-str (:body res)) (get "access_token")))) (catch Exception e - (log/error e "unexpected error on get-access-token") + (l/error :hint "unexpected error on get-access-token" + :cause e) nil))) (defn- get-user-info @@ -69,7 +70,8 @@ :backend "google" :fullname (get data "name")}))) (catch Exception e - (log/error e "unexpected exception on get-user-info") + (l/error :hint "unexpected exception on get-user-info" + :cause e) nil))) (defn- retrieve-info diff --git a/backend/src/app/http/session.clj b/backend/src/app/http/session.clj index 316558257..8eb09eb9d 100644 --- a/backend/src/app/http/session.clj +++ b/backend/src/app/http/session.clj @@ -15,14 +15,13 @@ [app.db :as db] [app.metrics :as mtx] [app.util.async :as aa] - [app.util.log4j :refer [update-thread-context!]] + [app.util.logging :as l] [app.util.time :as dt] [app.worker :as wrk] [buddy.core.codecs :as bc] [buddy.core.nonce :as bn] [clojure.core.async :as a] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [integrant.core :as ig])) ;; --- IMPL @@ -68,7 +67,7 @@ (if-let [{:keys [id profile-id] :as session} (retrieve-from-request cfg request)] (let [ech (::events-ch cfg)] (a/>!! ech id) - (update-thread-context! {:profile-id profile-id}) + (l/update-thread-context! {:profile-id profile-id}) (handler (assoc request :profile-id profile-id))) (handler request)))) @@ -132,9 +131,9 @@ (defmethod ig/init-key ::updater [_ {:keys [session metrics] :as cfg}] - (log/infof "initialize session updater (max-batch-age=%s, max-batch-size=%s)" - (str (:max-batch-age cfg)) - (str (:max-batch-size cfg))) + (l/info :action "initialize session updater" + :max-batch-age (str (:max-batch-age cfg)) + :max-batch-size (str (:max-batch-size cfg))) (let [input (batch-events cfg (::events-ch session)) mcnt (mtx/create {:name "http_session_update_total" @@ -146,8 +145,13 @@ (let [result (a/<! (update-sessions cfg batch))] (mcnt :inc) (if (ex/exception? result) - (log/error result "updater: unexpected error on update sessions") - (log/debugf "updater: updated %s sessions (reason: %s)." result (name reason))) + (l/error :mod "updater" + :hint "unexpected error on update sessions" + :cause result) + (l/debug :mod "updater" + :action "update sessions" + :reason (name reason) + :count result)) (recur)))))) (defn- timeout-chan @@ -209,7 +213,9 @@ (let [interval (db/interval max-age) result (db/exec-one! conn [sql:delete-expired interval]) result (:next.jdbc/update-count result)] - (log/debugf "gc-task: removed %s rows from http-session table" result) + (l/debug :mod "gc-task" + :action "clean http sessions" + :count result) result)))) (def ^:private diff --git a/backend/src/app/loggers/loki.clj b/backend/src/app/loggers/loki.clj index 2514d5725..bc97b1ad6 100644 --- a/backend/src/app/loggers/loki.clj +++ b/backend/src/app/loggers/loki.clj @@ -15,10 +15,10 @@ [app.util.async :as aa] [app.util.http :as http] [app.util.json :as json] + [app.util.logging :as l] [app.worker :as wrk] [clojure.core.async :as a] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [integrant.core :as ig])) (declare handle-event) @@ -33,13 +33,13 @@ (defmethod ig/init-key ::reporter [_ {:keys [receiver uri] :as cfg}] (when uri - (log/info "intializing loki reporter") + (l/info :msg "intializing loki reporter" :uri uri) (let [output (a/chan (a/sliding-buffer 1024))] (receiver :sub output) (a/go-loop [] (let [msg (a/<! output)] (if (nil? msg) - (log/info "stoping error reporting loop") + (l/info :msg "stoping error reporting loop") (do (a/<! (handle-event cfg msg)) (recur))))) @@ -75,10 +75,14 @@ (if (= (:status response) 204) true (do - (log/errorf "error on sending log to loki (try %s)\n%s" i (pr-str response)) + (l/error :hint "error on sending log to loki" + :try i + :rsp (pr-str response)) false))) (catch Exception e - (log/errorf e "error on sending message to loki (try %s)" i) + (l/error :hint "error on sending message to loki" + :cause e + :try i) false))) (defn- handle-event diff --git a/backend/src/app/loggers/mattermost.clj b/backend/src/app/loggers/mattermost.clj index f7eef7a1c..143d8d77c 100644 --- a/backend/src/app/loggers/mattermost.clj +++ b/backend/src/app/loggers/mattermost.clj @@ -18,12 +18,12 @@ [app.util.async :as aa] [app.util.http :as http] [app.util.json :as json] + [app.util.logging :as l] [app.util.template :as tmpl] [app.worker :as wrk] [clojure.core.async :as a] [clojure.java.io :as io] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [cuerdas.core :as str] [integrant.core :as ig])) @@ -43,14 +43,14 @@ (defmethod ig/init-key ::reporter [_ {:keys [receiver] :as cfg}] - (log/info "intializing mattermost error reporter") + (l/info :msg "intializing mattermost error reporter") (let [output (a/chan (a/sliding-buffer 128) (filter #(= (:level %) "error")))] (receiver :sub output) (a/go-loop [] (let [msg (a/<! output)] (if (nil? msg) - (log/info "stoping error reporting loop") + (l/info :msg "stoping error reporting loop") (do (a/<! (handle-event cfg msg)) (recur))))) @@ -75,10 +75,12 @@ :headers {"content-type" "application/json"} :body (json/encode-str {:text text})})] (when (not= (:status rsp) 200) - (log/errorf "error on sending data to mattermost\n%s" (pr-str rsp)))) + (l/error :hint "error on sending data to mattermost" + :response (pr-str rsp)))) (catch Exception e - (log/error e "unexpected exception on error reporter")))) + (l/error :hint "unexpected exception on error reporter" + :cause e)))) (defn- persist-on-database! [{:keys [pool] :as cfg} {:keys [id] :as cdata}] @@ -116,7 +118,8 @@ (send-mattermost-notification! cfg cdata)) (persist-on-database! cfg cdata)) (catch Exception e - (log/error e "unexpected exception on error reporter"))))) + (l/error :hint "unexpected exception on error reporter" + :cause e))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Http Handler diff --git a/backend/src/app/loggers/zmq.clj b/backend/src/app/loggers/zmq.clj index 9f1b8287c..b03c3c77c 100644 --- a/backend/src/app/loggers/zmq.clj +++ b/backend/src/app/loggers/zmq.clj @@ -13,10 +13,10 @@ [app.common.data :as d] [app.common.spec :as us] [app.util.json :as json] + [app.util.logging :as l] [app.util.time :as dt] [clojure.core.async :as a] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [cuerdas.core :as str] [integrant.core :as ig]) (:import @@ -34,7 +34,7 @@ (defmethod ig/init-key ::receiver [_ {:keys [endpoint] :as cfg}] - (log/infof "intializing ZMQ receiver on '%s'" endpoint) + (l/info :msg "intializing ZMQ receiver" :bind endpoint) (let [buffer (a/chan 1) output (a/chan 1 (comp (filter map?) (map prepare))) diff --git a/backend/src/app/main.clj b/backend/src/app/main.clj index fb18c6833..7f0639d29 100644 --- a/backend/src/app/main.clj +++ b/backend/src/app/main.clj @@ -11,8 +11,8 @@ (:require [app.common.data :as d] [app.config :as cf] + [app.util.logging :as l] [app.util.time :as dt] - [clojure.tools.logging :as log] [integrant.core :as ig])) (def system-config @@ -348,8 +348,8 @@ (-> system-config (ig/prep) (ig/init)))) - (log/infof "welcome to penpot (version: '%s')" - (:full cf/version))) + (l/info :msg "welcome to penpot" + :version (:full cf/version))) (defn stop [] diff --git a/backend/src/app/metrics.clj b/backend/src/app/metrics.clj index e71283ca2..bf1daef4b 100644 --- a/backend/src/app/metrics.clj +++ b/backend/src/app/metrics.clj @@ -5,13 +5,13 @@ ;; This Source Code Form is "Incompatible With Secondary Licenses", as ;; defined by the Mozilla Public License, v. 2.0. ;; -;; Copyright (c) 2020-2021 UXBOX Labs SL +;; Copyright (c) UXBOX Labs SL (ns app.metrics (:require [app.common.exceptions :as ex] + [app.util.logging :as l] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [integrant.core :as ig]) (:import io.prometheus.client.CollectorRegistry @@ -50,7 +50,7 @@ (defmethod ig/init-key ::metrics [_ {:keys [definitions] :as cfg}] - (log/infof "Initializing prometheus registry and instrumentation.") + (l/info :action "initialize metrics") (let [registry (create-registry) definitions (reduce-kv (fn [res k v] (->> (assoc v :registry registry) diff --git a/backend/src/app/msgbus.clj b/backend/src/app/msgbus.clj index c6d7c217b..e8da9a350 100644 --- a/backend/src/app/msgbus.clj +++ b/backend/src/app/msgbus.clj @@ -14,10 +14,10 @@ [app.common.spec :as us] [app.config :as cfg] [app.util.blob :as blob] + [app.util.logging :as l] [app.util.time :as dt] [clojure.core.async :as a] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [integrant.core :as ig] [promesa.core :as p]) (:import @@ -60,7 +60,8 @@ (defmethod ig/init-key ::msgbus [_ {:keys [backend buffer-size] :as cfg}] - (log/debugf "initializing msgbus (backend=%s)" (name backend)) + (l/debug :action "initialize msgbus" + :backend (name backend)) (let [cfg (init-backend cfg) ;; Channel used for receive publications from the application. @@ -165,13 +166,14 @@ (when-let [val (a/<! pub-ch)] (let [result (a/<! (impl-redis-pub rac val))] (when (ex/exception? result) - (log/error result "unexpected error on publish message to redis"))) + (l/error :cause result + :hint "unexpected error on publish message to redis"))) (recur))))) (defmethod init-sub-loop :redis [{:keys [::sub-conn ::sub-ch buffer-size]}] (let [rcv-ch (a/chan (a/dropping-buffer buffer-size)) - chans (agent {} :error-handler #(log/error % "unexpected error on agent")) + chans (agent {} :error-handler #(l/error :cause % :hint "unexpected error on agent")) rac (.async ^StatefulRedisPubSubConnection sub-conn)] ;; Add a unique listener to connection @@ -184,7 +186,7 @@ ;; more messages that we can process. (let [val {:topic topic :message (blob/decode message)}] (when-not (a/offer! rcv-ch val) - (log/warn "dropping message on subscription loop")))) + (l/warn :msg "dropping message on subscription loop")))) (psubscribed [it pattern count]) (punsubscribed [it pattern count]) (subscribed [it topic count]) @@ -194,9 +196,12 @@ (let [nsubs (if (nil? nsubs) #{chan} (conj nsubs chan))] (when (= 1 (count nsubs)) (let [result (a/<!! (impl-redis-sub rac topic))] - (log/tracef "opening subscription to %s" topic) + (l/trace :action "open subscription" + :topic topic) (when (ex/exception? result) - (log/errorf result "unexpected exception on subscribing to '%s'" topic)))) + (l/error :cause result + :hint "unexpected exception on subscribing" + :topic topic)))) nsubs)) (subscribe-to-topics [state topics chan] @@ -210,9 +215,12 @@ (let [nsubs (disj nsubs chan)] (when (empty? nsubs) (let [result (a/<!! (impl-redis-unsub rac topic))] - (log/tracef "closing subscription to %s" topic) + (l/trace :action "close subscription" + :topic topic) (when (ex/exception? result) - (log/errorf result "unexpected exception on unsubscribing from '%s'" topic)))) + (l/error :cause result + :hint "unexpected exception on unsubscribing" + :topic topic)))) nsubs)) (unsubscribe-channels [state pending] @@ -246,7 +254,6 @@ (recur (rest chans) pending) (recur (rest chans) (conj pending ch))) pending))] - ;; (log/tracef "received message => pending: %s" (pr-str pending)) (some->> (seq pending) (send-off chans unsubscribe-channels)) diff --git a/backend/src/app/notifications.clj b/backend/src/app/notifications.clj index 9897b7a32..75cb64f46 100644 --- a/backend/src/app/notifications.clj +++ b/backend/src/app/notifications.clj @@ -14,12 +14,12 @@ [app.db :as db] [app.metrics :as mtx] [app.util.async :as aa] + [app.util.logging :as l] [app.util.time :as dt] [app.util.transit :as t] [app.worker :as wrk] [clojure.core.async :as a] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [integrant.core :as ig] [ring.adapter.jetty9 :as jetty] [ring.middleware.cookies :refer [wrap-cookies]] @@ -149,7 +149,9 @@ :out-ch out-ch :sub-ch sub-ch)] - (log/tracef "on-connect %s" (:session-id cfg)) + (l/log :level :trace + :action "connect" + :session (:session-id cfg)) ;; Forward all messages from out-ch to the websocket ;; connection @@ -172,19 +174,26 @@ (a/close! sub-ch)))) (on-error [_conn e] - (log/tracef "on-error %s (%s)" (:session-id cfg) (ex-message e)) + (l/log :level :trace + :action "error" + :session (:session-id cfg)) + (a/close! out-ch) (a/close! rcv-ch)) (on-close [_conn _status _reason] - (log/tracef "on-close %s" (:session-id cfg)) + (l/log :level :trace + :action "close" + :session (:session-id cfg)) + (a/close! out-ch) (a/close! rcv-ch)) (on-message [_ws message] (let [message (t/decode-str message)] (when-not (a/offer! rcv-ch message) - (log/warn "droping ws input message, channe full"))))] + (l/log :level :warn + :msg "drop messages"))))] {:on-connect on-connect :on-error on-error @@ -254,12 +263,10 @@ (defmethod handle-message :connect [cfg _] - ;; (log/debugf "profile '%s' is connected to file '%s'" profile-id file-id) (send-presence cfg :connect)) (defmethod handle-message :disconnect [cfg _] - ;; (log/debugf "profile '%s' is disconnected from '%s'" profile-id file-id) (send-presence cfg :disconnect)) (defmethod handle-message :keepalive @@ -277,5 +284,7 @@ (defmethod handle-message :default [_ws message] (a/go - (log/warnf "received unexpected message: %s" message))) + (l/log :level :warn + :msg "received unexpected message" + :message message))) diff --git a/backend/src/app/rpc.clj b/backend/src/app/rpc.clj index de202964b..ab16c0c37 100644 --- a/backend/src/app/rpc.clj +++ b/backend/src/app/rpc.clj @@ -5,7 +5,7 @@ ;; This Source Code Form is "Incompatible With Secondary Licenses", as ;; defined by the Mozilla Public License, v. 2.0. ;; -;; Copyright (c) 2020-2021 UXBOX Labs SL +;; Copyright (c) UXBOX Labs SL (ns app.rpc (:require @@ -15,9 +15,9 @@ [app.db :as db] [app.metrics :as mtx] [app.rlimits :as rlm] + [app.util.logging :as l] [app.util.services :as sv] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [cuerdas.core :as str] [integrant.core :as ig])) @@ -76,7 +76,8 @@ (ex/raise :type :internal :code :rlimit-not-configured :hint (str/fmt "%s rlimit not configured" key))) - (log/tracef "adding rlimit to '%s' rpc handler" (::sv/name mdata)) + (l/trace :action "add rlimit" + :handler (::sv/name mdata)) (fn [cfg params] (rlm/execute rlinst (f cfg params)))) f)) @@ -86,7 +87,8 @@ (let [f (wrap-with-rlimits cfg f mdata) f (wrap-with-metrics cfg f mdata) spec (or (::sv/spec mdata) (s/spec any?))] - (log/tracef "registering '%s' command to rpc service" (::sv/name mdata)) + (l/trace :action "register" + :name (::sv/name mdata)) (fn [params] (when (and (:auth mdata true) (not (uuid? (:profile-id params)))) (ex/raise :type :authentication diff --git a/backend/src/app/storage.clj b/backend/src/app/storage.clj index 94e7e3b70..e8621ac8b 100644 --- a/backend/src/app/storage.clj +++ b/backend/src/app/storage.clj @@ -19,10 +19,10 @@ [app.storage.fs :as sfs] [app.storage.impl :as impl] [app.storage.s3 :as ss3] + [app.util.logging :as l] [app.util.time :as dt] [app.worker :as wrk] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [cuerdas.core :as str] [datoteka.core :as fs] [integrant.core :as ig] @@ -310,7 +310,9 @@ (run! (partial delete-in-bulk conn) groups) (recur (+ n ^long total))) (do - (log/infof "gc-deleted: processed %s items" n) + (l/info :task "gc-deleted" + :action "permanently delete items" + :count n) {:deleted n}))))))) (def sql:retrieve-deleted-objects @@ -382,7 +384,12 @@ (recur (+ cntf (count to-freeze)) (+ cntd (count to-delete)))) (do - (log/infof "gc-touched: %s objects marked as freeze and %s marked to be deleted" cntf cntd) + (l/info :task "gc-touched" + :action "mark freeze" + :count cntf) + (l/info :task "gc-touched" + :action "mark for deletion" + :count cntd) {:freeze cntf :delete cntd}))))))) (def sql:retrieve-touched-objects @@ -459,7 +466,10 @@ (recur (+ n (count all)) (+ d (count to-delete)))) (do - (log/infof "recheck: processed %s items, %s deleted" n d) + (l/info :task "recheck" + :action "recheck items" + :processed n + :deleted n) {:processed n :deleted d}))))))) (def sql:retrieve-pending-to-recheck diff --git a/backend/src/app/svgparse.clj b/backend/src/app/svgparse.clj index 0dd3621f9..5a773d28c 100644 --- a/backend/src/app/svgparse.clj +++ b/backend/src/app/svgparse.clj @@ -11,8 +11,8 @@ (:require [app.common.exceptions :as ex] [app.metrics :as mtx] + [app.util.logging :as l] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [clojure.xml :as xml] [integrant.core :as ig]) (:import @@ -60,7 +60,8 @@ (with-open [istream (IOUtils/toInputStream data "UTF-8")] (xml/parse istream secure-factory)) (catch Exception e - (log/warnf "error on processing svg: %s" (ex-message e)) + (l/warn :hint "error on processing svg" + :message (ex-message e)) (ex/raise :type :validation :code :invalid-svg-file :cause e)))) diff --git a/backend/src/app/tasks/delete_object.clj b/backend/src/app/tasks/delete_object.clj index 78fd47007..91fa1f702 100644 --- a/backend/src/app/tasks/delete_object.clj +++ b/backend/src/app/tasks/delete_object.clj @@ -5,15 +5,16 @@ ;; 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) UXBOX Labs SL (ns app.tasks.delete-object "Generic task for permanent deletion of objects." (:require + [app.common.data :as d] [app.common.spec :as us] [app.db :as db] + [app.util.logging :as l] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [integrant.core :as ig])) (declare handle-deletion) @@ -37,7 +38,8 @@ (defmethod handle-deletion :default [_conn {:keys [type]}] - (log/warnf "no handler found for '%s'" type)) + (l/warn :hint "no handler found" + :type (d/name type))) (defmethod handle-deletion :file [conn {:keys [id] :as props}] diff --git a/backend/src/app/tasks/delete_profile.clj b/backend/src/app/tasks/delete_profile.clj index 923ccf814..5c05a1d8a 100644 --- a/backend/src/app/tasks/delete_profile.clj +++ b/backend/src/app/tasks/delete_profile.clj @@ -13,8 +13,8 @@ [app.common.spec :as us] [app.db :as db] [app.db.sql :as sql] + [app.util.logging :as l] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [integrant.core :as ig])) (declare delete-profile-data) @@ -47,7 +47,8 @@ (if (or (:is-demo profile) (:deleted-at profile)) (delete-profile-data conn id) - (log/warnf "profile '%s' does not match constraints for deletion" id)))))) + (l/warn :hint "profile does not match constraints for deletion" + :profile-id id)))))) ;; --- IMPL @@ -70,7 +71,8 @@ (defn- delete-profile-data [conn profile-id] - (log/debugf "proceding to delete all data related to profile '%s'" profile-id) + (l/debug :action "delete profile" + :profile-id profile-id) (delete-teams conn profile-id) (delete-profile conn profile-id) true) diff --git a/backend/src/app/tasks/file_media_gc.clj b/backend/src/app/tasks/file_media_gc.clj index eebd434b5..cad9b1e02 100644 --- a/backend/src/app/tasks/file_media_gc.clj +++ b/backend/src/app/tasks/file_media_gc.clj @@ -15,9 +15,9 @@ [app.common.pages.migrations :as pmg] [app.db :as db] [app.util.blob :as blob] + [app.util.logging :as l] [app.util.time :as dt] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [integrant.core :as ig])) (declare process-file) @@ -40,7 +40,7 @@ (run! (partial process-file cfg) files) (recur (+ n (count files)))) (do - (log/debugf "finalized with total of %s processed files" n) + (l/debug :msg "finished processing files" :processed n) {:processed n})))))))) (def ^:private @@ -88,7 +88,10 @@ unused (->> (db/query conn :file-media-object {:file-id id}) (remove #(contains? used (:id %))))] - (log/debugf "processing file: id='%s' age='%s' to-delete=%s" id age (count unused)) + (l/debug :action "processing file" + :id id + :age age + :to-delete (count unused)) ;; Mark file as trimmed (db/update! conn :file @@ -96,8 +99,10 @@ {:id id}) (doseq [mobj unused] - (log/debugf "deleting media object: id='%s' media-id='%s' thumb-id='%s'" - (:id mobj) (:media-id mobj) (:thumbnail-id mobj)) + (l/debug :action "deleting media object" + :id (:id mobj) + :media-id (:media-id mobj) + :thumbnail-id (:thumbnail-id mobj)) ;; NOTE: deleting the file-media-object in the database ;; automatically marks as toched the referenced storage objects. (db/delete! conn :file-media-object {:id (:id mobj)})) diff --git a/backend/src/app/tasks/file_xlog_gc.clj b/backend/src/app/tasks/file_xlog_gc.clj index d333f2ac5..adff21a55 100644 --- a/backend/src/app/tasks/file_xlog_gc.clj +++ b/backend/src/app/tasks/file_xlog_gc.clj @@ -5,16 +5,16 @@ ;; This Source Code Form is "Incompatible With Secondary Licenses", as ;; defined by the Mozilla Public License, v. 2.0. ;; -;; Copyright (c) 2020-2021 UXBOX Labs SL +;; Copyright (c) UXBOX Labs SL (ns app.tasks.file-xlog-gc "A maintenance task that performs a garbage collection of the file change (transaction) log." (:require [app.db :as db] + [app.util.logging :as l] [app.util.time :as dt] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [integrant.core :as ig])) (declare sql:delete-files-xlog) @@ -31,7 +31,7 @@ (let [interval (db/interval max-age) result (db/exec-one! conn [sql:delete-files-xlog interval]) result (:next.jdbc/update-count result)] - (log/debugf "removed %s rows from file-change table" result) + (l/debug :action "trim file-change table" :removed result) result)))) (def ^:private diff --git a/backend/src/app/tasks/tasks_gc.clj b/backend/src/app/tasks/tasks_gc.clj index 3ff4e8db0..3dc19353a 100644 --- a/backend/src/app/tasks/tasks_gc.clj +++ b/backend/src/app/tasks/tasks_gc.clj @@ -5,16 +5,16 @@ ;; This Source Code Form is "Incompatible With Secondary Licenses", as ;; defined by the Mozilla Public License, v. 2.0. ;; -;; Copyright (c) 2020-2021 UXBOX Labs SL +;; Copyright (c) UXBOX Labs SL (ns app.tasks.tasks-gc "A maintenance task that performs a cleanup of already executed tasks from the database table." (:require [app.db :as db] + [app.util.logging :as l] [app.util.time :as dt] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [integrant.core :as ig])) (declare sql:delete-completed-tasks) @@ -31,7 +31,7 @@ (let [interval (db/interval max-age) result (db/exec-one! conn [sql:delete-completed-tasks interval]) result (:next.jdbc/update-count result)] - (log/debugf "removed %s rows from tasks-completed table" result) + (l/debug :action "trim completed tasks table" :removed result) result)))) (def ^:private diff --git a/backend/src/app/util/log4j.clj b/backend/src/app/util/log4j.clj deleted file mode 100644 index cd41bae78..000000000 --- a/backend/src/app/util/log4j.clj +++ /dev/null @@ -1,27 +0,0 @@ -;; 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) 2021 UXBOX Labs SL - -(ns app.util.log4j - (:require - [clojure.pprint :refer [pprint]]) - (:import - org.apache.logging.log4j.ThreadContext)) - -(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)) diff --git a/backend/src/app/util/logging.clj b/backend/src/app/util/logging.clj new file mode 100644 index 000000000..afe03bab7 --- /dev/null +++ b/backend/src/app/util/logging.clj @@ -0,0 +1,111 @@ +;; 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) UXBOX Labs SL + +(ns app.util.logging + (:require + [linked.core :as lk] + [clojure.pprint :refer [pprint]]) + (:import + java.util.Map + org.apache.logging.log4j.Level + org.apache.logging.log4j.LogManager + org.apache.logging.log4j.Logger + org.apache.logging.log4j.ThreadContext + org.apache.logging.log4j.message.MapMessage + org.apache.logging.log4j.spi.LoggerContext)) + +(defn build-map-message + [m] + (let [message (MapMessage. (count m))] + (reduce-kv #(.with ^MapMessage %1 (name %2) %3) message m))) + +(defprotocol ILogger + (-enabled? [logger level]) + (-write! [logger level throwable message])) + +(def logger-context + (LogManager/getContext false)) + +(def logging-agent + (agent nil :error-mode :continue)) + +(defn get-logger + [lname] + (.getLogger ^LoggerContext logger-context ^String lname)) + +(defn get-level + [level] + (case level + :trace Level/TRACE + :debug Level/DEBUG + :info Level/INFO + :warn Level/WARN + :error Level/ERROR + :fatal Level/FATAL)) + +(defn enabled? + [logger level] + (.isEnabled ^Logger logger ^Level level)) + +(defn write-log! + [logger level e msg] + (if e + (.log ^Logger logger + ^Level level + ^Object msg + ^Throwable e) + (.log ^Logger logger + ^Level level + ^Object msg))) + +(defmacro log + [& {:keys [level cause msg ::logger ::async] :as props}] + (let [props (dissoc props :level :cause ::logger ::async) + logger (or logger (str *ns*)) + logger-sym (gensym "log") + level-sym (gensym "log")] + `(let [~logger-sym (get-logger ~logger) + ~level-sym (get-level ~level)] + (if (enabled? ~logger-sym ~level-sym) + ~(if async + `(send-off logging-agent (fn [_#] (write-log! ~logger-sym ~level-sym ~cause (build-map-message ~props)))) + `(write-log! ~logger-sym ~level-sym ~cause (build-map-message ~props))))))) + +(defmacro info + [& params] + `(log :level :info ~@params)) + +(defmacro error + [& params] + `(log :level :error ~@params)) + +(defmacro warn + [& params] + `(log :level :warn ~@params)) + +(defmacro debug + [& params] + `(log :level :debug ~@params)) + +(defmacro trace + [& params] + `(log :level :trace ~@params)) + +(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)) diff --git a/backend/src/app/util/migrations.clj b/backend/src/app/util/migrations.clj index 9255657ab..bc47f5967 100644 --- a/backend/src/app/util/migrations.clj +++ b/backend/src/app/util/migrations.clj @@ -5,13 +5,13 @@ ;; 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) UXBOX Labs SL (ns app.util.migrations (:require + [app.util.logging :as l] [clojure.java.io :as io] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [cuerdas.core :as str] [next.jdbc :as jdbc])) @@ -40,7 +40,7 @@ (defn- impl-migrate-single [pool modname {:keys [name] :as migration}] (when-not (registered? pool modname (:name migration)) - (log/info (str/format "applying migration %s/%s" modname name)) + (l/info :action "apply migration" :module modname :name name) (register! pool modname name) ((:fn migration) pool))) diff --git a/backend/src/app/worker.clj b/backend/src/app/worker.clj index 76a2ab8c3..229d4c7b6 100644 --- a/backend/src/app/worker.clj +++ b/backend/src/app/worker.clj @@ -17,11 +17,10 @@ [app.db :as db] [app.metrics :as mtx] [app.util.async :as aa] - [app.util.log4j :refer [update-thread-context!]] + [app.util.logging :as l] [app.util.time :as dt] [clojure.core.async :as a] [clojure.spec.alpha :as s] - [clojure.tools.logging :as log] [cuerdas.core :as str] [integrant.core :as ig] [promesa.exec :as px]) @@ -91,7 +90,10 @@ (defmethod ig/init-key ::worker [_ {:keys [pool poll-interval name queue] :as cfg}] - (log/infof "starting worker '%s' on queue '%s'" (d/name name) (d/name queue)) + (l/log :level :info + :msg "start" + :name (d/name name) + :queue (d/name queue)) (let [close-ch (a/chan 1) poll-ms (inst-ms poll-interval)] (a/go-loop [] @@ -100,30 +102,32 @@ ;; Terminate the loop if close channel is closed or ;; event-loop-fn returns nil. (or (= port close-ch) (nil? val)) - (log/infof "stop condition found; shutdown worker: '%s'" (d/name name)) + (l/log :level :debug :msg "stop condition found") (db/pool-closed? pool) (do - (log/info "worker eventloop is aborted because pool is closed") + (l/log :level :debug :msg "eventloop aboirted because pool is closed") (a/close! close-ch)) (and (instance? java.sql.SQLException val) (contains? #{"08003" "08006" "08001" "08004"} (.getSQLState ^java.sql.SQLException val))) (do - (log/error "connection error, trying resume in some instants") + (l/log :level :error :hint "connection error, trying resume in some instants") (a/<! (a/timeout poll-interval)) (recur)) (and (instance? java.sql.SQLException val) (= "40001" (.getSQLState ^java.sql.SQLException val))) (do - (log/debug "serialization failure (retrying in some instants)") + (l/log :level :debug :msg "serialization failure (retrying in some instants)") (a/<! (a/timeout poll-ms)) (recur)) (instance? Exception val) (do - (log/errorf val "unexpected error ocurried on polling the database (will resume in some instants)") + (l/log :level :error + :cause val + :hint "unexpected error ocurried on polling the database (will resume in some instants)") (a/<! (a/timeout poll-ms)) (recur)) @@ -181,7 +185,10 @@ interval (db/interval duration) props (-> options extract-props db/tjson) id (uuid/next)] - (log/debugf "submit task '%s' to be executed in '%s'" (d/name task) (str duration)) + (l/log :level :debug + :action "submit task" + :name (d/name task) + :in duration) (db/exec-one! conn [sql:insert-new-task id (d/name task) props (d/name queue) priority max-retries interval]) id)) @@ -242,7 +249,9 @@ (let [task-fn (get tasks name)] (if task-fn (task-fn item) - (log/warnf "no task handler found for '%s'" (d/name name))) + (l/log :level :warn + :msg "no task handler found" + :name (d/name name))) {:status :completed :task item})) (defn get-error-context @@ -266,8 +275,12 @@ (assoc :inc-by 0)) (let [cdata (get-error-context error item)] - (update-thread-context! cdata) - (log/errorf error "unhandled exception on task (id: '%s')" (:id cdata)) + (l/update-thread-context! cdata) + (l/log :level :error + :cause error + :hint "unhandled exception on task" + :id (:id cdata)) + (if (>= (:retry-num item) (:max-retries item)) {:status :failed :task item :error error} {:status :retry :task item :error error}))))) @@ -276,12 +289,21 @@ [{:keys [tasks]} item] (let [name (d/name (:name item))] (try - (log/debugf "started task '%s/%s/%s'" name (:id item) (:retry-num item)) + (l/log :level :debug + :action "start task" + :name name + :id (:id item) + :retry (:retry-num item)) + (handle-task tasks item) (catch Exception e (handle-exception e item)) (finally - (log/debugf "finished task '%s/%s/%s'" name (:id item) (:retry-num item)))))) + (l/log :level :debug + :action "start task" + :name name + :id (:id item) + :retry (:retry-num item)))))) (def sql:select-next-tasks "select * from task as t @@ -349,8 +371,8 @@ ;; If id is not defined, use the task as id. (map (fn [{:keys [id task] :as item}] (if (some? id) - item - (assoc item :id task)))) + (assoc item :id (d/name id)) + (assoc item :id (d/name task))))) (map (fn [{:keys [task] :as item}] (let [f (get tasks task)] (when-not f @@ -387,7 +409,10 @@ [conn {:keys [id cron]}] (let [cron (str cron) id (name id)] - (log/infof "initialize scheduled task '%s' (cron: '%s')" id cron) + (l/log :level :debug + :action "initialize scheduled task" + :id id + :cron cron) (db/exec-one! conn [sql:upsert-scheduled-task id cron cron]))) (defn- synchronize-schedule @@ -407,8 +432,10 @@ [{:keys [executor pool] :as cfg} {:keys [id] :as task}] (letfn [(run-task [conn] (try - (when (db/exec-one! conn [sql:lock-scheduled-task id]) - (log/debugf "executing scheduled task '%s'" id) + (when (db/exec-one! conn [sql:lock-scheduled-task (d/name id)]) + (l/log :level :debug + :action "execute scheduled task" + :id id) ((:fn task) task)) (catch Throwable e e))) @@ -417,7 +444,10 @@ (db/with-atomic [conn pool] (let [result (run-task conn)] (when (ex/exception? result) - (log/errorf result "unhandled exception on scheduled task '%s'" id)))))] + (l/log :level :error + :cause result + :hint "unhandled exception on scheduled task" + :id id)))))] (try (px/run! executor handle-task) @@ -490,7 +520,9 @@ :help "Background task execution timing."})] (reduce-kv (fn [res k v] (let [tname (name k)] - (log/debugf "registring task '%s'" tname) + (l/log :level :debug + :action "register task" + :name tname) (assoc res k (mtx/wrap-summary v mobj [tname])))) {} tasks)))