-
-
Save frankitox/f10dd85c4d2d5baea8dbfb0519a284a4 to your computer and use it in GitHub Desktop.
Babashka script to extract a raw stacktrace from a Sentry event
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bb | |
(ns sentry-stacktrace | |
(:require | |
[babashka.curl :as curl] | |
[cheshire.core :as json] | |
[clojure.pprint :as pp] | |
[clojure.tools.cli :as cli] | |
[clojure.set :as set] | |
[clojure.string :as str])) | |
;; To run this script: | |
;; 1. Copy the file to your file system | |
;; 2. chmod u+x sentry_stacktrace.clj | |
;; 3. ./sentry_stacktrace --properties sentry.properties --event 5da81b523abd44ff9cdd68b5e884a7bc | |
(def options | |
[["-h" "--help"] | |
["-p" "--properties PROPS" "Path to sentry.properties file."] | |
["-o" "--org ORG" "The organization slug."] | |
["-p" "--project PROJECT" "The project slug."] | |
["-e" "--event EVENT" "The event id to find the stacktrace. REQUIRED."] | |
["-d" "--debug" "Pretty print the stacktrace data structure."] | |
[nil "--url URL" "Fully qualified URL to the Sentry server." | |
:default "https://sentry.io/"] | |
[nil "--auth-token AUTH_TOKEN" "Use the given Sentry auth token."]]) | |
;; https://docs.sentry.io/api/events/retrieve-an-event-for-a-project/ | |
(defn get-event [{:keys [org project auth-token event]}] | |
(-> (curl/get (str "https://sentry.io/api/0/projects/" org "/" project "/events/" event "/") | |
{:headers {"Authorization" (str "Bearer " auth-token)}}) | |
(:body) (json/parse-string true))) | |
(defn parse-stacktrace [event {:keys [debug]}] | |
(let [stacktraces (->> event (:entries) (filter (fn [t] (= "exception" (:type t))))) | |
frames (->> stacktraces first :data :values first :rawStacktrace :frames | |
reverse (filter (fn [t] (and (:colNo t) (:lineNo t))))) | |
pp-frames (when debug (-> frames pp/pprint with-out-str (str "\n\n")))] | |
(cond | |
(not= 1 (count stacktraces)) | |
{:msg (str pp-frames "The event has zero or more than one stacktraces") | |
:exit 1} | |
(empty? frames) | |
{:msg (str pp-frames "The stacktrace doesn't have specified columns and rows") | |
:exit 2} | |
:else | |
{:msg (str pp-frames | |
(->> | |
frames | |
(map #(str (:lineNo %) ":" (:colNo %))) | |
(str/join \newline))) | |
:exit 0}))) | |
(defn usage [summary] | |
{:msg (->> ["Helper script to extract Sentry raw stacktraces." | |
"" | |
"Usage: ./sentry-stacktrace.clj --properties FILE --event EVENT" | |
"" | |
"You can also send the Sentry token with env var SENTRY_AUTH_TOKEN." | |
"" | |
summary] | |
(str/join \newline)) | |
:exit 0}) | |
(defn file-props [path] | |
(let [props (->> (slurp path) | |
(str/split-lines) | |
(map #(str/split % #"=" 2)) | |
(into {}))] | |
(-> props | |
(set/rename-keys {"defaults.url" :url | |
"defaults.org" :org | |
"defaults.project" :project | |
"auth.token" :auth-token}) | |
(select-keys [:url :org :project :auth-token])))) | |
(defn process-opts [{:keys [options errors summary] :as parsed-args} env-token] | |
(let [{:keys [help debug] :as options} (merge | |
(when (:properties options) | |
(file-props (:properties options))) | |
options | |
(when (seq env-token) | |
{:auth-token env-token})) | |
required-opts #{:org :project :auth-token :event} | |
all-required-opts? (every? seq ((apply juxt required-opts) options))] | |
(cond | |
help (usage summary) | |
all-required-opts? (-> (get-event options) | |
(parse-stacktrace options)) | |
:else {:msg (str "You are missing some of the required options: " required-opts) | |
:exit 3}))) | |
(defn print-and-leave! [{:keys [msg exit]}] | |
(if (zero? exit) | |
(println msg) | |
(binding [*out* *err*] | |
(println msg))) | |
(System/exit exit)) | |
(defn -main [& args] | |
(print-and-leave! | |
(process-opts (cli/parse-opts args options) (System/getenv "SENTRY_AUTH_TOKEN")))) | |
(when (= *file* (System/getProperty "babashka.file")) | |
(apply -main *command-line-args*)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment