1
- /* eslint-disable @typescript-eslint/no-unsafe-member-access */
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
3
- import type { Hub } from '@sentry/browser' ;
4
- import { getCurrentHub } from '@sentry/browser' ;
5
- import { spanToJSON } from '@sentry/core' ;
6
- import type { Span , Transaction } from '@sentry/types' ;
1
+ import { startInactiveSpan } from '@sentry/browser' ;
2
+ import { spanToJSON , withActiveSpan } from '@sentry/core' ;
3
+ import type { Span } from '@sentry/types' ;
7
4
import { timestampInSeconds } from '@sentry/utils' ;
8
5
import hoistNonReactStatics from 'hoist-non-react-statics' ;
9
6
import * as React from 'react' ;
@@ -58,16 +55,12 @@ class Profiler extends React.Component<ProfilerProps> {
58
55
return ;
59
56
}
60
57
61
- const activeTransaction = getActiveTransaction ( ) ;
62
- if ( activeTransaction ) {
63
- // eslint-disable-next-line deprecation/deprecation
64
- this . _mountSpan = activeTransaction . startChild ( {
65
- description : `<${ name } >` ,
66
- op : REACT_MOUNT_OP ,
67
- origin : 'auto.ui.react.profiler' ,
68
- data : { 'ui.component_name' : name } ,
69
- } ) ;
70
- }
58
+ this . _mountSpan = startInactiveSpan ( {
59
+ name : `<${ name } >` ,
60
+ op : REACT_MOUNT_OP ,
61
+ origin : 'auto.ui.react.profiler' ,
62
+ attributes : { 'ui.component_name' : name } ,
63
+ } ) ;
71
64
}
72
65
73
66
// If a component mounted, we can finish the mount activity.
@@ -87,16 +80,17 @@ class Profiler extends React.Component<ProfilerProps> {
87
80
const changedProps = Object . keys ( updateProps ) . filter ( k => updateProps [ k ] !== this . props . updateProps [ k ] ) ;
88
81
if ( changedProps . length > 0 ) {
89
82
const now = timestampInSeconds ( ) ;
90
- // eslint-disable-next-line deprecation/deprecation
91
- this . _updateSpan = this . _mountSpan . startChild ( {
92
- data : {
93
- changedProps,
94
- 'ui.component_name' : this . props . name ,
95
- } ,
96
- description : `<${ this . props . name } >` ,
97
- op : REACT_UPDATE_OP ,
98
- origin : 'auto.ui.react.profiler' ,
99
- startTimestamp : now ,
83
+ this . _updateSpan = withActiveSpan ( this . _mountSpan , ( ) => {
84
+ return startInactiveSpan ( {
85
+ name : `<${ this . props . name } >` ,
86
+ op : REACT_UPDATE_OP ,
87
+ origin : 'auto.ui.react.profiler' ,
88
+ startTimestamp : now ,
89
+ attributes : {
90
+ 'ui.component_name' : this . props . name ,
91
+ 'ui.react.changed_props' : changedProps ,
92
+ } ,
93
+ } ) ;
100
94
} ) ;
101
95
}
102
96
}
@@ -114,19 +108,24 @@ class Profiler extends React.Component<ProfilerProps> {
114
108
// If a component is unmounted, we can say it is no longer on the screen.
115
109
// This means we can finish the span representing the component render.
116
110
public componentWillUnmount ( ) : void {
111
+ const endTimestamp = timestampInSeconds ( ) ;
117
112
const { name, includeRender = true } = this . props ;
118
113
119
114
if ( this . _mountSpan && includeRender ) {
120
- // If we were able to obtain the spanId of the mount activity, we should set the
121
- // next activity as a child to the component mount activity.
122
- // eslint-disable-next-line deprecation/deprecation
123
- this . _mountSpan . startChild ( {
124
- description : `<${ name } >` ,
125
- endTimestamp : timestampInSeconds ( ) ,
126
- op : REACT_RENDER_OP ,
127
- origin : 'auto.ui.react.profiler' ,
128
- startTimestamp : spanToJSON ( this . _mountSpan ) . timestamp ,
129
- data : { 'ui.component_name' : name } ,
115
+ const startTimestamp = spanToJSON ( this . _mountSpan ) . timestamp ;
116
+ withActiveSpan ( this . _mountSpan , ( ) => {
117
+ const renderSpan = startInactiveSpan ( {
118
+ name : `<${ name } >` ,
119
+ op : REACT_RENDER_OP ,
120
+ origin : 'auto.ui.react.profiler' ,
121
+ startTimestamp,
122
+ attributes : { 'ui.component_name' : name } ,
123
+ } ) ;
124
+ if ( renderSpan ) {
125
+ // Have to cast to Span because the type of _mountSpan is Span | undefined
126
+ // and not getting narrowed properly
127
+ renderSpan . end ( endTimestamp ) ;
128
+ }
130
129
} ) ;
131
130
}
132
131
}
@@ -144,6 +143,7 @@ class Profiler extends React.Component<ProfilerProps> {
144
143
* @param WrappedComponent component that is wrapped by Profiler
145
144
* @param options the {@link ProfilerProps} you can pass into the Profiler
146
145
*/
146
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
147
147
function withProfiler < P extends Record < string , any > > (
148
148
WrappedComponent : React . ComponentType < P > ,
149
149
// We do not want to have `updateProps` given in options, it is instead filled through the HOC.
@@ -185,18 +185,12 @@ function useProfiler(
185
185
return undefined ;
186
186
}
187
187
188
- const activeTransaction = getActiveTransaction ( ) ;
189
- if ( activeTransaction ) {
190
- // eslint-disable-next-line deprecation/deprecation
191
- return activeTransaction . startChild ( {
192
- description : `<${ name } >` ,
193
- op : REACT_MOUNT_OP ,
194
- origin : 'auto.ui.react.profiler' ,
195
- data : { 'ui.component_name' : name } ,
196
- } ) ;
197
- }
198
-
199
- return undefined ;
188
+ return startInactiveSpan ( {
189
+ name : `<${ name } >` ,
190
+ op : REACT_MOUNT_OP ,
191
+ origin : 'auto.ui.react.profiler' ,
192
+ attributes : { 'ui.component_name' : name } ,
193
+ } ) ;
200
194
} ) ;
201
195
202
196
React . useEffect ( ( ) => {
@@ -206,15 +200,21 @@ function useProfiler(
206
200
207
201
return ( ) : void => {
208
202
if ( mountSpan && options . hasRenderSpan ) {
209
- // eslint-disable-next-line deprecation/deprecation
210
- mountSpan . startChild ( {
211
- description : `<${ name } >` ,
212
- endTimestamp : timestampInSeconds ( ) ,
203
+ const startTimestamp = spanToJSON ( mountSpan ) . timestamp ;
204
+ const endTimestamp = timestampInSeconds ( ) ;
205
+
206
+ const renderSpan = startInactiveSpan ( {
207
+ name : `<${ name } >` ,
213
208
op : REACT_RENDER_OP ,
214
209
origin : 'auto.ui.react.profiler' ,
215
- startTimestamp : spanToJSON ( mountSpan ) . timestamp ,
216
- data : { 'ui.component_name' : name } ,
210
+ startTimestamp,
211
+ attributes : { 'ui.component_name' : name } ,
217
212
} ) ;
213
+ if ( renderSpan ) {
214
+ // Have to cast to Span because the type of _mountSpan is Span | undefined
215
+ // and not getting narrowed properly
216
+ renderSpan . end ( endTimestamp ) ;
217
+ }
218
218
}
219
219
} ;
220
220
// We only want this to run once.
@@ -223,18 +223,3 @@ function useProfiler(
223
223
}
224
224
225
225
export { withProfiler , Profiler , useProfiler } ;
226
-
227
- /** Grabs active transaction off scope */
228
- export function getActiveTransaction < T extends Transaction > (
229
- // eslint-disable-next-line deprecation/deprecation
230
- hub : Hub = getCurrentHub ( ) ,
231
- ) : T | undefined {
232
- if ( hub ) {
233
- // eslint-disable-next-line deprecation/deprecation
234
- const scope = hub . getScope ( ) ;
235
- // eslint-disable-next-line deprecation/deprecation
236
- return scope . getTransaction ( ) as T | undefined ;
237
- }
238
-
239
- return undefined ;
240
- }
0 commit comments