Skip to content
Closed
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');
2 changes: 1 addition & 1 deletion packages/react-native/Libraries/Core/setUpBatchedBridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ registerModule(
);
registerModule(
'GlobalPerformanceLogger',
() => require('../Utilities/GlobalPerformanceLogger').default,
() => require('../ReactNative/DeprecatedPerformanceLoggerStub').default,
);

if (__DEV__) {
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
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import type {
WrapperComponentProvider,
} from './AppRegistry.flow';

import createPerformanceLogger from '../Utilities/createPerformanceLogger';
import SceneTracker from '../Utilities/SceneTracker';
import DeprecatedPerformanceLoggerStub from './DeprecatedPerformanceLoggerStub';
import {coerceDisplayMode} from './DisplayMode';
import HeadlessJsTaskError from './HeadlessJsTaskError';
import invariant from 'invariant';
Expand Down Expand Up @@ -81,20 +81,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,
DeprecatedPerformanceLoggerStub,
),
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
@@ -0,0 +1,83 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/

import type {IPerformanceLogger} from './IPerformanceLogger.flow';

let didWarn: boolean = false;
function warnDeprecated(): void {
if (didWarn) {
return;
}
didWarn = true;
console.warn(
'The default `IPerformanceLogger` provided by `react-native` (the ' +
"`'GlobalPerformanceLogger'` callable native module and the " +
'`scopedPerformanceLogger` argument passed to the hook registered with ' +
'`AppRegistry.setComponentProviderInstrumentationHook`) is deprecated and ' +
'will be removed in a future release. The instance supplied today is a ' +
'no-op stub. Embedders that need a per-app performance logger should ' +
'attach their own implementation.',
);
}

/**
* @deprecated The `react-native` package no longer ships a real
* `IPerformanceLogger`. This stub is exposed to keep existing extension points
* (the `'GlobalPerformanceLogger'` callable native module and the second
* argument of `AppRegistry.setComponentProviderInstrumentationHook`'s hook)
* source-compatible for embedders. Every method is a no-op that emits a
* one-time deprecation warning on first use.
*/
const DeprecatedPerformanceLoggerStub: IPerformanceLogger = {
addTimespan: () => warnDeprecated(),
append: () => warnDeprecated(),
clear: () => warnDeprecated(),
clearCompleted: () => warnDeprecated(),
close: () => warnDeprecated(),
currentTimestamp: () => {
warnDeprecated();
return 0;
},
getExtras: () => {
warnDeprecated();
return {};
},
getPoints: () => {
warnDeprecated();
return {};
},
getPointExtras: () => {
warnDeprecated();
return {};
},
getTimespans: () => {
warnDeprecated();
return {};
},
hasTimespan: () => {
warnDeprecated();
return false;
},
isClosed: () => {
warnDeprecated();
return false;
},
logEverything: () => warnDeprecated(),
markPoint: () => warnDeprecated(),
removeExtra: () => {
warnDeprecated();
return undefined;
},
setExtra: () => warnDeprecated(),
startTimespan: () => warnDeprecated(),
stopTimespan: () => warnDeprecated(),
};

export default DeprecatedPerformanceLoggerStub;
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