Skip to content

Commit

Permalink
Migrate from raven-js to @sentry/browser
Browse files Browse the repository at this point in the history
Migrate frontend crash reporting to the modern Sentry JS client library.
  • Loading branch information
robertknight committed Jul 5, 2024
1 parent 0655caa commit 7ec925f
Show file tree
Hide file tree
Showing 12 changed files with 238 additions and 199 deletions.
6 changes: 3 additions & 3 deletions h/static/scripts/admin-site.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import 'bootstrap';

import { init as initRaven } from './base/raven';
import { init as initSentry } from './base/sentry';
import { settings } from './base/settings';
import { upgradeElements } from './base/upgrade-elements';
import { sharedControllers } from './controllers';
import { AdminUsersController } from './controllers/admin-users-controller';

const appSettings = settings(document);
if (appSettings.raven) {
initRaven(appSettings.raven);
if (appSettings.sentry) {
initSentry(appSettings.sentry);
}

const controllers = Object.assign(
Expand Down
71 changes: 0 additions & 71 deletions h/static/scripts/base/raven.js

This file was deleted.

52 changes: 52 additions & 0 deletions h/static/scripts/base/sentry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* This module configures Sentry crash reporting.
*
* Logging requires the Sentry DSN and Hypothesis version to be provided via the
* app's settings object.
*/

import * as Sentry from '@sentry/browser';

export type SentryConfig = {
dsn: string;
release: string;
userid?: string;
};

export function init(config: SentryConfig) {
Sentry.init({
dsn: config.dsn,
release: config.release,
});

if (config.userid) {
Sentry.setUser({ id: config.userid });
}
}

/**
* Report an error to Sentry.
*
* @param error - An error object describing what went wrong
* @param when - A string describing the context in which
* the error occurred.
* @param context - A JSON-serializable object containing additional
* information which may be useful when investigating the error.
*/
export function report(error: unknown, when: string, context?: unknown) {
if (!(error instanceof Error)) {
// If the passed object is not an Error, Sentry will serialize it using
// toString() which produces unhelpful results for objects that do not
// provide their own toString() implementations.
//
// If the error is a plain object or non-Error subclass with a message
// property, such as errors returned by chrome.extension.lastError,
// use that instead.
if (typeof error === 'object' && error && 'message' in error) {
error = error.message;
}
}

const extra = Object.assign({ when: when }, context);
Sentry.captureException(error, { extra });
}
2 changes: 1 addition & 1 deletion h/static/scripts/base/upgrade-elements.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export function upgradeElements(root, controllers) {
err.toString(),
);

// Re-raise error so that Raven can capture and report it
// Re-raise error so that Sentry can capture and report it
throw err;
}
});
Expand Down
6 changes: 3 additions & 3 deletions h/static/scripts/site.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { init as initRaven } from './base/raven';
import { init as initSentry } from './base/sentry';
import { settings } from './base/settings';
import { upgradeElements } from './base/upgrade-elements';
import { sharedControllers } from './controllers';
Expand All @@ -9,8 +9,8 @@ import { SearchBucketController } from './controllers/search-bucket-controller';
import { ShareWidgetController } from './controllers/share-widget-controller';

const appSettings = settings(document);
if (appSettings.raven) {
initRaven(appSettings.raven);
if (appSettings.sentry) {
initSentry(appSettings.sentry);
}

const controllers = Object.assign(
Expand Down
107 changes: 0 additions & 107 deletions h/static/scripts/tests/base/raven-test.js

This file was deleted.

83 changes: 83 additions & 0 deletions h/static/scripts/tests/base/sentry-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import * as sentry from '../../base/sentry';

describe('sentry', () => {
let fakeSentry;

beforeEach(() => {
fakeSentry = {
init: sinon.stub(),
captureException: sinon.stub(),
setUser: sinon.stub(),
};

sentry.$imports.$mock({
'@sentry/browser': fakeSentry,
});
});

afterEach(() => {
sentry.$imports.$restore();
});

describe('init', () => {
it('configures the Sentry client', () => {
sentry.init({
dsn: 'dsn',
release: 'release',
userid: 'acct:foobar@hypothes.is',
});
assert.calledWith(
fakeSentry.init,
sinon.match({
dsn: 'dsn',
release: 'release',
}),
);
});

it('sets the user context when a userid is specified', () => {
sentry.init({
dsn: 'dsn',
release: 'release',
userid: 'acct:foobar@hypothes.is',
});
assert.calledWith(
fakeSentry.setUser,
sinon.match({
id: 'acct:foobar@hypothes.is',
}),
);
});

it('does not set the user context when a userid is not specified', () => {
sentry.init({
dsn: 'dsn',
release: 'release',
userid: null,
});
assert.notCalled(fakeSentry.setUser);
});
});

describe('report', () => {
it('extracts the message property from Error-like objects', () => {
sentry.report({ message: 'An error' }, 'context');
assert.calledWith(fakeSentry.captureException, 'An error', {
extra: {
when: 'context',
},
});
});

it('passes extra details through', () => {
const error = new Error('an error');
sentry.report(error, 'some operation', { url: 'foobar.com' });
assert.calledWith(fakeSentry.captureException, error, {
extra: {
when: 'some operation',
url: 'foobar.com',
},
});
});
});
});
2 changes: 1 addition & 1 deletion h/subscribers.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def add_renderer_globals(event):
event["frontend_settings"] = {}

if "h.sentry_dsn_frontend" in request.registry.settings:
event["frontend_settings"]["raven"] = {
event["frontend_settings"]["sentry"] = {
"dsn": request.registry.settings["h.sentry_dsn_frontend"],
"release": __version__,
"userid": request.authenticated_userid,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@rollup/plugin-commonjs": "^26.0.1",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-terser": "^0.4.4",
"@sentry/browser": "^8.15.0",
"autoprefixer": "^10.4.19",
"bootstrap": "^4.6.2",
"classnames": "^2.5.1",
Expand All @@ -37,7 +38,6 @@
"popper.js": "^1.16.1",
"postcss": "^8.4.39",
"preact": "^10.22.1",
"raven-js": "^3.7.0",
"rollup": "^4.18.0",
"sass": "^1.77.6",
"scroll-into-view": "^1.16.2",
Expand Down
Loading

0 comments on commit 7ec925f

Please sign in to comment.