Skip to content

Commit

Permalink
Migrate to sentry-clj. Getting rid of raven lib. (#65)
Browse files Browse the repository at this point in the history
- Migration to sentry-clj library.
- Getting rid of unsupported raven library.
  • Loading branch information
arthuraliiev authored Mar 18, 2024
1 parent e442ea2 commit c3fa4f4
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 38 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,14 @@ Reporter provides a [component](https://github.com/stuartsierra/component) in or

### Changelog

#### 1.0.0

- Migrating from `exoscale/raven` to `io.sentry/sentry-clj`
- `raven-options` renamed to `sentry-options` within `spootnik.reporter.impl/Reporter` signature

#### 0.2.0

- Allow arbitray values for counter
- Allow arbitray values for counter

#### 0.1.60

Expand Down
2 changes: 1 addition & 1 deletion deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
{org.clojure/clojure "1.9.0"
org.clojure/tools.logging "0.4.0"
com.stuartsierra/component "0.3.2"
exoscale/raven "0.4.2"
io.sentry/sentry-clj "7.4.213"
spootnik/net "0.3.3-beta24"
spootnik/uncaught "0.5.3"
metrics-clojure "2.10.0"
Expand Down
2 changes: 1 addition & 1 deletion project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
[org.clojure/clojure "1.10.1"]
[org.clojure/tools.logging "1.0.0"]
[com.stuartsierra/component "1.0.0"]
[exoscale/raven "0.4.15"]
[io.sentry/sentry-clj "7.4.213"]
[spootnik/uncaught "0.5.5"]
[metrics-clojure "2.10.0"]
[metrics-clojure-riemann "2.10.0"]
Expand Down
10 changes: 4 additions & 6 deletions src/spootnik/reporter.clj
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
(ns spootnik.reporter
(:require [com.stuartsierra.component :as c]
[clojure.tools.logging :as log]
[raven.client :as raven]
[spootnik.reporter.impl :as rptr]
[manifold.deferred :as d]
spootnik.reporter.specs))
Expand Down Expand Up @@ -80,11 +79,10 @@

([error extra]
(log/error error)
(-> (capture! (-> (if (instance? Exception error)
(-> {:data (ex-data error)}
(raven/add-exception! error))
{:message error})
(raven/add-extra! extra)))
(-> (capture! (if (instance? Exception error)
{:extra extra
:throwable error}
{:message error}))
(d/catch Throwable
(fn [e]
(log/error e "Sentry failure")))
Expand Down
51 changes: 23 additions & 28 deletions src/spootnik/reporter/impl.clj
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
(ns spootnik.reporter.impl
(:require [aleph.http :as http]
[manifold.deferred :as d]
[clojure.java.io :as io]
[com.stuartsierra.component :as c]
[raven.client :as raven]
[metrics.reporters.console :as console]
[metrics.reporters.jmx :as jmx]
[metrics.reporters.graphite :as graphite]
Expand All @@ -19,7 +17,8 @@
[camel-snake-kebab.core :as csk]
[clojure.string :as str]
[clojure.tools.logging :refer [info error]]
[spootnik.uncaught :refer [with-uncaught]])
[spootnik.uncaught :refer [with-uncaught]]
[spootnik.reporter.sentry :as rs])
(:import com.aphyr.riemann.client.RiemannClient
com.aphyr.riemann.client.RiemannBatchClient
com.aphyr.riemann.client.TcpTransport
Expand Down Expand Up @@ -209,7 +208,7 @@
state (or (:state ev) (:state defaults))
time ^Long (or time (quot (System/currentTimeMillis) 1000))]
(-> (.event client)
(.host (or host (:host defaults) (raven/localhost)))
(.host (or host (:host defaults) (rs/localhost)))
(.service (or service (:service defaults) "<none>"))
(.time (long time))
(cond-> metric (.metric metric)
Expand Down Expand Up @@ -372,24 +371,25 @@
(defn parse-pggrouping-keys [grouping-keys]
(into {} (for [[k v] grouping-keys] [(csk/->snake_case_string k) v])))

;; "sentry" is a sentry map like {:dsn "..."}
;; "raven-options" is the options map sent to raven http client
;; http://aleph.io/codox/aleph/aleph.http.html#var-request
(defrecord Reporter [rclient raven-options reporters registry sentry metrics riemann prevent-capture? prometheus
;; Reporter configuration specs:
;; https://github.com/exoscale/reporter/blob/master/src/spootnik/reporter/specs.clj

(defrecord Reporter [rclient sentry-options reporters registry sentry
metrics riemann prevent-capture? prometheus
started? pushgateway]
c/Lifecycle
(start [this]
(if started?
this
(let [prometheus-registry (CollectorRegistry/defaultRegistry)
(let [prometheus-registry (CollectorRegistry/defaultRegistry)
[pgclient pgjob pgregistry pggrouping-keys] (when pushgateway [(build-pushgateway-client pushgateway)
(name (:job pushgateway))
(CollectorRegistry.)
(parse-pggrouping-keys (:grouping-keys pushgateway))])
pgmetrics (when pushgateway (build-collectors! pgregistry (get-in metrics [:reporters :pushgateway])))
rclient (when riemann (riemann-client riemann))
[reg reps] (build-metrics metrics rclient prometheus-registry pgregistry)
options (when sentry (or raven-options {}))
options (when sentry (or sentry-options {}))
prometheus-server (when prometheus
(let [tls (:tls prometheus)
opts (cond-> {:port (:port prometheus)}
Expand All @@ -405,14 +405,17 @@
prometheus
prometheus-registry)
opts)))]

(rs/init! sentry)

(when-not prevent-capture?
(with-uncaught e
(capture! (assoc this :raven-options options) e)))
(capture! (assoc this :sentry-options options) e)))
(cond-> (assoc this
:registry reg
:reporters reps
:rclient rclient
:raven-options options
:sentry-options options
:started? true)
prometheus (assoc :prometheus {:server prometheus-server
:registry prometheus-registry})
Expand All @@ -436,9 +439,12 @@
(.close ^RiemannClient rclient)
(catch Exception _)))
(when prometheus
(.close ^java.io.Closeable (:server prometheus))))
(.close ^java.io.Closeable (:server prometheus)))

(rs/close! sentry))

(assoc this
:raven-options nil
:sentry-options nil
:reporters nil
:registry nil
:rclient nil
Expand Down Expand Up @@ -516,21 +522,10 @@
SentrySink
(capture! [this e]
(capture! this e {}))
(capture! [this e tags]
(if (:dsn sentry)
(-> (try
(raven/capture! raven-options (:dsn sentry) e tags)
(catch Exception e
(d/error-deferred e)))
(d/chain
(fn [event-id]
(error e (str "captured exception as sentry event: " event-id))))
(d/catch (fn [e']
(error e "Failed to capture exception" {:tags tags :capture-exception e'})
(capture! this e'))))
(error e)))
(capture! [_this e tags]
(rs/send-event! (:dsn sentry) sentry-options e tags))
RiemannSink
(send! [this ev]
(send! [_this ev]
(when rclient
(let [to-seq #(if-not (sequential? %) [%] %)]
(->> ev
Expand Down
115 changes: 115 additions & 0 deletions src/spootnik/reporter/sentry.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
(ns spootnik.reporter.sentry
(:require
[sentry-clj.core :as sentry-io]
[manifold.deferred :as d]
[clojure.string :as str]
[clojure.tools.logging :refer [error]]
[clojure.java.shell :as sh]))

(def http-requests-payload-stub
"Storage for stubbed http sentry events "
(atom nil))

(defn in-memory? [dsn]
(or (= dsn ":memory:")
(nil? dsn)))

(def hostname-refresh-interval
"How often to allow reading /etc/hostname, in seconds."
60)

(defn get-hostname
"Get the current hostname by shelling out to 'hostname'"
[]
(or
(try
(let [{:keys [exit out]} (sh/sh "hostname")]
(when (= exit 0)
(str/trim out)))
(catch Exception _))
"<unknown>"))

(defn hostname
"Fetches the hostname by shelling to 'hostname', whenever the given age
is stale enough. If the given age is recent, as defined by
hostname-refresh-interval, returns age and val instead."
[[age val]]
(if (and val (<= (* 1000 hostname-refresh-interval)
(- (System/currentTimeMillis) age)))
[age val]
[(System/currentTimeMillis) (get-hostname)]))

(let [cache (atom [nil nil])]
(defn localhost
"Returns the local host name."
[]
(if (re-find #"^Windows" (System/getProperty "os.name"))
(or (System/getenv "COMPUTERNAME") "localhost")
(or (System/getenv "HOSTNAME")
(second (swap! cache hostname))))))

(defn- payload->sentry-request [payload]
{:url (-> payload :uri)
:method (-> payload :request-method name clojure.string/upper-case)
:query-string (-> payload :query-string)
:headers (-> payload :headers)})

(defn e->sentry-event
"
Supported event keys:
https://github.com/getsentry/sentry-clj/tree/master?tab=readme-ov-file#supported-event-keys
"

[e options tags]
(let [{:keys [message extra throwable]} e
message (or message (ex-message e))
user (some-> extra :org/uuid str)
fingerprints (some-> options :fingerpint seq)
request (some-> extra :payload payload->sentry-request)]

(cond-> {:message message
:level :error
:platform "java"
:server-name (localhost)}

throwable (assoc :throwable throwable)
extra (assoc :extra extra)
(seq tags) (assoc :tags tags)
user (assoc :user user)
fingerprints (assoc :fingerprints fingerprints)
request (assoc :request request))))

(defn send-event! [dsn options e tags]
(let [event (e->sentry-event e options tags)]
(if-not (in-memory? dsn)
(-> (try
(sentry-io/send-event event)
(catch Exception e
(d/error-deferred e)))

(d/chain
(fn [event-id]
(error e (str "captured exception as sentry event: " event-id))
event-id))

(d/catch (fn [e']
(error e "Failed to capture exception" {:tags tags :capture-exception e'})
(send-event! dsn options e' tags))))

(swap! http-requests-payload-stub conj event))))

(defn init!
"
Additional options can be found here:
https://github.com/getsentry/sentry-clj/tree/master?tab=readme-ov-file#additional-initialisation-options
"

[{:keys [dsn] :as sentry}]
(if-not (in-memory? dsn)
(sentry-io/init! dsn sentry)
(reset! http-requests-payload-stub [])))

(defn close! [{:keys [dsn]}]
(if-not (in-memory? dsn)
(sentry-io/close!)
(reset! http-requests-payload-stub nil)))
2 changes: 1 addition & 1 deletion test/spootnik/reporter/impl_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[prometheus.core :as prometheus]
[spootnik.reporter.impl :refer :all]
[com.stuartsierra.component :as component]
[raven.client :refer [http-requests-payload-stub]]
[spootnik.reporter.sentry :refer [http-requests-payload-stub]]
[clojure.set :as cljset])
(:import io.prometheus.client.CollectorRegistry
io.netty.handler.ssl.SslContextBuilder
Expand Down

0 comments on commit c3fa4f4

Please sign in to comment.