Skip to content

Commit e57aeb7

Browse files
authored
feat[apm]: Add discardBackgroundSpans option (#2471)
* feat: Add discardBackgroundSpans option * ref: CodeReview + Discard all activities
1 parent 708bac4 commit e57aeb7

File tree

2 files changed

+40
-12
lines changed

2 files changed

+40
-12
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott
66

7+
- [apm] feat: Add `discardBackgroundSpans` to discard background spans by default
8+
79
## 5.13.1
810

911
- [node] fix: Restore engines back to `>= 6`

packages/apm/src/integrations/tracing.ts

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,16 @@ interface TracingOptions {
7474
* Default: 600
7575
*/
7676
maxTransactionDuration: number;
77+
78+
/**
79+
* Flag to discard all spans that occur in background. This includes transactions. Browser background tab timing is
80+
* not suited towards doing precise measurements of operations. That's why this option discards any active transaction
81+
* and also doesn't add any spans that happen in the background. Background spans/transaction can mess up your
82+
* statistics in non deterministic ways that's why we by default recommend leaving this opition enabled.
83+
*
84+
* Default: true
85+
*/
86+
discardBackgroundSpans: boolean;
7787
}
7888

7989
/** JSDoc */
@@ -114,9 +124,9 @@ export class Tracing implements Integration {
114124

115125
private static _activeTransaction?: Span;
116126

117-
private static _currentIndex: number = 0;
127+
private static _currentIndex: number = 1;
118128

119-
public static readonly _activities: { [key: number]: Activity } = {};
129+
public static _activities: { [key: number]: Activity } = {};
120130

121131
private static _debounce: number = 0;
122132

@@ -127,8 +137,9 @@ export class Tracing implements Integration {
127137
*
128138
* @param _options TracingOptions
129139
*/
130-
public constructor(private readonly _options?: Partial<TracingOptions>) {
140+
public constructor(_options?: Partial<TracingOptions>) {
131141
const defaults = {
142+
discardBackgroundSpans: true,
132143
idleTimeout: 500,
133144
maxTransactionDuration: 600,
134145
shouldCreateSpanForRequest(url: string): boolean {
@@ -148,7 +159,7 @@ export class Tracing implements Integration {
148159
if (!_options || !Array.isArray(_options.tracingOrigins) || _options.tracingOrigins.length === 0) {
149160
this._emitOptionsWarning = true;
150161
}
151-
Tracing.options = this._options = {
162+
Tracing.options = {
152163
...defaults,
153164
..._options,
154165
};
@@ -171,23 +182,21 @@ export class Tracing implements Integration {
171182
return;
172183
}
173184

174-
// tslint:disable-next-line: no-non-null-assertion
175-
if (this._options!.traceXHR !== false) {
185+
if (Tracing.options.traceXHR) {
176186
addInstrumentationHandler({
177187
callback: xhrCallback,
178188
type: 'xhr',
179189
});
180190
}
181-
// tslint:disable-next-line: no-non-null-assertion
182-
if (this._options!.traceFetch !== false && supportsNativeFetch()) {
191+
192+
if (Tracing.options.traceFetch && supportsNativeFetch()) {
183193
addInstrumentationHandler({
184194
callback: fetchCallback,
185195
type: 'fetch',
186196
});
187197
}
188198

189-
// tslint:disable-next-line: no-non-null-assertion
190-
if (this._options!.startTransactionOnLocationChange) {
199+
if (Tracing.options.startTransactionOnLocationChange) {
191200
addInstrumentationHandler({
192201
callback: historyCallback,
193202
type: 'history',
@@ -202,6 +211,16 @@ export class Tracing implements Integration {
202211
});
203212
}
204213

214+
if (Tracing.options.discardBackgroundSpans && global.document) {
215+
document.addEventListener('visibilitychange', () => {
216+
if (document.hidden && Tracing._activeTransaction) {
217+
logger.log('[Tracing] Discarded active transaction incl. activities since tab moved to the background');
218+
Tracing._activeTransaction = undefined;
219+
Tracing._activities = {};
220+
}
221+
});
222+
}
223+
205224
// This EventProcessor makes sure that the transaction is not longer than maxTransactionDuration
206225
addGlobalEventProcessor((event: Event) => {
207226
const self = getCurrentHub().getIntegration(Tracing);
@@ -351,6 +370,10 @@ export class Tracing implements Integration {
351370
// Tracing is not enabled
352371
return 0;
353372
}
373+
if (!Tracing._activeTransaction) {
374+
logger.log(`[Tracing] Not pushing activity ${name} since there is no active transaction`);
375+
return 0;
376+
}
354377

355378
// We want to clear the timeout also here since we push a new activity
356379
clearTimeout(Tracing._debounce);
@@ -389,7 +412,10 @@ export class Tracing implements Integration {
389412
* Removes activity and finishes the span in case there is one
390413
*/
391414
public static popActivity(id: number, spanData?: { [key: string]: any }): void {
392-
if (!Tracing._isEnabled()) {
415+
// The !id is on purpose to also fail with 0
416+
// Since 0 is returned by push activity in case tracing is not enabled
417+
// or there is no active transaction
418+
if (!Tracing._isEnabled() || !id) {
393419
// Tracing is not enabled
394420
return;
395421
}
@@ -422,7 +448,7 @@ export class Tracing implements Integration {
422448

423449
logger.log('[Tracing] activies count', count);
424450

425-
if (count === 0) {
451+
if (count === 0 && Tracing._activeTransaction) {
426452
const timeout = Tracing.options && Tracing.options.idleTimeout;
427453
logger.log(`[Tracing] Flushing Transaction in ${timeout}ms`);
428454
Tracing._debounce = (setTimeout(() => {

0 commit comments

Comments
 (0)