Skip to content

Commit 33991ad

Browse files
AbhiPrasadonurtemizkan
authored andcommitted
feat(tracing): Add metadata around idleTimeout (#4251)
- Add tag if user sets custom idleTimeout - Add tag if user sets reportAllChanges option - Add finish reason tag to idleTransactions (tracked in enum)
1 parent 2fad654 commit 33991ad

File tree

6 files changed

+39
-33
lines changed

6 files changed

+39
-33
lines changed

packages/tracing/src/browser/backgroundtab.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { getGlobalObject, logger } from '@sentry/utils';
22

3+
import { FINISH_REASON_TAG, IDLE_TRANSACTION_FINISH_REASONS } from '../constants';
34
import { IdleTransaction } from '../idletransaction';
45
import { SpanStatus } from '../spanstatus';
56
import { getActiveTransaction } from '../utils';
@@ -24,6 +25,7 @@ export function registerBackgroundTabDetection(): void {
2425
activeTransaction.setStatus(SpanStatus.Cancelled);
2526
}
2627
activeTransaction.setTag('visibilitychange', 'document.hidden');
28+
activeTransaction.setTag(FINISH_REASON_TAG, IDLE_TRANSACTION_FINISH_REASONS[2]);
2729
activeTransaction.finish();
2830
}
2931
});

packages/tracing/src/browser/browsertracing.ts

