Skip to content

Commit

Permalink
feat: allow to pass custom sdk for fullstory (#60)
Browse files Browse the repository at this point in the history
This change will allow passing a different client. That means you can create your own client implementation that uses Segment over Fullstory directly.
  • Loading branch information
yordis authored Jan 21, 2022
1 parent 50a9056 commit a69049b
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 43 deletions.
69 changes: 26 additions & 43 deletions src/SentryFullStory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -12,79 +13,61 @@ import * as util from './util';

type Options = {
baseSentryUrl?: string;
client?: FullStoryClient;
};

class SentryFullStory {
public readonly name: string = SentryFullStory.id;
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;
});
}
Expand Down
4 changes: 4 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface FullStoryClient {
event(eventName: string, eventProperties: { [key: string]: any }): void;
getCurrentSessionURL(now?: boolean): string | null;
}
33 changes: 33 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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';
}
}

0 comments on commit a69049b

Please sign in to comment.