Skip to content

Instantly share code, notes, and snippets.

@martinklepsch
Created December 3, 2020 13:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save martinklepsch/0a146f46dfc7a304eaec0f348e5a5d36 to your computer and use it in GitHub Desktop.
Save martinklepsch/0a146f46dfc7a304eaec0f348e5a5d36 to your computer and use it in GitHub Desktop.
(ns icebreaker.util.sentry
{:clj-kondo/config '{:linters
{:unresolved-symbol {:exclude [sentry]}
:unresolved-namespace {:exclude [sentry]}}}}
(:require #?(:node ["@sentry/node" :as sentry]
:browser ["@sentry/browser" :as sentry])
#?@(:cljs [[promesa.core :as p]
[icebreaker.config :as config]
[icebreaker.model :as model]])))
#?(:cljs
(do
(defn dsn
[]
(when-let [{:keys [public-key
host
project-id]} config/sentry-config]
(str "https://" public-key "@" host "/" project-id)))
(defn init
[]
(when-let [d (dsn)]
(println "[init] sentry" config/ENV config/RELEASE (:project-name config/sentry-config))
(sentry/init #js {:dsn d
:release config/RELEASE
:environment config/ENV})
true))
(defn set-user!
[user]
(some-> ^js sentry
(.configureScope (fn [^js scope]
(.setUser scope (clj->js user))))))
(defn set-event!
[event-id event]
(some-> ^js sentry
(.configureScope (fn [^js scope]
(.setTag scope "event.id" event-id)))))
(defn set-ex-data!
"When passed an instance of `ExceptionInfo` this will add the data
attached to the exception object as additional context on the error.
If the exception data contains a `:name` key that will be used as the
exception class that is visible most prominently in Sentry."
;; This could eventually replace things like `set-event!` above by
;; supporting a `:tags` key which sets the appropriate tags w/ setTag.
[e]
(when (instance? ExceptionInfo e)
(some->> e ex-data :name (set! (.-name e)))
(.configureScope ^js sentry (fn [^js scope]
(.setExtra scope "ex-data" (pr-str (dissoc (ex-data e) :name)))))))
(defn capture-message! [msg]
(.captureMessage ^js sentry msg)
nil)
(defn capture!
[e]
(if-not (.. ^js sentry (getCurrentHub) (getClient))
(js/console.log "No client: Sentry not initialized for error:" e)
(do
(js/console.log "Reporting error to Sentry:" (.-message e))
(set-ex-data! e)
(.captureException ^js sentry e)
;; .flush will ensure errors are written to sentry before exiting
;; https://docs.sentry.io/error-reporting/configuration/draining/?platform=javascript
;; TODO investigate not rethrowing to improve function performance
;; NOTE would probably require a refactor of how we do middleware
;; https://cloud.google.com/functions/docs/monitoring/error-reporting
(-> (.flush ^js sentry 10000)
(.then #(throw e))))))
(defn wrap-capture!
[f]
(fn [& args]
(try
(let [ret (apply f args)]
(if (p/promise? ret)
(.catch ret capture!)
ret))
(catch js/Error e (capture! e)))))
(def log-level
{:critical "critical"
:fatal "fatal"
:error "error"
:warn "warning"
:info "info"
:debug "debug"
:log "log"})
(defn breadcrumb!
[{:keys [category
level
message
data]
:or {category "log"
level :info}}]
(let [slevel (get log-level level)]
(assert slevel (str "invalid sentry log level" level))
(some-> ^js sentry
(.addBreadcrumb #js {:category category
:level slevel
:message message
:data data}))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment