Skip to content

feat(rum): Capture browser navigator information #2966

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 13 commits into from
Oct 19, 2020
50 changes: 50 additions & 0 deletions packages/tracing/src/browser/metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { getFID } from './web-vitals/getFID';
import { getLCP } from './web-vitals/getLCP';
import { getTTFB } from './web-vitals/getTTFB';
import { getFirstHidden } from './web-vitals/lib/getFirstHidden';
import { NavigatorDeviceMemory, NavigatorNetworkInformation } from './web-vitals/types';

const global = getGlobalObject<Window>();

Expand Down Expand Up @@ -129,6 +130,8 @@ export class MetricsInstrumentation {

this._performanceCursor = Math.max(performance.getEntries().length - 1, 0);

this._trackNavigator(transaction);

// Measurements are only available for pageload transactions
if (transaction.op === 'pageload') {
transaction.setMeasurements(this._measurements);
Expand All @@ -149,6 +152,46 @@ export class MetricsInstrumentation {
});
}

/**
* Capture the information of the user agent.
*/
private _trackNavigator(transaction: Transaction): void {
const navigator = global.navigator as null | (Navigator & NavigatorNetworkInformation & NavigatorDeviceMemory);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you'd use if (!('navigator' in global)) would it still require adding information/device types? If so, we can leave it as is.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. TypeScript does not provide the built-in interfaces for NavigatorNetworkInformation and NavigatorDeviceMemory.


if (!navigator) {
return;
}

// track network connectivity

const connection = navigator.connection;
if (connection) {
if (connection.effectiveType) {
transaction.setTag('effectiveConnectionType', connection.effectiveType);
}

if (connection.type) {
transaction.setTag('connectionType', connection.type);
}

if (isMeasurementValue(connection.rtt)) {
this._measurements['connection.rtt'] = { value: connection.rtt as number };
}

if (isMeasurementValue(connection.downlink)) {
this._measurements['connection.downlink'] = { value: connection.downlink as number };
}
}

if (isMeasurementValue(navigator.deviceMemory)) {
transaction.setTag('deviceMemory', String(navigator.deviceMemory));
}

if (isMeasurementValue(navigator.hardwareConcurrency)) {
transaction.setTag('hardwareConcurrency', String(navigator.hardwareConcurrency));
}
}

/** Starts tracking the Largest Contentful Paint on the current page. */
private _trackLCP(): void {
getLCP(metric => {
Expand Down Expand Up @@ -332,3 +375,10 @@ export function _startChild(transaction: Transaction, { startTimestamp, ...ctx }
...ctx,
});
}

/**
* Checks if a given value is a valid measurement value.
*/
function isMeasurementValue(value: any): boolean {
return typeof value === 'number' && isFinite(value);
}
39 changes: 39 additions & 0 deletions packages/tracing/src/browser/web-vitals/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,42 @@ export interface Metric {
export interface ReportHandler {
(metric: Metric): void;
}

// http://wicg.github.io/netinfo/#navigatornetworkinformation-interface
export interface NavigatorNetworkInformation {
readonly connection?: NetworkInformation;
}

// http://wicg.github.io/netinfo/#connection-types
type ConnectionType = 'bluetooth' | 'cellular' | 'ethernet' | 'mixed' | 'none' | 'other' | 'unknown' | 'wifi' | 'wimax';

// http://wicg.github.io/netinfo/#effectiveconnectiontype-enum
type EffectiveConnectionType = '2g' | '3g' | '4g' | 'slow-2g';

// http://wicg.github.io/netinfo/#dom-megabit
type Megabit = number;
// http://wicg.github.io/netinfo/#dom-millisecond
type Millisecond = number;

// http://wicg.github.io/netinfo/#networkinformation-interface
interface NetworkInformation extends EventTarget {
// http://wicg.github.io/netinfo/#type-attribute
readonly type?: ConnectionType;
// http://wicg.github.io/netinfo/#effectivetype-attribute
readonly effectiveType?: EffectiveConnectionType;
// http://wicg.github.io/netinfo/#downlinkmax-attribute
readonly downlinkMax?: Megabit;
// http://wicg.github.io/netinfo/#downlink-attribute
readonly downlink?: Megabit;
// http://wicg.github.io/netinfo/#rtt-attribute
readonly rtt?: Millisecond;
// http://wicg.github.io/netinfo/#savedata-attribute
readonly saveData?: boolean;
// http://wicg.github.io/netinfo/#handling-changes-to-the-underlying-connection
onchange?: EventListener;
}

// https://w3c.github.io/device-memory/#sec-device-memory-js-api
export interface NavigatorDeviceMemory {
readonly deviceMemory?: number;
}