Skip to content

feat: Add basic router instrumentation for @sentry/ember #2784

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Sep 8, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions packages/ember/addon/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function InitSentryForEmber(_runtimeConfig: BrowserOptions | undefined) {
if (config.ignoreEmberOnErrorWarning) {
return;
}
next(null, function () {
next(null, function() {
warn(
'Ember.onerror found. Using Ember.onerror can hide some errors (such as flushed runloop errors) from Sentry. Use Sentry.captureException to capture errors within Ember.onError or remove it to have errors caught by Sentry directly. This error can be silenced via addon configuration.',
!Ember.onerror,
Expand All @@ -35,7 +35,7 @@ export function InitSentryForEmber(_runtimeConfig: BrowserOptions | undefined) {

function createEmberEventProcessor(): void {
if (addGlobalEventProcessor) {
addGlobalEventProcessor((event) => {
addGlobalEventProcessor(event => {
event.sdk = {
...event.sdk,
name: 'sentry.javascript.ember',
Expand All @@ -54,4 +54,5 @@ function createEmberEventProcessor(): void {
}
}

export default Sentry;
export * from '@sentry/browser';
75 changes: 75 additions & 0 deletions packages/ember/addon/instance-initializers/sentry-performance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import ApplicationInstance from '@ember/application/instance';
import environmentConfig from 'ember-get-config';
import Sentry from '@sentry/ember';

export function initialize(appInstance: ApplicationInstance): void {
const config = environmentConfig['@sentry/ember'];
if (config['disablePerformance']) {
return;
}
instrumentForPerformance(appInstance);
}

function getTransitionInformation(transition: any, router: any) {
const fromRoute = transition?.from?.name;
const toRoute = transition ? transition.to.name : router.currentRouteName;
return {
fromRoute,
toRoute,
};
}

export async function instrumentForPerformance(appInstance: ApplicationInstance) {
const config = environmentConfig['@sentry/ember'];
const sentryConfig = config.sentry;
const tracing = await import('@sentry/tracing');

const router = appInstance.lookup('service:router');

sentryConfig['integrations'] = [
...(sentryConfig['integrations'] || []),
new tracing.Integrations.BrowserTracing({
routingInstrumentation: (startTransaction, startTransactionOnPageLoad) => {
let activeTransaction: any;
if (startTransactionOnPageLoad && window.location) {
const routeInfo = router.recognize(window.location.pathname);
activeTransaction = startTransaction({
name: `route:${routeInfo.name}`,
op: 'pageload',
tags: {
url: window.location.pathname,
toRoute: routeInfo.name,
'routing.instrumentation': '@sentry/ember',
},
});
}

router.on('routeWillChange', (transition: any) => {
const { fromRoute, toRoute } = getTransitionInformation(transition, router);
activeTransaction = startTransaction({
name: `route:${toRoute}`,
op: 'navigation',
tags: {
fromRoute,
toRoute,
'routing.instrumentation': '@sentry/ember',
},
});
});
router.on('routeDidChange', () => {
if (activeTransaction) {
activeTransaction.finish();
}
});
},
idleTimeout: 2000,
}),
];

const browserClient = new Sentry.BrowserClient(sentryConfig);
Sentry.getCurrentHub().bindClient(browserClient);
}

export default {
initialize,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default, initialize } from '@sentry/ember/instance-initializers/sentry-performance';
7 changes: 6 additions & 1 deletion packages/ember/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
'use strict';

module.exports = {
name: require('./package').name
name: require('./package').name,
options: {
babel: {
plugins: [ require.resolve('ember-auto-import/babel-plugin') ]
}
}
};
1 change: 1 addition & 0 deletions packages/ember/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
},
"dependencies": {
"@sentry/browser": "5.20.1",
"@sentry/tracing": "5.20.1",
"@sentry/types": "5.20.1",
"@sentry/utils": "5.20.1",
"ember-get-config": "^0.2.4",
Expand Down
4 changes: 3 additions & 1 deletion packages/ember/tests/dummy/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ class TestFetchTransport extends Transports.FetchTransport {
}
}

InitSentryForEmber({ transport: TestFetchTransport });
InitSentryForEmber({
transport: TestFetchTransport,
});

export default class App extends Application {
modulePrefix = config.modulePrefix;
Expand Down
62 changes: 1 addition & 61 deletions packages/ember/tests/dummy/app/controllers/application.js
Original file line number Diff line number Diff line change
@@ -1,63 +1,3 @@
import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import EmberError from '@ember/error';
import { scheduleOnce } from '@ember/runloop';
import RSVP from 'rsvp';

export default class ApplicationController extends Controller {
@tracked showComponents;

@action
createError() {
this.nonExistentFunction();
}

@action
createEmberError() {
throw new EmberError('Whoops, looks like you have an EmberError');
}

@action
createCaughtEmberError() {
try {
throw new EmberError('Looks like you have a caught EmberError');
} catch(e) {
console.log(e);
}
}

@action
createFetchError() {
fetch('http://doesntexist.example');
}

@action
createAfterRenderError() {
function throwAfterRender() {
throw new Error('After Render Error');
}
scheduleOnce('afterRender', throwAfterRender);
}

@action
createRSVPRejection() {
const promise = new RSVP.Promise((resolve, reject) => {
reject('Promise rejected');
});
return promise;
}

@action
createRSVPError() {
const promise = new RSVP.Promise(() => {
throw new Error('Error within RSVP Promise');
});
return promise;
}

@action
toggleShowComponents() {
this.showComponents = !this.showComponents;
}
}
export default class ApplicationController extends Controller {}
63 changes: 63 additions & 0 deletions packages/ember/tests/dummy/app/controllers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import EmberError from '@ember/error';
import { scheduleOnce } from '@ember/runloop';
import RSVP from 'rsvp';

export default class IndexController extends Controller {
@tracked showComponents;

@action
createError() {
this.nonExistentFunction();
}

@action
createEmberError() {
throw new EmberError('Whoops, looks like you have an EmberError');
}

@action
createCaughtEmberError() {
try {
throw new EmberError('Looks like you have a caught EmberError');
} catch (e) {
console.log(e);
}
}

@action
createFetchError() {
fetch('http://doesntexist.example');
}

@action
createAfterRenderError() {
function throwAfterRender() {
throw new Error('After Render Error');
}
scheduleOnce('afterRender', throwAfterRender);
}

@action
createRSVPRejection() {
const promise = new RSVP.Promise((resolve, reject) => {
reject('Promise rejected');
});
return promise;
}

@action
createRSVPError() {
const promise = new RSVP.Promise(() => {
throw new Error('Error within RSVP Promise');
});
return promise;
}

@action
toggleShowComponents() {
this.showComponents = !this.showComponents;
}
}
1 change: 1 addition & 0 deletions packages/ember/tests/dummy/app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export default class Router extends EmberRouter {
}

Router.map(function() {
this.route('tracing');
});
47 changes: 36 additions & 11 deletions packages/ember/tests/dummy/app/styles/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ body {
background-repeat: repeat;
height: 100%;
margin: 0;
font-family: Rubik,Avenir Next,Helvetica Neue,sans-serif;
font-family: Rubik, Avenir Next, Helvetica Neue, sans-serif;
font-size: 16px;
line-height: 24px;
color: var(--foreground-color);
Expand All @@ -43,7 +43,7 @@ body {
.box {
background-color: #fff;
border: 0;
box-shadow: 0 0 0 1px rgba(0,0,0,.08),0 1px 4px rgba(0,0,0,.1);
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08), 0 1px 4px rgba(0, 0, 0, 0.1);
border-radius: 4px;
display: flex;
width: 100%;
Expand All @@ -54,8 +54,8 @@ body {
padding-top: 20px;
width: 60px;
background: #564f64;
background-image: linear-gradient(-180deg,rgba(52,44,62,0),rgba(52,44,62,.5));
box-shadow: 0 2px 0 0 rgba(0,0,0,.1);
background-image: linear-gradient(-180deg, rgba(52, 44, 62, 0), rgba(52, 44, 62, 0.5));
box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.1);
border-radius: 4px 0 0 4px;
margin-top: -1px;
margin-bottom: -1px;
Expand All @@ -73,12 +73,37 @@ body {
background-image: url('/assets/images/sentry-logo.svg');
}

.nav {
display: flex;
justify-content: center;
padding: 10px;
padding-top: 20px;
padding-bottom: 0px;
}

.nav a {
padding-left: 10px;
padding-right: 10px;
font-weight: 500;
text-decoration: none;
color: var(--foreground-color);
}

.nav a.active {
border-bottom: 4px solid #6c5fc7;
}

section.content {
flex: 1;
padding-bottom: 40px;
}

h1, h2, h3, h4, h5, h6 {
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: 600;
}

Expand All @@ -101,7 +126,8 @@ div.section {
padding-top: 20px;
}

.content-container h3, .content-container h4 {
.content-container h3,
.content-container h4 {
margin-top: 0px;
}

Expand All @@ -113,7 +139,7 @@ button {
border-radius: 3px;
font-weight: 600;
padding: 8px 16px;
transition: all .1s;
transition: all 0.1s;

border: 1px solid transparent;
border-radius: 3px;
Expand All @@ -139,8 +165,8 @@ button.primary {

display: inline-block;

text-shadow: 0 -1px 0 rgba(0,0,0,.15);
box-shadow: 0 2px 0 rgba(0,0,0,.08);
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.15);
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.08);

text-transform: none;
overflow: visible;
Expand All @@ -154,7 +180,6 @@ button.primary:hover {
button.primary:focus {
background: #5b4cc0;
border-color: #3a2f87;
box-shadow: inset 0 2px 0 rgba(0,0,0,.12);
box-shadow: inset 0 2px 0 rgba(0, 0, 0, 0.12);
outline: none;
}

Loading