From 5cc1462ea80dac3666f36ad39bd5bfef5be01327 Mon Sep 17 00:00:00 2001 From: Yordis Prieto Lazo Date: Wed, 20 Oct 2021 08:58:52 -0400 Subject: [PATCH] feat: allow to pass custom sdk for fullstory fixes #30 --- src/SentryFullStory.ts | 69 ++++++++++++++++-------------------------- src/types.ts | 4 +++ src/util.ts | 33 ++++++++++++++++++++ 3 files changed, 63 insertions(+), 43 deletions(-) create mode 100644 src/types.ts diff --git a/src/SentryFullStory.ts b/src/SentryFullStory.ts index 0eb906d..012e790 100644 --- a/src/SentryFullStory.ts +++ b/src/SentryFullStory.ts @@ -2,7 +2,8 @@ import * as Sentry from '@sentry/browser'; import { Event, EventHint } from '@sentry/types'; import * as FullStory from '@fullstory/browser'; -import * as util from './util'; +import { doesFullStoryExist, getOriginalExceptionProperties, getSentryUrl } from './util'; +import { FullStoryClient } from './types'; /** * This integration creates a link from the Sentry Error to the FullStory replay. @@ -12,6 +13,7 @@ import * as util from './util'; type Options = { baseSentryUrl?: string; + client?: FullStoryClient; }; class SentryFullStory { @@ -19,72 +21,53 @@ class SentryFullStory { public static id: string = 'SentryFullStory'; sentryOrg: string; baseSentryUrl: string; + client: FullStoryClient; constructor(sentryOrg: string, options: Options = {}) { this.sentryOrg = sentryOrg; + this.client = options.client || FullStory; this.baseSentryUrl = options.baseSentryUrl || 'https://sentry.io'; } - private static doesFullStoryExist() { - return !!window[window['_fs_namespace']]; - } - setupOnce() { Sentry.addGlobalEventProcessor((event: Event, hint?: EventHint) => { + const self = Sentry.getCurrentHub().getIntegration(SentryFullStory); + // Run the integration ONLY when it was installed on the current Hub AND isn't a transaction + if (self && event.type !== 'transaction' && doesFullStoryExist()) { - const getSentryUrl = (): string => { - // Returns the sentry URL of the error - // If we cannot get the URL, return a string saying we cannot - try { - // No docs on this but the SDK team assures me it works unless you bind another Sentry client - const { dsn } = Sentry.getCurrentHub().getClient()?.getOptions() || {}; - if (!dsn) { - console.error('No DSN'); - return 'Could not retrieve url'; - } - if (!hint) { - console.error('No event hint'); - return 'Could not retrieve url'; + const getFullStoryUrl = () => { + // getCurrentSessionURL isn't available until after the FullStory script is fully bootstrapped. + // If an error occurs before getCurrentSessionURL is ready, make a note in Sentry and move on. + // More on getCurrentSessionURL here: https://help.fullstory.com/develop-js/getcurrentsessionurl + try { + return this.client.getCurrentSessionURL(true) || 'Current session URL API not ready' + } catch (e) { + const reason = e instanceof Error ? e.message : String(e) + return `Unable to get url: ${reason}` } - const projectId = util.getProjectIdFromSentryDsn(dsn); - return `${this.baseSentryUrl}/organizations/${this.sentryOrg}/issues/?project=${projectId}&query=${hint.event_id}`; - } catch (err) { - console.error('Error retrieving project ID from DSN', err); - //TODO: Could put link to a help here - return 'Could not retrieve url'; } - }; - const getFullStoryUrl = (): string => { - // getCurrentSessionURL isn't available until after the FullStory script is fully bootstrapped. - // If an error occurs before getCurrentSessionURL is ready, make a note in Sentry and move on. - // More on getCurrentSessionURL here: https://help.fullstory.com/develop-js/getcurrentsessionurl - try { - return FullStory.getCurrentSessionURL(true) || 'Current session URL API not ready' - } catch (e) { - const reason = e instanceof Error ? e.message : String(e) - return `Unable to get url: ${reason}` - } - } - - const self = Sentry.getCurrentHub().getIntegration(SentryFullStory); - // Run the integration ONLY when it was installed on the current Hub AND isn't a transaction - if (self && event.type !== 'transaction' && SentryFullStory.doesFullStoryExist()) { event.contexts = { ...event.contexts, fullStory: { fullStoryUrl: getFullStoryUrl() }, }; + try { - FullStory.event('Sentry Error', { - sentryUrl: getSentryUrl(), - ...util.getOriginalExceptionProperties(hint), + this.client.event('Sentry Error', { + sentryUrl: getSentryUrl({ + baseSentryUrl: this.baseSentryUrl, + sentryOrg: this.sentryOrg, + hint, + }), + ...getOriginalExceptionProperties(hint), }); } catch (e) { console.debug('Unable to report sentry error details to FullStory') } } + return event; }); } diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..b149408 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,4 @@ +export interface FullStoryClient { + event(eventName: string, eventProperties: { [key: string]: any }): void; + getCurrentSessionURL(now?: boolean): string | null; +} diff --git a/src/util.ts b/src/util.ts index bc26591..c5c4d66 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,4 +1,12 @@ import { EventHint } from '@sentry/types'; +import * as Sentry from '@sentry/browser'; + +/** + * Returns true if Fullstory is installed correctly. + */ +export function doesFullStoryExist() { + return !!window[window['_fs_namespace']]; +} /** * Get the project ID from a Sentry DSN @@ -25,3 +33,28 @@ export const getOriginalExceptionProperties = (hint?: EventHint) => { return {}; }; + +/** + * Returns the sentry URL of the error. If we cannot get the URL, return a + * string saying we cannot. + */ +export function getSentryUrl(args: { hint?: EventHint, sentryOrg: string, baseSentryUrl: string }) { + try { + // No docs on this but the SDK team assures me it works unless you bind another Sentry client + const { dsn } = Sentry.getCurrentHub().getClient()?.getOptions() || {}; + if (!dsn) { + console.error('No sn'); + return 'Could not retrieve url'; + } + if (!args.hint) { + console.error('No event hint'); + return 'Could not retrieve url'; + } + const projectId = getProjectIdFromSentryDsn(dsn); + return `${args.baseSentryUrl}/organizations/${args.sentryOrg}/issues/?project=${projectId}&query=${args.hint.event_id}`; + } catch (err) { + console.error('Error retrieving project ID from DSN', err); + //TODO: Could put link to a help here + return 'Could not retrieve url'; + } +}