Skip to content

Commit cb2ce41

Browse files
committed
Rework render span
1 parent 3c5a8d6 commit cb2ce41

File tree

3 files changed

+56
-57
lines changed

3 files changed

+56
-57
lines changed

packages/apm/src/integrations/tracing.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ export class Tracing implements Integration {
776776
spanContext?: SpanContext,
777777
options?: {
778778
autoPopAfter?: number;
779-
},
779+
},
780780
): number {
781781
const activeTransaction = Tracing._activeTransaction;
782782

packages/react/src/profiler.tsx

+23-28
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export type ProfilerProps = {
8383
// If the Profiler is disabled. False by default. This is useful if you want to disable profilers
8484
// in certain environments.
8585
disabled?: boolean;
86-
// If time component is on page should be displayed as spans. False by default.
86+
// If time component is on page should be displayed as spans. True by default.
8787
hasRenderSpan?: boolean;
8888
// If component updates should be displayed as spans. True by default.
8989
hasUpdateSpan?: boolean;
@@ -105,7 +105,7 @@ class Profiler extends React.Component<ProfilerProps> {
105105

106106
public static defaultProps: Partial<ProfilerProps> = {
107107
disabled: false,
108-
hasRenderSpan: false,
108+
hasRenderSpan: true,
109109
hasUpdateSpan: true,
110110
};
111111

@@ -129,17 +129,6 @@ class Profiler extends React.Component<ProfilerProps> {
129129
this.mountSpan = getActivitySpan(this.mountActivity);
130130
popActivity(this.mountActivity);
131131
this.mountActivity = null;
132-
133-
const { name, hasRenderSpan = false } = this.props;
134-
135-
// If we were able to obtain the spanId of the mount activity, we should set the
136-
// next activity as a child to the component mount activity.
137-
if (this.mountSpan && hasRenderSpan) {
138-
this.renderSpan = this.mountSpan.startChild({
139-
description: `<${name}>`,
140-
op: `react.render`,
141-
});
142-
}
143132
}
144133

145134
public componentDidUpdate({ updateProps, hasUpdateSpan = true }: ProfilerProps): void {
@@ -170,8 +159,17 @@ class Profiler extends React.Component<ProfilerProps> {
170159
// If a component is unmounted, we can say it is no longer on the screen.
171160
// This means we can finish the span representing the component render.
172161
public componentWillUnmount(): void {
173-
if (this.renderSpan) {
174-
this.renderSpan.finish();
162+
const { name, hasRenderSpan = true } = this.props;
163+
164+
if (this.mountSpan && hasRenderSpan) {
165+
// If we were able to obtain the spanId of the mount activity, we should set the
166+
// next activity as a child to the component mount activity.
167+
this.mountSpan.startChild({
168+
description: `<${name}>`,
169+
endTimestamp: timestampWithMs(),
170+
op: `react.render`,
171+
startTimestamp: this.mountSpan.endTimestamp,
172+
});
175173
}
176174
}
177175

@@ -219,9 +217,9 @@ function withProfiler<P extends object>(
219217
*/
220218
function useProfiler(
221219
name: string,
222-
options?: {
223-
disabled?: boolean;
224-
hasRenderSpan?: boolean;
220+
options: { disabled?: boolean; hasRenderSpan?: boolean } = {
221+
disabled: false,
222+
hasRenderSpan: true,
225223
},
226224
): void {
227225
const [mountActivity] = React.useState(() => {
@@ -241,17 +239,14 @@ function useProfiler(
241239
const mountSpan = getActivitySpan(mountActivity);
242240
popActivity(mountActivity);
243241

244-
const renderSpan =
245-
mountSpan && options && options.hasRenderSpan
246-
? mountSpan.startChild({
247-
description: `<${name}>`,
248-
op: `react.render`,
249-
})
250-
: undefined;
251-
252242
return () => {
253-
if (renderSpan) {
254-
renderSpan.finish();
243+
if (mountSpan && options.hasRenderSpan) {
244+
mountSpan.startChild({
245+
description: `<${name}>`,
246+
endTimestamp: timestampWithMs(),
247+
op: `react.render`,
248+
startTimestamp: mountSpan.endTimestamp,
249+
});
255250
}
256251
};
257252
}, []);

packages/react/test/profiler.test.tsx

+32-28
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ SENTRY_APM_SAMPLING = 1
1212
)*/
1313
const TEST_SPAN_ID = '518999beeceb49af';
1414

15-
const mockSpanFinish = jest.fn();
16-
const mockStartChild = jest.fn((spanArgs: SpanContext) => ({ ...spanArgs, finish: mockSpanFinish }));
15+
const mockStartChild = jest.fn((spanArgs: SpanContext) => ({ ...spanArgs }));
1716
const TEST_SPAN = {
1817
spanId: TEST_SPAN_ID,
1918
startChild: mockStartChild,
@@ -57,7 +56,6 @@ beforeEach(() => {
5756
mockLoggerWarn.mockClear();
5857
mockGetActivitySpan.mockClear();
5958
mockStartChild.mockClear();
60-
mockSpanFinish.mockClear();
6159
});
6260

6361
describe('withProfiler', () => {
@@ -111,26 +109,30 @@ describe('withProfiler', () => {
111109
});
112110

113111
describe('render span', () => {
114-
it('does not get created by default', () => {
112+
it('is created on unmount', () => {
115113
const ProfiledComponent = withProfiler(() => <h1>Testing</h1>);
116114
expect(mockStartChild).toHaveBeenCalledTimes(0);
117-
render(<ProfiledComponent />);
118-
expect(mockStartChild).toHaveBeenCalledTimes(0);
119-
});
120115

121-
it('is created when given hasRenderSpan option', () => {
122-
const ProfiledComponent = withProfiler(() => <h1>Testing</h1>, { hasRenderSpan: true });
123-
expect(mockStartChild).toHaveBeenCalledTimes(0);
124116
const component = render(<ProfiledComponent />);
117+
component.unmount();
118+
125119
expect(mockStartChild).toHaveBeenCalledTimes(1);
126-
expect(mockStartChild).toHaveBeenLastCalledWith({
127-
description: `<${UNKNOWN_COMPONENT}>`,
128-
op: 'react.render',
129-
});
120+
expect(mockStartChild).toHaveBeenLastCalledWith(
121+
expect.objectContaining({
122+
description: `<${UNKNOWN_COMPONENT}>`,
123+
op: 'react.render',
124+
}),
125+
);
126+
});
130127

131-
expect(mockSpanFinish).toHaveBeenCalledTimes(0);
128+
it('is not created if hasRenderSpan is false', () => {
129+
const ProfiledComponent = withProfiler(() => <h1>Testing</h1>, { hasRenderSpan: false });
130+
expect(mockStartChild).toHaveBeenCalledTimes(0);
131+
132+
const component = render(<ProfiledComponent />);
132133
component.unmount();
133-
expect(mockSpanFinish).toHaveBeenCalledTimes(1);
134+
135+
expect(mockStartChild).toHaveBeenCalledTimes(0);
134136
});
135137
});
136138

@@ -207,25 +209,27 @@ describe('useProfiler()', () => {
207209
});
208210

209211
describe('render span', () => {
210-
it('does not get created by default', () => {
212+
it('does not get created when hasRenderSpan is false', () => {
211213
// tslint:disable-next-line: no-void-expression
212-
renderHook(() => useProfiler('Example'));
214+
const component = renderHook(() => useProfiler('Example', { hasRenderSpan: false }));
215+
expect(mockStartChild).toHaveBeenCalledTimes(0);
216+
component.unmount();
213217
expect(mockStartChild).toHaveBeenCalledTimes(0);
214218
});
215219

216-
it('is created when given hasRenderSpan option', () => {
220+
it('is created by default', () => {
217221
// tslint:disable-next-line: no-void-expression
218-
const component = renderHook(() => useProfiler('Example', { hasRenderSpan: true }));
219-
220-
expect(mockStartChild).toHaveBeenCalledTimes(1);
221-
expect(mockStartChild).toHaveBeenLastCalledWith({
222-
description: '<Example>',
223-
op: 'react.render',
224-
});
222+
const component = renderHook(() => useProfiler('Example'));
225223

226-
expect(mockSpanFinish).toHaveBeenCalledTimes(0);
224+
expect(mockStartChild).toHaveBeenCalledTimes(0);
227225
component.unmount();
228-
expect(mockSpanFinish).toHaveBeenCalledTimes(1);
226+
expect(mockStartChild).toHaveBeenCalledTimes(1);
227+
expect(mockStartChild).toHaveBeenLastCalledWith(
228+
expect.objectContaining({
229+
description: '<Example>',
230+
op: 'react.render',
231+
}),
232+
);
229233
});
230234
});
231235
});

0 commit comments

Comments
 (0)