UNPKG

apollo-link-sentry

Version:

[Apollo Link](https://www.apollographql.com/docs/react/api/link/introduction) to enrich [Sentry](https://sentry.io) events with [GraphQL](https://graphql.org) data

84 lines (83 loc) 3.22 kB
import { ApolloError, ApolloLink, } from '@apollo/client/core'; import { Observable } from 'zen-observable-ts'; import { makeBreadcrumb } from './breadcrumb'; import { withDefaults } from './options'; import { attachBreadcrumbToSentry, setFingerprint, setTransaction, } from './sentry'; export class SentryLink extends ApolloLink { options; constructor(options = {}) { super(); this.options = withDefaults(options); } request(operation, forward) { const { options } = this; if (!(options.shouldHandleOperation?.(operation) ?? true)) { return forward(operation); } if (options.setTransaction) { setTransaction(operation); } if (options.setFingerprint) { setFingerprint(operation); } const { attachBreadcrumbs } = options; if (!attachBreadcrumbs) { return forward(operation); } const breadcrumb = makeBreadcrumb(operation, options); return new Observable((originalObserver) => { const subscription = forward(operation).subscribe({ next: (result) => { breadcrumb.level = severityForResult(result); if (attachBreadcrumbs.includeFetchResult) { breadcrumb.data.fetchResult = result; } if (attachBreadcrumbs.includeError && result.errors && result.errors.length > 0) { breadcrumb.data.error = new ApolloError({ graphQLErrors: result.errors, }); } originalObserver.next(result); }, complete: () => { attachBreadcrumbToSentry(operation, breadcrumb, options); originalObserver.complete(); }, error: (error) => { breadcrumb.level = 'error'; let scrubbedError; if (isServerError(error)) { const { result, response, ...rest } = error; scrubbedError = rest; if (attachBreadcrumbs.includeFetchResult) { breadcrumb.data.fetchResult = result; } } else { scrubbedError = error; } if (attachBreadcrumbs.includeError) { breadcrumb.data.error = scrubbedError; } attachBreadcrumbToSentry(operation, breadcrumb, options); originalObserver.error(error); }, }); return () => { subscription.unsubscribe(); }; }); } } function isServerError(error) { return (typeof error === 'object' && error !== null && 'response' in error && 'result' in error && 'statusCode' in error); } function severityForResult(result) { return result.errors && result.errors.length > 0 ? 'error' : 'info'; }