Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 0 additions & 13 deletions packages/react-native/Libraries/Core/InitializeCore.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,4 @@

'use strict';

const start = Date.now();

require('../../src/private/setup/setUpDefaultReactNativeEnvironment').default();

const GlobalPerformanceLogger =
require('../Utilities/GlobalPerformanceLogger').default;
// We could just call GlobalPerformanceLogger.markPoint at the top of the file,
// but then we'd be excluding the time it took to require the logger.
// Instead, we just use Date.now and backdate the timestamp.
GlobalPerformanceLogger.markPoint(
'initializeCore_start',
GlobalPerformanceLogger.currentTimestamp() - (Date.now() - start),
);
GlobalPerformanceLogger.markPoint('initializeCore_end');
4 changes: 0 additions & 4 deletions packages/react-native/Libraries/Core/setUpBatchedBridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ registerModule(
'RCTNativeAppEventEmitter',
() => require('../EventEmitter/RCTNativeAppEventEmitter').default,
);
registerModule(
'GlobalPerformanceLogger',
() => require('../Utilities/GlobalPerformanceLogger').default,
);

if (__DEV__) {
registerModule('HMRClient', () => require('../Utilities/HMRClient').default);
Expand Down
41 changes: 29 additions & 12 deletions packages/react-native/Libraries/Network/XMLHttpRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import type {
EventCallback,
EventListener,
} from '../../src/private/webapis/dom/events/EventTarget';
import type {IPerformanceLogger} from '../Utilities/createPerformanceLogger';

import Event from '../../src/private/webapis/dom/events/Event';
import {
Expand All @@ -27,8 +26,6 @@ import ProgressEvent from '../../src/private/webapis/xhr/events/ProgressEvent';
import {type EventSubscription} from '../vendor/emitter/EventEmitter';

const BlobManager = require('../Blob/BlobManager').default;
const GlobalPerformanceLogger =
require('../Utilities/GlobalPerformanceLogger').default;
const RCTNetworking = require('./RCTNetworking').default;
const base64 = require('base64-js');
const invariant = require('invariant');
Expand Down Expand Up @@ -58,6 +55,17 @@ type XHRInterceptor = interface {
loadingFailed(id: number, error: string): void,
};

/**
* Minimal contract for the optional performance logger that callers may attach
* via `setPerformanceLogger(...)`. Defined locally so this module stays
* self-contained and does not depend on any specific logger implementation.
* Any object satisfying these two methods structurally is accepted.
*/
type XHRPerformanceLogger = interface {
startTimespan(key: string): void,
stopTimespan(key: string): void,
};

// The native blob module is optional so inject it here if available.
if (BlobManager.isAvailable) {
BlobManager.addNetworkingHandler();
Expand Down Expand Up @@ -167,8 +175,7 @@ class XMLHttpRequest extends EventTarget {
_timedOut: boolean = false;
_trackingName: ?string;
_incrementalEvents: boolean = false;
_startTime: ?number = null;
_performanceLogger: IPerformanceLogger = GlobalPerformanceLogger;
_performanceLogger: ?XHRPerformanceLogger = null;

static __setInterceptor_DO_NOT_USE(interceptor: ?XHRInterceptor) {
XMLHttpRequest._interceptor = interceptor;
Expand Down Expand Up @@ -334,8 +341,10 @@ class XMLHttpRequest extends EventTarget {
responseURL: ?string,
): void {
if (requestId === this._requestId) {
this._perfKey != null &&
this._performanceLogger.stopTimespan(this._perfKey);
const performanceLogger = this._performanceLogger;
if (this._perfKey != null && performanceLogger != null) {
performanceLogger.stopTimespan(this._perfKey);
}
this.status = status;
this.setResponseHeaders(responseHeaders);
this.setReadyState(this.HEADERS_RECEIVED);
Expand Down Expand Up @@ -521,9 +530,15 @@ class XMLHttpRequest extends EventTarget {
}

/**
* Custom extension for setting a custom performance logger
* Custom extension that lets callers attach a performance logger receiving
* a `network_XMLHttpRequest_<friendlyName>` start/stop timespan around each
* dispatched request. The logger only needs to implement
* `startTimespan(key)` / `stopTimespan(key)` (see the `XHRPerformanceLogger`
* interface above). When no logger is set the timespan is not emitted.
*/
setPerformanceLogger(performanceLogger: IPerformanceLogger): XMLHttpRequest {
setPerformanceLogger(
performanceLogger: XHRPerformanceLogger,
): XMLHttpRequest {
this._performanceLogger = performanceLogger;
return this;
}
Expand Down Expand Up @@ -598,9 +613,11 @@ class XMLHttpRequest extends EventTarget {

const doSend = () => {
const friendlyName = this._trackingName ?? this._url;
this._perfKey = 'network_XMLHttpRequest_' + String(friendlyName);
this._performanceLogger.startTimespan(this._perfKey);
this._startTime = performance.now();
const performanceLogger = this._performanceLogger;
if (performanceLogger != null) {
this._perfKey = 'network_XMLHttpRequest_' + String(friendlyName);
performanceLogger.startTimespan(this._perfKey);
}
invariant(
this._method,
'XMLHttpRequest method needs to be defined (%s).',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,10 @@

'use strict';

const createPerformanceLogger =
require('../../Utilities/createPerformanceLogger').default;
const GlobalPerformanceLogger =
require('../../Utilities/GlobalPerformanceLogger').default;
const Platform = require('../../Utilities/Platform').default;
const XMLHttpRequest = require('../XMLHttpRequest').default;

jest.unmock('../../Utilities/Platform');
jest.mock('../../Utilities/GlobalPerformanceLogger');
let requestId = 1;
function setRequestId(id: number) {
if (Platform.OS === 'ios') {
Expand Down Expand Up @@ -246,30 +241,11 @@ describe('XMLHttpRequest', function () {
);
});

it('should log to GlobalPerformanceLogger if a custom performance logger is not set', () => {
xhr.open('GET', 'blabla');
xhr.send();

expect(GlobalPerformanceLogger.startTimespan).toHaveBeenCalledWith(
'network_XMLHttpRequest_blabla',
);
expect(GlobalPerformanceLogger.stopTimespan).not.toHaveBeenCalled();

setRequestId(8);
xhr.__didReceiveResponse(requestId, 200, {
'Content-Type': 'text/plain; charset=utf-8',
'Content-Length': '32',
});

expect(GlobalPerformanceLogger.stopTimespan).toHaveBeenCalledWith(
'network_XMLHttpRequest_blabla',
);
});

it('should log to a custom performance logger if set', () => {
const performanceLogger = createPerformanceLogger();
jest.spyOn(performanceLogger, 'startTimespan');
jest.spyOn(performanceLogger, 'stopTimespan');
const performanceLogger = {
startTimespan: jest.fn(),
stopTimespan: jest.fn(),
};

xhr.setPerformanceLogger(performanceLogger);

Expand All @@ -279,7 +255,6 @@ describe('XMLHttpRequest', function () {
expect(performanceLogger.startTimespan).toHaveBeenCalledWith(
'network_XMLHttpRequest_blabla',
);
expect(GlobalPerformanceLogger.startTimespan).not.toHaveBeenCalled();
expect(performanceLogger.stopTimespan).not.toHaveBeenCalled();

setRequestId(9);
Expand All @@ -291,7 +266,6 @@ describe('XMLHttpRequest', function () {
expect(performanceLogger.stopTimespan).toHaveBeenCalledWith(
'network_XMLHttpRequest_blabla',
);
expect(GlobalPerformanceLogger.stopTimespan).not.toHaveBeenCalled();
});

it('should sort and lowercase response headers', function () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
*/

import type * as React from 'react';
import type {IPerformanceLogger} from '../Utilities/IPerformanceLogger';
import type {ViewStyle} from '../StyleSheet/StyleSheetTypes';
import type {IPerformanceLogger} from './IPerformanceLogger';

type Task = (taskData: any) => Promise<void>;
type TaskProvider = () => Task;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

import type {ViewStyleProp} from '../StyleSheet/StyleSheet';
import type {RootTag} from '../Types/RootTagTypes';
import type {IPerformanceLogger} from '../Utilities/createPerformanceLogger';
import type {DisplayModeType} from './DisplayMode';
import type {IPerformanceLogger} from './IPerformanceLogger.flow';

type HeadlessTask = (taskData: any) => Promise<void>;
export type TaskProvider = () => HeadlessTask;
Expand Down
66 changes: 62 additions & 4 deletions packages/react-native/Libraries/ReactNative/AppRegistryImpl.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import type {
TaskProvider,
WrapperComponentProvider,
} from './AppRegistry.flow';
import type {IPerformanceLogger} from './IPerformanceLogger.flow';

import createPerformanceLogger from '../Utilities/createPerformanceLogger';
import SceneTracker from '../Utilities/SceneTracker';
import {coerceDisplayMode} from './DisplayMode';
import HeadlessJsTaskError from './HeadlessJsTaskError';
Expand All @@ -31,6 +31,65 @@ import invariant from 'invariant';
type TaskCanceller = () => void;
type TaskCancelProvider = () => TaskCanceller;

let didWarnDeprecatedScopedPerformanceLogger: boolean = false;
function warnDeprecatedScopedPerformanceLogger(): void {
if (didWarnDeprecatedScopedPerformanceLogger) {
return;
}
didWarnDeprecatedScopedPerformanceLogger = true;
console.warn(
'AppRegistry: the `scopedPerformanceLogger` argument passed to ' +
'`componentProviderInstrumentationHook` is deprecated and will be ' +
'removed in a future release. The instance provided today is a no-op ' +
'stub.',
);
}

const DEPRECATED_NOOP_SCOPED_PERFORMANCE_LOGGER: IPerformanceLogger = {
addTimespan: () => warnDeprecatedScopedPerformanceLogger(),
append: () => warnDeprecatedScopedPerformanceLogger(),
clear: () => warnDeprecatedScopedPerformanceLogger(),
clearCompleted: () => warnDeprecatedScopedPerformanceLogger(),
close: () => warnDeprecatedScopedPerformanceLogger(),
currentTimestamp: () => {
warnDeprecatedScopedPerformanceLogger();
return 0;
},
getExtras: () => {
warnDeprecatedScopedPerformanceLogger();
return {};
},
getPoints: () => {
warnDeprecatedScopedPerformanceLogger();
return {};
},
getPointExtras: () => {
warnDeprecatedScopedPerformanceLogger();
return {};
},
getTimespans: () => {
warnDeprecatedScopedPerformanceLogger();
return {};
},
hasTimespan: () => {
warnDeprecatedScopedPerformanceLogger();
return false;
},
isClosed: () => {
warnDeprecatedScopedPerformanceLogger();
return false;
},
logEverything: () => warnDeprecatedScopedPerformanceLogger(),
markPoint: () => warnDeprecatedScopedPerformanceLogger(),
removeExtra: () => {
warnDeprecatedScopedPerformanceLogger();
return undefined;
},
setExtra: () => warnDeprecatedScopedPerformanceLogger(),
startTimespan: () => warnDeprecatedScopedPerformanceLogger(),
stopTimespan: () => warnDeprecatedScopedPerformanceLogger(),
};

const runnables: Runnables = {};
const sections: Runnables = {};
const taskProviders: Map<string, TaskProvider> = new Map();
Expand Down Expand Up @@ -81,20 +140,19 @@ export function registerComponent(
componentProvider: ComponentProvider,
section?: boolean,
): string {
const scopedPerformanceLogger = createPerformanceLogger();
runnables[appKey] = (appParameters, displayMode) => {
const renderApplication = require('./renderApplication').default;
renderApplication(
componentProviderInstrumentationHook(
componentProvider,
scopedPerformanceLogger,
DEPRECATED_NOOP_SCOPED_PERFORMANCE_LOGGER,
),
appParameters.initialProps,
appParameters.rootTag,
wrapperComponentProvider && wrapperComponentProvider(appParameters),
rootViewStyleProvider && rootViewStyleProvider(appParameters),
true, // fabric - deprecated, always true
scopedPerformanceLogger,
undefined, // formerly scopedPerformanceLogger; reserved positional slot
appKey === 'LogBox', // is logbox
appKey,
displayMode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* @format
*/

export type ExtraValue = number | string | boolean;
export type Extras = {[key: string]: ExtraValue};
export type Timespan = {
startTime: number;
endTime?: number | undefined;
Expand All @@ -15,11 +17,12 @@ export type Timespan = {
endExtras?: Extras | undefined;
};

// Extra values should be serializable primitives
export type ExtraValue = number | string | boolean;

export type Extras = {[key: string]: ExtraValue};

/**
* @deprecated The scoped performance logger argument passed to the
* `componentProviderInstrumentationHook` is no longer used by `react-native`
* itself and will be removed in a future release. The instance supplied today
* is a no-op stub.
*/
export interface IPerformanceLogger {
addTimespan(
key: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
* @format
*/

export type ExtraValue = number | string | boolean;
export type Extras = {[key: string]: ExtraValue};
export type Timespan = {
startTime: number,
endTime?: number,
Expand All @@ -16,11 +18,12 @@ export type Timespan = {
endExtras?: Extras,
};

// Extra values should be serializable primitives
export type ExtraValue = number | string | boolean;

export type Extras = {[key: string]: ExtraValue};

/**
* @deprecated The scoped performance logger argument passed to the
* `componentProviderInstrumentationHook` is no longer used by `react-native`
* itself and will be removed in a future release. The instance supplied today
* is a no-op stub.
*/
export interface IPerformanceLogger {
addTimespan(
key: string,
Expand All @@ -34,10 +37,10 @@ export interface IPerformanceLogger {
clearCompleted(): void;
close(): void;
currentTimestamp(): number;
getExtras(): Readonly<{[key: string]: ?ExtraValue, ...}>;
getPoints(): Readonly<{[key: string]: ?number, ...}>;
getPointExtras(): Readonly<{[key: string]: ?Extras, ...}>;
getTimespans(): Readonly<{[key: string]: ?Timespan, ...}>;
getExtras(): Readonly<{[key: string]: ?ExtraValue}>;
getPoints(): Readonly<{[key: string]: ?number}>;
getPointExtras(): Readonly<{[key: string]: ?Extras}>;
getTimespans(): Readonly<{[key: string]: ?Timespan}>;
hasTimespan(key: string): boolean;
isClosed(): boolean;
logEverything(): void;
Expand Down
Loading
Loading