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' ;
74import { timestampInSeconds } from '@sentry/utils' ;
85import hoistNonReactStatics from 'hoist-non-react-statics' ;
96import * as React from 'react' ;
@@ -58,16 +55,12 @@ class Profiler extends React.Component<ProfilerProps> {
5855 return ;
5956 }
6057
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+ } ) ;
7164 }
7265
7366 // If a component mounted, we can finish the mount activity.
@@ -87,16 +80,17 @@ class Profiler extends React.Component<ProfilerProps> {
8780 const changedProps = Object . keys ( updateProps ) . filter ( k => updateProps [ k ] !== this . props . updateProps [ k ] ) ;
8881 if ( changedProps . length > 0 ) {
8982 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+ } ) ;
10094 } ) ;
10195 }
10296 }
@@ -114,19 +108,24 @@ class Profiler extends React.Component<ProfilerProps> {
114108 // If a component is unmounted, we can say it is no longer on the screen.
115109 // This means we can finish the span representing the component render.
116110 public componentWillUnmount ( ) : void {
111+ const endTimestamp = timestampInSeconds ( ) ;
117112 const { name, includeRender = true } = this . props ;
118113
119114 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+ }
130129 } ) ;
131130 }
132131 }
@@ -144,6 +143,7 @@ class Profiler extends React.Component<ProfilerProps> {
144143 * @param WrappedComponent component that is wrapped by Profiler
145144 * @param options the {@link ProfilerProps} you can pass into the Profiler
146145 */
146+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
147147function withProfiler < P extends Record < string , any > > (
148148 WrappedComponent : React . ComponentType < P > ,
149149 // We do not want to have `updateProps` given in options, it is instead filled through the HOC.
@@ -185,18 +185,12 @@ function useProfiler(
185185 return undefined ;
186186 }
187187
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+ } ) ;
200194 } ) ;
201195
202196 React . useEffect ( ( ) => {
@@ -206,15 +200,21 @@ function useProfiler(
206200
207201 return ( ) : void => {
208202 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 } >` ,
213208 op : REACT_RENDER_OP ,
214209 origin : 'auto.ui.react.profiler' ,
215- startTimestamp : spanToJSON ( mountSpan ) . timestamp ,
216- data : { 'ui.component_name' : name } ,
210+ startTimestamp,
211+ attributes : { 'ui.component_name' : name } ,
217212 } ) ;
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+ }
218218 }
219219 } ;
220220 // We only want this to run once.
@@ -223,18 +223,3 @@ function useProfiler(
223223}
224224
225225export { 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