1- import { getCurrentHub } from '@sentry/browser' ;
2- import { Integration , IntegrationClass , Span } from '@sentry/types' ;
3- import { logger , timestampWithMs } from '@sentry/utils' ;
1+ import { getCurrentHub , Hub } from '@sentry/browser' ;
2+ import { Integration , IntegrationClass , Span , Transaction } from '@sentry/types' ;
3+ import { timestampWithMs } from '@sentry/utils' ;
44import * as hoistNonReactStatic from 'hoist-non-react-statics' ;
55import * as React from 'react' ;
66
@@ -11,6 +11,7 @@ const TRACING_GETTER = ({
1111} as any ) as IntegrationClass < Integration > ;
1212
1313let globalTracingIntegration : Integration | null = null ;
14+ /** @deprecated remove when @sentry/apm no longer used */
1415const getTracingIntegration = ( ) => {
1516 if ( globalTracingIntegration ) {
1617 return globalTracingIntegration ;
@@ -20,21 +21,11 @@ const getTracingIntegration = () => {
2021 return globalTracingIntegration ;
2122} ;
2223
23- /**
24- * Warn if tracing integration not configured. Will only warn once.
25- */
26- function warnAboutTracing ( name : string ) : void {
27- if ( globalTracingIntegration === null ) {
28- logger . warn (
29- `Unable to profile component ${ name } due to invalid Tracing Integration. Please make sure the Tracing integration is setup properly.` ,
30- ) ;
31- }
32- }
33-
3424/**
3525 * pushActivity creates an new react activity.
3626 * Is a no-op if Tracing integration is not valid
3727 * @param name displayName of component that started activity
28+ * @deprecated remove when @sentry/apm no longer used
3829 */
3930function pushActivity ( name : string , op : string ) : number | null {
4031 if ( globalTracingIntegration === null ) {
@@ -52,6 +43,7 @@ function pushActivity(name: string, op: string): number | null {
5243 * popActivity removes a React activity.
5344 * Is a no-op if Tracing integration is not valid.
5445 * @param activity id of activity that is being popped
46+ * @deprecated remove when @sentry/apm no longer used
5547 */
5648function popActivity ( activity : number | null ) : void {
5749 if ( activity === null || globalTracingIntegration === null ) {
@@ -66,6 +58,7 @@ function popActivity(activity: number | null): void {
6658 * Obtain a span given an activity id.
6759 * Is a no-op if Tracing integration is not valid.
6860 * @param activity activity id associated with obtained span
61+ * @deprecated remove when @sentry/apm no longer used
6962 */
7063function getActivitySpan ( activity : number | null ) : Span | undefined {
7164 if ( activity === null || globalTracingIntegration === null ) {
@@ -96,11 +89,9 @@ export type ProfilerProps = {
9689 */
9790class Profiler extends React . Component < ProfilerProps > {
9891 // The activity representing how long it takes to mount a component.
99- public mountActivity : number | null = null ;
92+ private _mountActivity : number | null = null ;
10093 // The span of the mount activity
101- public mountSpan : Span | undefined = undefined ;
102- // The span of the render
103- public renderSpan : Span | undefined = undefined ;
94+ private _mountSpan : Span | undefined = undefined ;
10495
10596 public static defaultProps : Partial < ProfilerProps > = {
10697 disabled : false ,
@@ -116,33 +107,48 @@ class Profiler extends React.Component<ProfilerProps> {
116107 return ;
117108 }
118109
110+ // If they are using @sentry /apm, we need to push/pop activities
111+ // tslint:disable-next-line: deprecation
119112 if ( getTracingIntegration ( ) ) {
120- this . mountActivity = pushActivity ( name , 'mount' ) ;
113+ // tslint:disable-next-line: deprecation
114+ this . _mountActivity = pushActivity ( name , 'mount' ) ;
121115 } else {
122- warnAboutTracing ( name ) ;
116+ const activeTransaction = getActiveTransaction ( ) ;
117+ if ( activeTransaction ) {
118+ this . _mountSpan = activeTransaction . startChild ( {
119+ description : `<${ name } >` ,
120+ op : 'react.mount' ,
121+ } ) ;
122+ }
123123 }
124124 }
125125
126126 // If a component mounted, we can finish the mount activity.
127127 public componentDidMount ( ) : void {
128- this . mountSpan = getActivitySpan ( this . mountActivity ) ;
129- popActivity ( this . mountActivity ) ;
130- this . mountActivity = null ;
128+ if ( this . _mountSpan ) {
129+ this . _mountSpan . finish ( ) ;
130+ } else {
131+ // tslint:disable-next-line: deprecation
132+ this . _mountSpan = getActivitySpan ( this . _mountActivity ) ;
133+ // tslint:disable-next-line: deprecation
134+ popActivity ( this . _mountActivity ) ;
135+ this . _mountActivity = null ;
136+ }
131137 }
132138
133139 public componentDidUpdate ( { updateProps, includeUpdates = true } : ProfilerProps ) : void {
134140 // Only generate an update span if hasUpdateSpan is true, if there is a valid mountSpan,
135141 // and if the updateProps have changed. It is ok to not do a deep equality check here as it is expensive.
136142 // We are just trying to give baseline clues for further investigation.
137- if ( includeUpdates && this . mountSpan && updateProps !== this . props . updateProps ) {
143+ if ( includeUpdates && this . _mountSpan && updateProps !== this . props . updateProps ) {
138144 // See what props haved changed between the previous props, and the current props. This is
139145 // set as data on the span. We just store the prop keys as the values could be potenially very large.
140146 const changedProps = Object . keys ( updateProps ) . filter ( k => updateProps [ k ] !== this . props . updateProps [ k ] ) ;
141147 if ( changedProps . length > 0 ) {
142148 // The update span is a point in time span with 0 duration, just signifying that the component
143149 // has been updated.
144150 const now = timestampWithMs ( ) ;
145- this . mountSpan . startChild ( {
151+ this . _mountSpan . startChild ( {
146152 data : {
147153 changedProps,
148154 } ,
@@ -160,14 +166,14 @@ class Profiler extends React.Component<ProfilerProps> {
160166 public componentWillUnmount ( ) : void {
161167 const { name, includeRender = true } = this . props ;
162168
163- if ( this . mountSpan && includeRender ) {
169+ if ( this . _mountSpan && includeRender ) {
164170 // If we were able to obtain the spanId of the mount activity, we should set the
165171 // next activity as a child to the component mount activity.
166- this . mountSpan . startChild ( {
172+ this . _mountSpan . startChild ( {
167173 description : `<${ name } >` ,
168174 endTimestamp : timestampWithMs ( ) ,
169175 op : `react.render` ,
170- startTimestamp : this . mountSpan . endTimestamp ,
176+ startTimestamp : this . _mountSpan . endTimestamp ,
171177 } ) ;
172178 }
173179 }
@@ -221,22 +227,26 @@ function useProfiler(
221227 hasRenderSpan : true ,
222228 } ,
223229) : void {
224- const [ mountActivity ] = React . useState ( ( ) => {
230+ const [ mountSpan ] = React . useState ( ( ) => {
225231 if ( options && options . disabled ) {
226- return null ;
232+ return undefined ;
227233 }
228234
229- if ( getTracingIntegration ( ) ) {
230- return pushActivity ( name , 'mount' ) ;
235+ const activeTransaction = getActiveTransaction ( ) ;
236+ if ( activeTransaction ) {
237+ return activeTransaction . startChild ( {
238+ description : `<${ name } >` ,
239+ op : 'react.mount' ,
240+ } ) ;
231241 }
232242
233- warnAboutTracing ( name ) ;
234- return null ;
243+ return undefined ;
235244 } ) ;
236245
237246 React . useEffect ( ( ) => {
238- const mountSpan = getActivitySpan ( mountActivity ) ;
239- popActivity ( mountActivity ) ;
247+ if ( mountSpan ) {
248+ mountSpan . finish ( ) ;
249+ }
240250
241251 return ( ) => {
242252 if ( mountSpan && options . hasRenderSpan ) {
@@ -252,3 +262,15 @@ function useProfiler(
252262}
253263
254264export { withProfiler , Profiler , useProfiler } ;
265+
266+ /** Grabs active transaction off scope */
267+ export function getActiveTransaction < T extends Transaction > ( hub : Hub = getCurrentHub ( ) ) : T | undefined {
268+ if ( hub ) {
269+ const scope = hub . getScope ( ) ;
270+ if ( scope ) {
271+ return scope . getTransaction ( ) as T | undefined ;
272+ }
273+ }
274+
275+ return undefined ;
276+ }
0 commit comments