+16-12
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { DEFAULT_IDLE_TIMEOUT, IdleTransaction } from '../idletransaction';
77
import { SpanStatus } from '../spanstatus';
88
import { extractTraceparentData, secToMs } from '../utils';
99
import { registerBackgroundTabDetection } from './backgroundtab';
10-
import { DEFAULT_METRICS_INSTR_OPTIONS, MetricsInstrumentation, MetricsInstrumentationOptions } from './metrics';
10+
import { MetricsInstrumentation } from './metrics';
1111
import {
1212
defaultRequestInstrumentationOptions,
1313
instrumentOutgoingRequests,
@@ -67,7 +67,7 @@ export interface BrowserTracingOptions extends RequestInstrumentationOptions {
6767
*
6868
* Default: undefined
6969
*/
70-
_metricOptions?: Partial<MetricsInstrumentationOptions>;
70+
_metricOptions?: Partial<{ _reportAllChanges: boolean }>;
7171

7272
/**
7373
* beforeNavigate is called before a pageload/navigation transaction is created and allows users to modify transaction
@@ -129,18 +129,19 @@ export class BrowserTracing implements Integration {
129129

130130
private readonly _emitOptionsWarning: boolean = false;
131131

132+
/** Store configured idle timeout so that it can be added as a tag to transactions */
133+
private _configuredIdleTimeout: BrowserTracingOptions['idleTimeout'] | undefined = undefined;
134+
132135
public constructor(_options?: Partial<BrowserTracingOptions>) {
133136
let tracingOrigins = defaultRequestInstrumentationOptions.tracingOrigins;
134137
// NOTE: Logger doesn't work in constructors, as it's initialized after integrations instances
135-
if (
136-
_options &&
137-
_options.tracingOrigins &&
138-
Array.isArray(_options.tracingOrigins) &&
139-
_options.tracingOrigins.length !== 0
140-
) {
141-
tracingOrigins = _options.tracingOrigins;
142-
} else {
143-
this._emitOptionsWarning = true;
138+
if (_options) {
139+
this._configuredIdleTimeout = _options.idleTimeout;
140+
if (_options.tracingOrigins && Array.isArray(_options.tracingOrigins) && _options.tracingOrigins.length !== 0) {
141+
tracingOrigins = _options.tracingOrigins;
142+
} else {
143+
this._emitOptionsWarning = true;
144+
}
144145
}
145146

146147
this.options = {
@@ -149,7 +150,8 @@ export class BrowserTracing implements Integration {
149150
tracingOrigins,
150151
};
151152

152-
this._metrics = new MetricsInstrumentation({ ...DEFAULT_METRICS_INSTR_OPTIONS, ...this.options._metricOptions });
153+
const { _metricOptions } = this.options;
154+
this._metrics = new MetricsInstrumentation(_metricOptions && _metricOptions._reportAllChanges);
153155
}
154156

155157
/**
@@ -236,6 +238,8 @@ export class BrowserTracing implements Integration {
236238
adjustTransactionDuration(secToMs(maxTransactionDuration), transaction, endTimestamp);
237239
});
238240

241+
idleTransaction.setTag('idleTimeout', this._configuredIdleTimeout);
242+
239243
return idleTransaction as Transaction;
240244
}
241245
}

packages/tracing/src/browser/metrics.ts

+6-15
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,6 @@ import { NavigatorDeviceMemory, NavigatorNetworkInformation } from './web-vitals
1414

1515
const global = getGlobalObject<Window>();
1616

17-
/**
18-
* Exports a way to add options to our metric collection. Currently experimental.
19-
*/
20-
export interface MetricsInstrumentationOptions {
21-
_reportAllChanges: boolean;
22-
}
23-
24-
export const DEFAULT_METRICS_INSTR_OPTIONS: MetricsInstrumentationOptions = {
25-
_reportAllChanges: false,
26-
};
27-
2817
/** Class tracking metrics */
2918
export class MetricsInstrumentation {
3019
private _measurements: Measurements = {};
@@ -33,14 +22,14 @@ export class MetricsInstrumentation {
3322
private _lcpEntry: LargestContentfulPaint | undefined;
3423
private _clsEntry: LayoutShift | undefined;
3524

36-
public constructor(_options: MetricsInstrumentationOptions) {
25+
public constructor(private _reportAllChanges: boolean = false) {
3726
if (!isNodeEnv() && global?.performance && global?.document) {
3827
if (global.performance.mark) {
3928
global.performance.mark('sentry-tracing-init');
4029
}
4130

4231
this._trackCLS();
43-
this._trackLCP(_options._reportAllChanges);
32+
this._trackLCP();
4433
this._trackFID();
4534
}
4635
}
@@ -206,6 +195,8 @@ export class MetricsInstrumentation {
206195

207196
transaction.setMeasurements(this._measurements);
208197
this._tagMetricInfo(transaction);
198+
199+
transaction.setTag('sentry_reportAllChanges', this._reportAllChanges);
209200
}
210201
}
211202

@@ -296,7 +287,7 @@ export class MetricsInstrumentation {
296287
}
297288

298289
/** Starts tracking the Largest Contentful Paint on the current page. */
299-
private _trackLCP(reportAllChanges: boolean): void {
290+
private _trackLCP(): void {
300291
getLCP(metric => {
301292
const entry = metric.entries.pop();
302293

@@ -310,7 +301,7 @@ export class MetricsInstrumentation {
310301
this._measurements['lcp'] = { value: metric.value };
311302
this._measurements['mark.lcp'] = { value: timeOrigin + startTime };
312303
this._lcpEntry = entry as LargestContentfulPaint;
313-
}, reportAllChanges);
304+
}, this._reportAllChanges);
314305
}
315306

316307
/** Starts tracking the First Input Delay on the current page. */

packages/tracing/src/constants.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Store finish reasons in tuple to save on bundle size
2+
// Readonly type should enforce that this is not mutated.
3+
export const FINISH_REASON_TAG = 'finishReason';
4+
5+
export const IDLE_TRANSACTION_FINISH_REASONS = ['heartbeatFailed', 'idleTimeout', 'documentHidden'] as const;

packages/tracing/src/idletransaction.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Hub } from '@sentry/hub';
22
import { TransactionContext } from '@sentry/types';
33
import { logger, timestampWithMs } from '@sentry/utils';
44

5+
import { FINISH_REASON_TAG, IDLE_TRANSACTION_FINISH_REASONS } from './constants';
56
import { Span, SpanRecorder } from './span';
67
import { SpanStatus } from './spanstatus';
78
import { Transaction } from './transaction';
@@ -223,6 +224,7 @@ export class IdleTransaction extends Transaction {
223224

224225
setTimeout(() => {
225226
if (!this._finished) {
227+
this.setTag(FINISH_REASON_TAG, IDLE_TRANSACTION_FINISH_REASONS[1]);
226228
this.finish(end);
227229
}
228230
}, timeout);
@@ -252,7 +254,7 @@ export class IdleTransaction extends Transaction {
252254
if (this._heartbeatCounter >= 3) {
253255
logger.log(`[Tracing] Transaction finished because of no change for 3 heart beats`);
254256
this.setStatus(SpanStatus.DeadlineExceeded);
255-
this.setTag('heartbeat', 'failed');
257+
this.setTag(FINISH_REASON_TAG, IDLE_TRANSACTION_FINISH_REASONS[0]);
256258
this.finish();
257259
} else {
258260
this._pingHeartbeat();

packages/tracing/test/browser/browsertracing.test.ts

+7-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
getHeaderContext,
1212
getMetaContent,
1313
} from '../../src/browser/browsertracing';
14-
import { DEFAULT_METRICS_INSTR_OPTIONS, MetricsInstrumentation } from '../../src/browser/metrics';
14+
import { MetricsInstrumentation } from '../../src/browser/metrics';
1515
import { defaultRequestInstrumentationOptions } from '../../src/browser/request';
1616
import { instrumentRoutingWithDefaults } from '../../src/browser/router';
1717
import * as hubExtensions from '../../src/hubextensions';
@@ -246,6 +246,8 @@ describe('BrowserTracing', () => {
246246
expect(mockFinish).toHaveBeenCalledTimes(0);
247247
jest.advanceTimersByTime(DEFAULT_IDLE_TIMEOUT);
248248
expect(mockFinish).toHaveBeenCalledTimes(1);
249+
250+
expect(transaction.tags).toEqual({ finishReason: 'idleTimeout', idleTimeout: undefined });
249251
});
250252

251253
it('can be a custom value', () => {
@@ -260,6 +262,8 @@ describe('BrowserTracing', () => {
260262
expect(mockFinish).toHaveBeenCalledTimes(0);
261263
jest.advanceTimersByTime(2000);
262264
expect(mockFinish).toHaveBeenCalledTimes(1);
265+
266+
expect(transaction.tags).toEqual({ finishReason: 'idleTimeout', idleTimeout: 2000 });
263267
});
264268
});
265269

@@ -507,7 +511,7 @@ describe('BrowserTracing', () => {
507511
createBrowserTracing(true, {});
508512

509513
expect(MetricsInstrumentation).toHaveBeenCalledTimes(1);
510-
expect(MetricsInstrumentation).toHaveBeenLastCalledWith(DEFAULT_METRICS_INSTR_OPTIONS);
514+
expect(MetricsInstrumentation).toHaveBeenLastCalledWith(undefined);
511515
});
512516

513517
it('creates metrics instrumentation with custom options', () => {
@@ -518,9 +522,7 @@ describe('BrowserTracing', () => {
518522
});
519523

520524
expect(MetricsInstrumentation).toHaveBeenCalledTimes(1);
521-
expect(MetricsInstrumentation).toHaveBeenLastCalledWith({
522-
_reportAllChanges: true,
523-
});
525+
expect(MetricsInstrumentation).toHaveBeenLastCalledWith(true);
524526
});
525527
});
526528
});

0 commit comments

Comments
 (0)