refactor: move sentry to platform (#3451)
This commit is contained in:
@@ -42,8 +42,6 @@
|
||||
"@hoppscotch/ui": "workspace:^",
|
||||
"@hoppscotch/vue-toasted": "^0.1.0",
|
||||
"@lezer/highlight": "^1.1.6",
|
||||
"@sentry/tracing": "^7.64.0",
|
||||
"@sentry/vue": "^7.64.0",
|
||||
"@urql/core": "^4.1.1",
|
||||
"@urql/devtools": "^2.0.3",
|
||||
"@urql/exchange-auth": "^2.1.6",
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
import { HoppModule } from "."
|
||||
import * as Sentry from "@sentry/vue"
|
||||
import { BrowserTracing } from "@sentry/tracing"
|
||||
import { Route } from "@sentry/vue/types/router"
|
||||
import { RouteLocationNormalized, Router } from "vue-router"
|
||||
import { settingsStore } from "~/newstore/settings"
|
||||
import { App } from "vue"
|
||||
import { APP_IS_IN_DEV_MODE } from "~/helpers/dev"
|
||||
import { gqlClientError$ } from "~/helpers/backend/GQLClient"
|
||||
import { platform } from "~/platform"
|
||||
|
||||
/**
|
||||
* The tag names we allow giving to Sentry
|
||||
*/
|
||||
type SentryTag = "BACKEND_OPERATIONS"
|
||||
|
||||
interface SentryVueRouter {
|
||||
onError: (fn: (err: Error) => void) => void
|
||||
beforeEach: (fn: (to: Route, from: Route, next: () => void) => void) => void
|
||||
}
|
||||
|
||||
function normalizedRouteToSentryRoute(route: RouteLocationNormalized): Route {
|
||||
return {
|
||||
matched: route.matched,
|
||||
// route.params' type translates just to a fancy version of this, hence assertion
|
||||
params: route.params as Route["params"],
|
||||
path: route.path,
|
||||
// route.query's type translates just to a fancy version of this, hence assertion
|
||||
query: route.query as Route["query"],
|
||||
name: route.name,
|
||||
}
|
||||
}
|
||||
|
||||
function getInstrumentationVueRouter(router: Router): SentryVueRouter {
|
||||
return <SentryVueRouter>{
|
||||
onError: router.onError,
|
||||
beforeEach(func) {
|
||||
router.beforeEach((to, from, next) => {
|
||||
func(
|
||||
normalizedRouteToSentryRoute(to),
|
||||
normalizedRouteToSentryRoute(from),
|
||||
next
|
||||
)
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
let sentryActive = false
|
||||
|
||||
function initSentry(dsn: string, router: Router, app: App) {
|
||||
Sentry.init({
|
||||
app,
|
||||
dsn,
|
||||
release: import.meta.env.VITE_SENTRY_RELEASE_TAG ?? undefined,
|
||||
environment: APP_IS_IN_DEV_MODE
|
||||
? "dev"
|
||||
: import.meta.env.VITE_SENTRY_ENVIRONMENT,
|
||||
integrations: [
|
||||
new BrowserTracing({
|
||||
routingInstrumentation: Sentry.vueRouterInstrumentation(
|
||||
getInstrumentationVueRouter(router)
|
||||
),
|
||||
// TODO: We may want to limit this later on
|
||||
tracingOrigins: [new URL(import.meta.env.VITE_BACKEND_GQL_URL).origin],
|
||||
}),
|
||||
],
|
||||
tracesSampleRate: 0.8,
|
||||
})
|
||||
sentryActive = true
|
||||
}
|
||||
|
||||
function deinitSentry() {
|
||||
Sentry.close()
|
||||
sentryActive = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports a set of related errors to Sentry
|
||||
* @param errs The errors to report
|
||||
* @param tag The tag for the errord
|
||||
* @param extraTags Additional tag data to add
|
||||
* @param extras Extra information to attach
|
||||
*/
|
||||
function reportErrors(
|
||||
errs: Error[],
|
||||
tag: SentryTag,
|
||||
extraTags: Record<string, string | number | boolean> | null = null,
|
||||
extras: any = undefined
|
||||
) {
|
||||
if (sentryActive) {
|
||||
Sentry.withScope((scope) => {
|
||||
scope.setTag("tag", tag)
|
||||
if (extraTags) {
|
||||
Object.entries(extraTags).forEach(([key, value]) => {
|
||||
scope.setTag(key, value)
|
||||
})
|
||||
}
|
||||
if (extras !== null && extras === undefined) scope.setExtras(extras)
|
||||
|
||||
scope.addAttachment({
|
||||
filename: "extras-dump.json",
|
||||
data: JSON.stringify(extras),
|
||||
contentType: "application/json",
|
||||
})
|
||||
|
||||
errs.forEach((err) => Sentry.captureException(err))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports a specific error to Sentry
|
||||
* @param err The error to report
|
||||
* @param tag The tag for the error
|
||||
* @param extraTags Additional tag data to add
|
||||
* @param extras Extra information to attach
|
||||
*/
|
||||
function reportError(
|
||||
err: Error,
|
||||
tag: SentryTag,
|
||||
extraTags: Record<string, string | number | boolean> | null = null,
|
||||
extras: any = undefined
|
||||
) {
|
||||
reportErrors([err], tag, extraTags, extras)
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes to events occuring in various subsystems in the app
|
||||
* for personalized error reporting
|
||||
*/
|
||||
function subscribeToAppEventsForReporting() {
|
||||
gqlClientError$.subscribe((ev) => {
|
||||
switch (ev.type) {
|
||||
case "SUBSCRIPTION_CONN_CALLBACK_ERR_REPORT":
|
||||
reportErrors(ev.errors, "BACKEND_OPERATIONS", { from: ev.type })
|
||||
break
|
||||
|
||||
case "CLIENT_REPORTED_ERROR":
|
||||
reportError(
|
||||
ev.error,
|
||||
"BACKEND_OPERATIONS",
|
||||
{ from: ev.type },
|
||||
{ op: ev.op }
|
||||
)
|
||||
break
|
||||
|
||||
case "GQL_CLIENT_REPORTED_ERROR":
|
||||
reportError(
|
||||
new Error("Backend Query Failed"),
|
||||
"BACKEND_OPERATIONS",
|
||||
{ opType: ev.opType },
|
||||
{
|
||||
opResult: ev.opResult,
|
||||
}
|
||||
)
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to app system events for adding
|
||||
* additional data tags for the error reporting
|
||||
*/
|
||||
function subscribeForAppDataTags() {
|
||||
const currentUser$ = platform.auth.getCurrentUserStream()
|
||||
|
||||
currentUser$.subscribe((user) => {
|
||||
if (sentryActive) {
|
||||
Sentry.setTag("user_logged_in", !!user)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default <HoppModule>{
|
||||
onRouterInit(app, router) {
|
||||
if (!import.meta.env.VITE_SENTRY_DSN) {
|
||||
console.log(
|
||||
"Sentry tracing is not enabled because 'VITE_SENTRY_DSN' env is not defined"
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if (settingsStore.value.TELEMETRY_ENABLED) {
|
||||
initSentry(import.meta.env.VITE_SENTRY_DSN, router, app)
|
||||
}
|
||||
|
||||
settingsStore.subject$.subscribe(({ TELEMETRY_ENABLED }) => {
|
||||
if (!TELEMETRY_ENABLED && sentryActive) {
|
||||
deinitSentry()
|
||||
} else if (TELEMETRY_ENABLED && !sentryActive) {
|
||||
initSentry(import.meta.env.VITE_SENTRY_DSN!, router, app)
|
||||
}
|
||||
})
|
||||
|
||||
subscribeToAppEventsForReporting()
|
||||
subscribeForAppDataTags()
|
||||
},
|
||||
}
|
||||
@@ -60,6 +60,7 @@
|
||||
<div class="py-4 space-y-4">
|
||||
<div class="flex items-center">
|
||||
<HoppSmartToggle
|
||||
v-if="hasPlatformTelemetry"
|
||||
:on="TELEMETRY_ENABLED"
|
||||
@change="showConfirmModal"
|
||||
>
|
||||
@@ -134,6 +135,7 @@ import { InterceptorService } from "~/services/interceptor.service"
|
||||
import { pipe } from "fp-ts/function"
|
||||
import * as O from "fp-ts/Option"
|
||||
import * as A from "fp-ts/Array"
|
||||
import { platform } from "~/platform"
|
||||
|
||||
const t = useI18n()
|
||||
const colorMode = useColorMode()
|
||||
@@ -163,6 +165,8 @@ const TELEMETRY_ENABLED = useSetting("TELEMETRY_ENABLED")
|
||||
const EXPAND_NAVIGATION = useSetting("EXPAND_NAVIGATION")
|
||||
const SIDEBAR_ON_LEFT = useSetting("SIDEBAR_ON_LEFT")
|
||||
|
||||
const hasPlatformTelemetry = Boolean(platform.platformFeatureFlags.hasTelemetry)
|
||||
|
||||
const confirmRemove = ref(false)
|
||||
|
||||
const proxySettings = computed(() => ({
|
||||
|
||||
@@ -26,6 +26,7 @@ export type PlatformDef = {
|
||||
additionalInspectors?: InspectorsPlatformDef
|
||||
platformFeatureFlags: {
|
||||
exportAsGIST: boolean
|
||||
hasTelemetry: boolean
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,5 +38,6 @@ createHoppApp("#app", {
|
||||
],
|
||||
platformFeatureFlags: {
|
||||
exportAsGIST: false,
|
||||
hasTelemetry: false,
|
||||
},
|
||||
})
|
||||
|
||||
7977
pnpm-lock.yaml
generated
7977
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user