Skip to content

Commit 5caa104

Browse files
rubennortemeta-codesync[bot]
authored andcommitted
Hoist PerformanceLogger primitives out of react-native
Summary: Changelog: [General][Fixed] Removed second argument for hook function passed to `AppRegistry.setComponentProviderInstrumentationHook` as it's not usable by apps. ## Context The performance-logger primitives (`createPerformanceLogger`, `GlobalPerformanceLogger`, `IPerformanceLogger`, `PerformanceLoggerContext`) and the telemetry that lived inside the `react-native` package have always been Meta-internal. They were never exported from `index.js.flow` or `package.json#exports`, and the timespans/extras they emitted (`renderApplication_React_render`, `initializeCore_start`/`_end`, the `'GlobalPerformanceLogger'` callable native module, the per-app scoped `IPerformanceLogger`) only ever fed Meta's instrumentation. Keeping them inside `react-native` adds dead weight to the OSS package and forces any future change to that surface to land through OSS sync. Hoisting them out keeps the OSS package focused on what external consumers actually use, while leaving Meta's instrumentation stack fully functional. This is non-breaking for OSS consumers — nothing that was importable from `react-native` becomes unavailable. Technically, this could be considered a breaking change, because `AppRegistry.setComponentProviderInstrumentationHook` accepts a function that was receiving a performance logger as the second parameter, but because that performance logger wasn't later accessible anywhere, we should consider that it wasn't really used. A quick search on Github yielded not results for the use of the API altogether: https://github.com/search?q=AppRegistry.setComponentProviderInstrumentationHook%28&type=code ## Changes - Removed the perf-logger source files and their telemetry emission from `react-native`. - `XMLHttpRequest` keeps its `setPerformanceLogger(...)` extension and the `network_XMLHttpRequest_<friendlyName>` start/stop timespan, but the parameter is now typed against a tiny local interface (`startTimespan(key)` / `stopTimespan(key)`) defined inside the module, so the file no longer depends on the moved primitives. The logger defaults to `null` (no global fallback); when no logger is set the timespan is not emitted. The unused `_startTime` field is dropped, and the XHR test for the custom-logger path is preserved with a hand-rolled spy. - `InitializeCore.js` no longer emits `initializeCore_start` / `initializeCore_end` markPoints, and `setUpBatchedBridge.js` no longer registers the `'GlobalPerformanceLogger'` callable native module. - `renderApplication.js` no longer wraps the rendered tree in `<PerformanceLoggerContext.Provider>`, no longer emits the `renderApplication_React_render` timespan, and no longer sets the `usedReactConcurrentRoot` / `usedReactFabric` / `usedReactProfiler` extras. Its previous 7th positional `scopedPerformanceLogger` parameter is preserved as a reserved `_unused?: void` slot so direct callers that still supply an extra value continue to type-check; the value is ignored. - `AppRegistry.setComponentProviderInstrumentationHook` is preserved as part of the public API. The hook's previous second argument (the per-app `IPerformanceLogger`) is removed entirely; the hook signature is now `(component: ComponentProvider) => React.ComponentType<any>`. Embedders that need richer per-app context can attach it via their own mechanism. - `ReactNativeApi.d.ts` is regenerated by `yarn build-types`. The generated public surface is identical except that `IPerformanceLogger` is gone and `ComponentProviderInstrumentationHook` no longer takes a second argument. Differential Revision: D102166537
1 parent 53e6ce2 commit 5caa104

16 files changed

Lines changed: 50 additions & 960 deletions

packages/react-native/Libraries/Core/InitializeCore.js

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,4 @@
2626

2727
'use strict';
2828

29-
const start = Date.now();
30-
3129
require('../../src/private/setup/setUpDefaultReactNativeEnvironment').default();
32-
33-
const GlobalPerformanceLogger =
34-
require('../Utilities/GlobalPerformanceLogger').default;
35-
// We could just call GlobalPerformanceLogger.markPoint at the top of the file,
36-
// but then we'd be excluding the time it took to require the logger.
37-
// Instead, we just use Date.now and backdate the timestamp.
38-
GlobalPerformanceLogger.markPoint(
39-
'initializeCore_start',
40-
GlobalPerformanceLogger.currentTimestamp() - (Date.now() - start),
41-
);
42-
GlobalPerformanceLogger.markPoint('initializeCore_end');

packages/react-native/Libraries/Core/setUpBatchedBridge.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ registerModule(
2525
'RCTNativeAppEventEmitter',
2626
() => require('../EventEmitter/RCTNativeAppEventEmitter').default,
2727
);
28-
registerModule(
29-
'GlobalPerformanceLogger',
30-
() => require('../Utilities/GlobalPerformanceLogger').default,
31-
);
3228

