chore: add additional telemetry for teams errors

This commit is contained in:
Andrew Bastin
2022-10-01 00:58:58 +05:30
parent 99e7e73965
commit 1006617e99
3 changed files with 84 additions and 9 deletions

View File

@@ -93,6 +93,16 @@ declare module '@vue/runtime-core' {
HttpTestResultReport: typeof import('./components/http/TestResultReport.vue')['default']
HttpTests: typeof import('./components/http/Tests.vue')['default']
HttpURLEncodedParams: typeof import('./components/http/URLEncodedParams.vue')['default']
IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default']
IconLucideCheckCircle: typeof import('~icons/lucide/check-circle')['default']
IconLucideChevronRight: typeof import('~icons/lucide/chevron-right')['default']
IconLucideInbox: typeof import('~icons/lucide/inbox')['default']
IconLucideInfo: typeof import('~icons/lucide/info')['default']
IconLucideLayers: typeof import('~icons/lucide/layers')['default']
IconLucideLoader: typeof import('~icons/lucide/loader')['default']
IconLucideMinus: typeof import('~icons/lucide/minus')['default']
IconLucideSearch: typeof import('~icons/lucide/search')['default']
IconLucideUsers: typeof import('~icons/lucide/users')['default']
LensesHeadersRenderer: typeof import('./components/lenses/HeadersRenderer.vue')['default']
LensesHeadersRendererEntry: typeof import('./components/lenses/HeadersRendererEntry.vue')['default']
LensesRenderersHTMLLensRenderer: typeof import('./components/lenses/renderers/HTMLLensRenderer.vue')['default']

View File

@@ -11,6 +11,7 @@ import {
errorExchange,
CombinedError,
Operation,
OperationResult,
} from "@urql/core"
import { authExchange } from "@urql/exchange-auth"
import { devtoolsExchange } from "@urql/devtools"
@@ -34,12 +35,18 @@ const BACKEND_GQL_URL =
const BACKEND_WS_URL =
import.meta.env.VITE_BACKEND_WS_URL ?? "wss://api.hoppscotch.io/graphql"
type GQLOpType = "query" | "mutation" | "subscription"
/**
* A type that defines error events that are possible during backend operations on the GQLCLient
*/
export type GQLClientErrorEvent =
| { type: "SUBSCRIPTION_CONN_CALLBACK_ERR_REPORT"; errors: Error[] }
| { type: "CLIENT_REPORTED_ERROR"; error: CombinedError; op: Operation }
| {
type: "GQL_CLIENT_REPORTED_ERROR"
opType: GQLOpType
opResult: OperationResult
}
/**
* A stream of the errors that occur during GQLClient operations.
@@ -178,11 +185,20 @@ export const runGQLQuery = <DocType, DocVarType, DocErrorType extends string>(
E.fromNullable(res.error?.message),
E.match(
// The left case (network error was null)
(gqlErr) =>
<GQLError<DocErrorType>>{
(gqlErr) => {
if (res.error) {
gqlClientError$.next({
type: "GQL_CLIENT_REPORTED_ERROR",
opType: "query",
opResult: res,
})
}
return <GQLError<DocErrorType>>{
type: "gql_error",
error: parseGQLErrorString(gqlErr ?? "") as DocErrorType,
},
}
},
// The right case (it was a GraphQL Error)
(networkErr) =>
<GQLError<DocErrorType>>{
@@ -230,11 +246,20 @@ export const runGQLSubscription = <
E.fromNullable(res.error?.message),
E.match(
// The left case (network error was null)
(gqlErr) =>
<GQLError<DocErrorType>>{
(gqlErr) => {
if (res.error) {
gqlClientError$.next({
type: "GQL_CLIENT_REPORTED_ERROR",
opType: "subscription",
opResult: res,
})
}
return <GQLError<DocErrorType>>{
type: "gql_error",
error: parseGQLErrorString(gqlErr ?? "") as DocErrorType,
},
}
},
// The right case (it was a GraphQL Error)
(networkErr) =>
<GQLError<DocErrorType>>{
@@ -311,11 +336,20 @@ export const runMutation = <
E.fromNullable(result.error?.message),
E.match(
// The left case (network error was null)
(gqlErr) =>
<GQLError<DocErrors>>{
(gqlErr) => {
if (result.error) {
gqlClientError$.next({
type: "GQL_CLIENT_REPORTED_ERROR",
opType: "mutation",
opResult: result,
})
}
return <GQLError<DocErrors>>{
type: "gql_error",
error: parseGQLErrorString(gqlErr ?? ""),
},
}
},
// The right case (it was a network error)
(networkErr) =>
<GQLError<DocErrors>>{

View File

@@ -7,6 +7,7 @@ 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 { currentUser$ } from "~/helpers/fb/auth"
/**
* The tag names we allow giving to Sentry
@@ -97,6 +98,12 @@ function reportErrors(
}
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))
})
}
@@ -137,6 +144,29 @@ function subscribeToAppEventsForReporting() {
{ 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() {
currentUser$.subscribe((user) => {
if (sentryActive) {
Sentry.setTag("user_logged_in", !!user)
}
})
}
@@ -163,5 +193,6 @@ export default <HoppModule>{
})
subscribeToAppEventsForReporting()
subscribeForAppDataTags()
},
}