Skip to content

Commit cd7d887

Browse files
authored
fix: Make APM optional in gatsby package (getsentry#2752)
* fix: Make APM optional in gatsby package * ref: Use idleTimout if no activities occur in idle transaction
1 parent 913b0ca commit cd7d887

File tree

5 files changed

+88
-5
lines changed

5 files changed

+88
-5
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott
66
- [react] feat: Export `createReduxEnhancer` to log redux actions as breadcrumbs, and attach state as an extra. (#2717)
77
- [tracing] feat: `Add @sentry/tracing` (#2719)
8+
- [gatsby] fix: Make APM optional in gatsby package (#2752)
9+
- [tracing] ref: Use idleTimout if no activities occur in idle transaction (#2752)
810

911
## 5.19.2
1012

packages/gatsby/README.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Register the package as a plugin in `gastby-config.js`:
2424
}
2525
```
2626

27-
Options will be passed directly to `Sentry.init`. The `environment` value defaults to `NODE_ENV` (or `development` if not set).
27+
Options will be passed directly to `Sentry.init`. See all available options in [our docs](https://docs.sentry.io/error-reporting/configuration/?platform=javascript). The `environment` value defaults to `NODE_ENV` (or `development` if not set).
2828

2929
## GitHub Actions
3030

@@ -38,6 +38,26 @@ The `release` value is inferred from `COMMIT_REF`.
3838

3939
To automatically capture the `release` value on Vercel you will need to register appropriate [system environment variable](https://vercel.com/docs/v2/build-step#system-environment-variables) (e.g. `VERCEL_GITHUB_COMMIT_SHA`) in your project.
4040

41+
## Sentry Performance
42+
43+
To enable Tracing support, supply the `tracesSampleRate` to the options and make sure you have installed the `@sentry/tracing` package.
44+
45+
```javascript
46+
{
47+
// ...
48+
plugins: [
49+
{
50+
resolve: "@sentry/gatsby",
51+
options: {
52+
dsn: process.env.SENTRY_DSN, // this is the default
53+
tracesSampleRate: 1, // this is just to test, you should lower this in production
54+
}
55+
},
56+
// ...
57+
]
58+
}
59+
```
60+
4161
## Links
4262

4363
- [Official SDK Docs](https://docs.sentry.io/quickstart/)

packages/gatsby/gatsby-browser.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
11
exports.onClientEntry = function(_, pluginParams) {
2-
require.ensure(['@sentry/react', '@sentry/apm'], function(require) {
2+
require.ensure(['@sentry/react'], function(require) {
33
const Sentry = require('@sentry/react');
4-
const TracingIntegration = require('@sentry/apm').Integrations.Tracing;
4+
5+
let TracingIntegration = undefined;
6+
let BrowserTracingIntegration = undefined;
7+
try {
8+
BrowserTracingIntegration = require('@sentry/tracing').Integrations.BrowserTracing;
9+
} catch (_) {}
10+
try {
11+
/** @deprecated Remove when @sentry/apm is no longer used */
12+
TracingIntegration = require('@sentry/apm').Integrations.Tracing;
13+
} catch (_) {}
14+
515
const tracesSampleRate = pluginParams.tracesSampleRate !== undefined ? pluginParams.tracesSampleRate : 0;
616
const integrations = [...(pluginParams.integrations || [])];
17+
718
if (tracesSampleRate) {
8-
integrations.push(new TracingIntegration());
19+
if (BrowserTracingIntegration) {
20+
integrations.push(new BrowserTracingIntegration());
21+
} else if (TracingIntegration) {
22+
integrations.push(new TracingIntegration());
23+
}
924
}
25+
1026
Sentry.init({
1127
environment: process.env.NODE_ENV || 'development',
1228
release: __SENTRY_RELEASE__,
@@ -15,6 +31,7 @@ exports.onClientEntry = function(_, pluginParams) {
1531
tracesSampleRate,
1632
integrations,
1733
});
34+
1835
Sentry.addGlobalEventProcessor(event => {
1936
event.sdk = {
2037
...event.sdk,

packages/tracing/src/idletransaction.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ export class IdleTransaction extends Transaction {
7070

7171
private readonly _beforeFinishCallbacks: BeforeFinishCallback[] = [];
7272

73+
// If a transaction is created and no activities are added, we want to make sure that
74+
// it times out properly. This is cleared and not used when activities are added.
75+
private _initTimeout: any;
76+
7377
public constructor(
7478
transactionContext: TransactionContext,
7579
private readonly _idleHub?: Hub,
@@ -188,6 +192,11 @@ export class IdleTransaction extends Transaction {
188192
* @param spanId The span id that represents the activity
189193
*/
190194
private _pushActivity(spanId: string): void {
195+
if (this._initTimeout) {
196+
// tslint:disable-next-line: no-unsafe-any
197+
clearTimeout(this._initTimeout);
198+
this._initTimeout = undefined;
199+
}
191200
logger.log(`[Tracing] pushActivity: ${spanId}`);
192201
this.activities[spanId] = true;
193202
logger.log('[Tracing] new activities count', Object.keys(this.activities).length);
@@ -235,12 +244,25 @@ export class IdleTransaction extends Transaction {
235244
*/
236245
public initSpanRecorder(maxlen?: number): void {
237246
if (!this.spanRecorder) {
247+
this._initTimeout = setTimeout(() => {
248+
if (!this._finished) {
249+
this.finish();
250+
}
251+
}, this._idleTimeout);
252+
238253
const pushActivity = (id: string) => {
254+
if (this._finished) {
255+
return;
256+
}
239257
this._pushActivity(id);
240258
};
241259
const popActivity = (id: string) => {
260+
if (this._finished) {
261+
return;
262+
}
242263
this._popActivity(id);
243264
};
265+
244266
this.spanRecorder = new IdleTransactionSpanRecorder(pushActivity, popActivity, this.spanId, maxlen);
245267

246268
// Start heartbeat so that transactions do not run forever.

packages/tracing/test/idletransaction.test.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { BrowserClient } from '@sentry/browser';
22
import { Hub } from '@sentry/hub';
33

4-
import { IdleTransaction, IdleTransactionSpanRecorder } from '../src/idletransaction';
4+
import { IdleTransaction, IdleTransactionSpanRecorder, DEFAULT_IDLE_TIMEOUT } from '../src/idletransaction';
55
import { Span } from '../src/span';
66
import { SpanStatus } from '../src/spanstatus';
77

@@ -145,6 +145,25 @@ describe('IdleTransaction', () => {
145145
}
146146
});
147147

148+
describe('_initTimeout', () => {
149+
it('finishes if no activities are added to the transaction', () => {
150+
const transaction = new IdleTransaction({ name: 'foo', startTimestamp: 1234 }, hub, 1000);
151+
transaction.initSpanRecorder(10);
152+
153+
jest.runTimersToTime(DEFAULT_IDLE_TIMEOUT);
154+
expect(transaction.endTimestamp).toBeDefined();
155+
});
156+
157+
it('does not finish if a activity is started', () => {
158+
const transaction = new IdleTransaction({ name: 'foo', startTimestamp: 1234 }, hub, 1000);
159+
transaction.initSpanRecorder(10);
160+
transaction.startChild({});
161+
162+
jest.runTimersToTime(DEFAULT_IDLE_TIMEOUT);
163+
expect(transaction.endTimestamp).toBeUndefined();
164+
});
165+
});
166+
148167
describe('heartbeat', () => {
149168
it('does not start heartbeat if there is no span recorder', () => {
150169
const transaction = new IdleTransaction({ name: 'foo' }, hub, 1000);
@@ -164,12 +183,14 @@ describe('IdleTransaction', () => {
164183
jest.runOnlyPendingTimers();
165184
expect(mockFinish).toHaveBeenCalledTimes(0);
166185
});
186+
167187
it('finishes a transaction after 3 beats', () => {
168188
const transaction = new IdleTransaction({ name: 'foo' }, hub, 1000);
169189
const mockFinish = jest.spyOn(transaction, 'finish');
170190
transaction.initSpanRecorder(10);
171191

172192
expect(mockFinish).toHaveBeenCalledTimes(0);
193+
transaction.startChild({});
173194

174195
// Beat 1
175196
jest.runOnlyPendingTimers();
@@ -190,6 +211,7 @@ describe('IdleTransaction', () => {
190211
transaction.initSpanRecorder(10);
191212

192213
expect(mockFinish).toHaveBeenCalledTimes(0);
214+
transaction.startChild({});
193215

194216
// Beat 1
195217
jest.runOnlyPendingTimers();

0 commit comments

Comments
 (0)