3329
if (__DEV__) {
3430
registerModule('HMRClient', () => require('../Utilities/HMRClient').default);

packages/react-native/Libraries/Network/XMLHttpRequest.js

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import type {
1414
EventCallback,
1515
EventListener,
1616
} from '../../src/private/webapis/dom/events/EventTarget';
17-
import type {IPerformanceLogger} from '../Utilities/createPerformanceLogger';
1817

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

2928
const BlobManager = require('../Blob/BlobManager').default;
30-
const GlobalPerformanceLogger =
31-
require('../Utilities/GlobalPerformanceLogger').default;
3229
const RCTNetworking = require('./RCTNetworking').default;
3330
const base64 = require('base64-js');
3431
const invariant = require('invariant');
@@ -58,6 +55,17 @@ type XHRInterceptor = interface {
5855
loadingFailed(id: number, error: string): void,
5956
};
6057

58+
/**
59+
* Minimal contract for the optional performance logger that callers may attach
60+
* via `setPerformanceLogger(...)`. Defined locally so this module stays
61+
* self-contained and does not depend on any specific logger implementation.
62+
* Any object satisfying these two methods structurally is accepted.
63+
*/
64+
type XHRPerformanceLogger = interface {
65+
startTimespan(key: string): void,
66+
stopTimespan(key: string): void,
67+
};
68+
6169
// The native blob module is optional so inject it here if available.
6270
if (BlobManager.isAvailable) {
6371
BlobManager.addNetworkingHandler();
@@ -167,8 +175,7 @@ class XMLHttpRequest extends EventTarget {
167175
_timedOut: boolean = false;
168176
_trackingName: ?string;
169177
_incrementalEvents: boolean = false;
170-
_startTime: ?number = null;
171-
_performanceLogger: IPerformanceLogger = GlobalPerformanceLogger;
178+
_performanceLogger: ?XHRPerformanceLogger = null;
172179

173180
static __setInterceptor_DO_NOT_USE(interceptor: ?XHRInterceptor) {
174181
XMLHttpRequest._interceptor = interceptor;
@@ -334,8 +341,10 @@ class XMLHttpRequest extends EventTarget {
334341
responseURL: ?string,
335342
): void {
336343
if (requestId === this._requestId) {
337-
this._perfKey != null &&
338-
this._performanceLogger.stopTimespan(this._perfKey);
344+
const performanceLogger = this._performanceLogger;
345+
if (this._perfKey != null && performanceLogger != null) {
346+
performanceLogger.stopTimespan(this._perfKey);
347+
}
339348
this.status = status;
340349
this.setResponseHeaders(responseHeaders);
341350
this.setReadyState(this.HEADERS_RECEIVED);
@@ -521,9 +530,15 @@ class XMLHttpRequest extends EventTarget {
521530
}
522531

523532
/**
524-
* Custom extension for setting a custom performance logger
533+
* Custom extension that lets callers attach a performance logger receiving
534+
* a `network_XMLHttpRequest_<friendlyName>` start/stop timespan around each
535+
* dispatched request. The logger only needs to implement
536+
* `startTimespan(key)` / `stopTimespan(key)` (see the `XHRPerformanceLogger`
537+
* interface above). When no logger is set the timespan is not emitted.
525538
*/
526-
setPerformanceLogger(performanceLogger: IPerformanceLogger): XMLHttpRequest {
539+
setPerformanceLogger(
540+
performanceLogger: XHRPerformanceLogger,
541+
): XMLHttpRequest {
527542
this._performanceLogger = performanceLogger;
528543
return this;
529544
}
@@ -598,9 +613,11 @@ class XMLHttpRequest extends EventTarget {
598613

599614
const doSend = () => {
600615
const friendlyName = this._trackingName ?? this._url;
601-
this._perfKey = 'network_XMLHttpRequest_' + String(friendlyName);
602-
this._performanceLogger.startTimespan(this._perfKey);
603-
this._startTime = performance.now();
616+
const performanceLogger = this._performanceLogger;
617+
if (performanceLogger != null) {
618+
this._perfKey = 'network_XMLHttpRequest_' + String(friendlyName);
619+
performanceLogger.startTimespan(this._perfKey);
620+
}
604621
invariant(
605622
this._method,
606623
'XMLHttpRequest method needs to be defined (%s).',

packages/react-native/Libraries/Network/__tests__/XMLHttpRequest-test.js

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,10 @@
1010

1111
'use strict';
1212

13-
const createPerformanceLogger =
14-
require('../../Utilities/createPerformanceLogger').default;
15-
const GlobalPerformanceLogger =
16-
require('../../Utilities/GlobalPerformanceLogger').default;
1713
const Platform = require('../../Utilities/Platform').default;
1814
const XMLHttpRequest = require('../XMLHttpRequest').default;
1915

2016
jest.unmock('../../Utilities/Platform');
21-
jest.mock('../../Utilities/GlobalPerformanceLogger');
2217
let requestId = 1;
2318
function setRequestId(id: number) {
2419
if (Platform.OS === 'ios') {
@@ -246,30 +241,11 @@ describe('XMLHttpRequest', function () {
246241
);
247242
});
248243

249-
it('should log to GlobalPerformanceLogger if a custom performance logger is not set', () => {
250-
xhr.open('GET', 'blabla');
251-
xhr.send();
252-
253-
expect(GlobalPerformanceLogger.startTimespan).toHaveBeenCalledWith(
254-
'network_XMLHttpRequest_blabla',
255-
);
256-
expect(GlobalPerformanceLogger.stopTimespan).not.toHaveBeenCalled();
257-
258-
setRequestId(8);
259-
xhr.__didReceiveResponse(requestId, 200, {
260-
'Content-Type': 'text/plain; charset=utf-8',
261-
'Content-Length': '32',
262-
});
263-
264-
expect(GlobalPerformanceLogger.stopTimespan).toHaveBeenCalledWith(
265-
'network_XMLHttpRequest_blabla',
266-
);
267-
});
268-
269244
it('should log to a custom performance logger if set', () => {
270-
const performanceLogger = createPerformanceLogger();
271-
jest.spyOn(performanceLogger, 'startTimespan');
272-
jest.spyOn(performanceLogger, 'stopTimespan');
245+
const performanceLogger = {
246+
startTimespan: jest.fn(),
247+
stopTimespan: jest.fn(),
248+
};
273249

274250
xhr.setPerformanceLogger(performanceLogger);
275251

@@ -279,7 +255,6 @@ describe('XMLHttpRequest', function () {
279255
expect(performanceLogger.startTimespan).toHaveBeenCalledWith(
280256
'network_XMLHttpRequest_blabla',
281257
);
282-
expect(GlobalPerformanceLogger.startTimespan).not.toHaveBeenCalled();
283258
expect(performanceLogger.stopTimespan).not.toHaveBeenCalled();
284259

285260
setRequestId(9);
@@ -291,7 +266,6 @@ describe('XMLHttpRequest', function () {
291266
expect(performanceLogger.stopTimespan).toHaveBeenCalledWith(
292267
'network_XMLHttpRequest_blabla',
293268
);
294-
expect(GlobalPerformanceLogger.stopTimespan).not.toHaveBeenCalled();
295269
});
296270

297271
it('should sort and lowercase response headers', function () {

packages/react-native/Libraries/ReactNative/AppRegistry.d.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
*/
99

1010
import type * as React from 'react';
11-
import type {IPerformanceLogger} from '../Utilities/IPerformanceLogger';
1211
import type {ViewStyle} from '../StyleSheet/StyleSheetTypes';
1312

1413
type Task = (taskData: any) => Promise<void>;
@@ -28,7 +27,6 @@ export type AppConfig = {
2827

2928
export type ComponentProviderInstrumentationHook = (
3029
component: ComponentProvider,
31-
scopedPerformanceLogger: IPerformanceLogger,
3230
) => React.ComponentType<any>;
3331

3432
export type WrapperComponentProvider = (

packages/react-native/Libraries/ReactNative/AppRegistry.flow.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
import type {ViewStyleProp} from '../StyleSheet/StyleSheet';
1212
import type {RootTag} from '../Types/RootTagTypes';
13-
import type {IPerformanceLogger} from '../Utilities/createPerformanceLogger';
1413
import type {DisplayModeType} from './DisplayMode';
1514

1615
type HeadlessTask = (taskData: any) => Promise<void>;
@@ -19,7 +18,6 @@ export type TaskProvider = () => HeadlessTask;
1918
export type ComponentProvider = () => React.ComponentType<any>;
2019
export type ComponentProviderInstrumentationHook = (
2120
component_: ComponentProvider,
22-
scopedPerformanceLogger: IPerformanceLogger,
2321
) => React.ComponentType<any>;
2422
export type AppConfig = {
2523
appKey: string,

packages/react-native/Libraries/ReactNative/AppRegistryImpl.js

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import type {
2222
WrapperComponentProvider,
2323
} from './AppRegistry.flow';
2424

25-
import createPerformanceLogger from '../Utilities/createPerformanceLogger';
2625
import SceneTracker from '../Utilities/SceneTracker';
2726
import {coerceDisplayMode} from './DisplayMode';
2827
import HeadlessJsTaskError from './HeadlessJsTaskError';
@@ -81,20 +80,16 @@ export function registerComponent(
8180
componentProvider: ComponentProvider,
8281
section?: boolean,
8382
): string {
84-
const scopedPerformanceLogger = createPerformanceLogger();
8583
runnables[appKey] = (appParameters, displayMode) => {
8684
const renderApplication = require('./renderApplication').default;
8785
renderApplication(
88-
componentProviderInstrumentationHook(
89-
componentProvider,
90-
scopedPerformanceLogger,
91-
),
86+
componentProviderInstrumentationHook(componentProvider),
9287
appParameters.initialProps,
9388
appParameters.rootTag,
9489
wrapperComponentProvider && wrapperComponentProvider(appParameters),
9590
rootViewStyleProvider && rootViewStyleProvider(appParameters),
9691
true, // fabric - deprecated, always true
97-
scopedPerformanceLogger,
92+
undefined, // formerly scopedPerformanceLogger; reserved positional slot
9893
appKey === 'LogBox', // is logbox
9994
appKey,
10095
displayMode,

packages/react-native/Libraries/ReactNative/renderApplication.js

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@
99
*/
1010

1111
import type {ViewStyleProp} from '../StyleSheet/StyleSheet';
12-
import type {IPerformanceLogger} from '../Utilities/createPerformanceLogger';
1312

14-
import GlobalPerformanceLogger from '../Utilities/GlobalPerformanceLogger';
15-
import PerformanceLoggerContext from '../Utilities/PerformanceLoggerContext';
1613
import AppContainer from './AppContainer';
1714
import DisplayMode, {type DisplayModeType} from './DisplayMode';
1815
import getCachedComponentWithDebugName from './getCachedComponentWithDebugName';
@@ -39,27 +36,26 @@ export default function renderApplication<Props extends Object>(
3936
// Keep this parameter for backwards compatibility only. It is always treated as
4037
// true internally.
4138
fabric?: true | void,
42-
scopedPerformanceLogger?: IPerformanceLogger,
39+
// Reserved positional slot (formerly `scopedPerformanceLogger`). Preserved so
40+
// existing callers that supply this argument continue to type-check; the
41+
// value is ignored.
42+
_unused?: void,
4343
isLogBox?: boolean,
4444
debugName?: string,
4545
displayMode?: ?DisplayModeType,
4646
useOffscreen?: boolean,
4747
) {
4848
invariant(rootTag, 'Expect to have a valid rootTag, instead got ', rootTag);
4949

50-
const performanceLogger = scopedPerformanceLogger ?? GlobalPerformanceLogger;
51-
5250
let renderable: React.MixedElement = (
53-
<PerformanceLoggerContext.Provider value={performanceLogger}>
54-
<AppContainer
55-
rootTag={rootTag}
56-
WrapperComponent={WrapperComponent}
57-
rootViewStyle={rootViewStyle}
58-
initialProps={initialProps ?? Object.freeze({})}
59-
internal_excludeLogBox={isLogBox}>
60-
<RootComponent {...initialProps} rootTag={rootTag} />
61-
</AppContainer>
62-
</PerformanceLoggerContext.Provider>
51+
<AppContainer
52+
rootTag={rootTag}
53+
WrapperComponent={WrapperComponent}
54+
rootViewStyle={rootViewStyle}
55+
initialProps={initialProps ?? Object.freeze({})}
56+
internal_excludeLogBox={isLogBox}>
57+
<RootComponent {...initialProps} rootTag={rootTag} />
58+
</AppContainer>
6359
);
6460

6561
if (__DEV__ && debugName) {
@@ -74,9 +70,6 @@ export default function renderApplication<Props extends Object>(
7470
}
7571

7672
if (useOffscreen && displayMode != null) {
77-
// $FlowFixMe[incompatible-type]
78-
// $FlowFixMe[prop-missing]
79-
// $FlowFixMe[missing-export]
8073
const Activity: ActivityType = React.unstable_Activity;
8174

8275
renderable = (
@@ -87,18 +80,10 @@ export default function renderApplication<Props extends Object>(
8780
);
8881
}
8982

90-
performanceLogger.startTimespan('renderApplication_React_render');
91-
performanceLogger.setExtra('usedReactConcurrentRoot', '1');
92-
performanceLogger.setExtra('usedReactFabric', '1');
93-
performanceLogger.setExtra(
94-
'usedReactProfiler',
95-
Renderer.isProfilingRenderer(),
96-
);
9783
Renderer.renderElement({
9884
element: renderable,
9985
rootTag,
10086
useFabric: true,
10187
useConcurrentRoot: true,
10288
});
103-
performanceLogger.stopTimespan('renderApplication_React_render');
10489
}

packages/react-native/Libraries/Utilities/GlobalPerformanceLogger.js

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)