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' ;
4
4
import * as hoistNonReactStatic from 'hoist-non-react-statics' ;
5
5
import * as React from 'react' ;
6
6
@@ -11,6 +11,7 @@ const TRACING_GETTER = ({
11
11
} as any ) as IntegrationClass < Integration > ;
12
12
13
13
let globalTracingIntegration : Integration | null = null ;
14
+ /** @deprecated remove when @sentry/apm no longer used */
14
15
const getTracingIntegration = ( ) => {
15
16
if ( globalTracingIntegration ) {
16
17
return globalTracingIntegration ;
@@ -20,21 +21,11 @@ const getTracingIntegration = () => {
20
21
return globalTracingIntegration ;
21
22
} ;
22
23
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
-
34
24
/**
35
25
* pushActivity creates an new react activity.
36
26
* Is a no-op if Tracing integration is not valid
37
27
* @param name displayName of component that started activity
28
+ * @deprecated remove when @sentry/apm no longer used
38
29
*/
39
30
function pushActivity ( name : string , op : string ) : number | null {
40
31
if ( globalTracingIntegration === null ) {
@@ -52,6 +43,7 @@ function pushActivity(name: string, op: string): number | null {
52
43
* popActivity removes a React activity.
53
44
* Is a no-op if Tracing integration is not valid.
54
45
* @param activity id of activity that is being popped
46
+ * @deprecated remove when @sentry/apm no longer used
55
47
*/
56
48
function popActivity ( activity : number | null ) : void {
57
49
if ( activity === null || globalTracingIntegration === null ) {
@@ -66,6 +58,7 @@ function popActivity(activity: number | null): void {
66
58
* Obtain a span given an activity id.
67
59
* Is a no-op if Tracing integration is not valid.
68
60
* @param activity activity id associated with obtained span
61
+ * @deprecated remove when @sentry/apm no longer used
69
62
*/
70
63
function getActivitySpan ( activity : number | null ) : Span | undefined {
71
64
if ( activity === null || globalTracingIntegration === null ) {
@@ -96,11 +89,9 @@ export type ProfilerProps = {
96
89
*/
97
90
class Profiler extends React . Component < ProfilerProps > {
98
91
// The activity representing how long it takes to mount a component.
99
- public mountActivity : number | null = null ;
92
+ private _mountActivity : number | null = null ;
100
93
// 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 ;
104
95
105
96
public static defaultProps : Partial < ProfilerProps > = {
106
97
disabled : false ,
@@ -116,33 +107,48 @@ class Profiler extends React.Component<ProfilerProps> {
116
107
return ;
117
108
}
118
109
110
+ // If they are using @sentry /apm, we need to push/pop activities
111
+ // tslint:disable-next-line: deprecation
119
112
if ( getTracingIntegration ( ) ) {
120
- this . mountActivity = pushActivity ( name , 'mount' ) ;
113
+ // tslint:disable-next-line: deprecation
114
+ this . _mountActivity = pushActivity ( name , 'mount' ) ;
121
115
} 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
+ }
123
123
}
124
124
}
125
125
126
126
// If a component mounted, we can finish the mount activity.
127
127
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
+ }
131
137
}
132
138
133
139
public componentDidUpdate ( { updateProps, includeUpdates = true } : ProfilerProps ) : void {
134
140
// Only generate an update span if hasUpdateSpan is true, if there is a valid mountSpan,
135
141
// and if the updateProps have changed. It is ok to not do a deep equality check here as it is expensive.
136
142
// 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 ) {
138
144
// See what props haved changed between the previous props, and the current props. This is
139
145
// set as data on the span. We just store the prop keys as the values could be potenially very large.
140
146
const changedProps = Object . keys ( updateProps ) . filter ( k => updateProps [ k ] !== this . props . updateProps [ k ] ) ;
141
147
if ( changedProps . length > 0 ) {
142
148
// The update span is a point in time span with 0 duration, just signifying that the component
143
149
// has been updated.
144
150
const now = timestampWithMs ( ) ;
145
- this . mountSpan . startChild ( {
151
+ this . _mountSpan . startChild ( {
146
152
data : {
147
153
changedProps,
148
154
} ,
@@ -160,14 +166,14 @@ class Profiler extends React.Component<ProfilerProps> {
160
166
public componentWillUnmount ( ) : void {
161
167
const { name, includeRender = true } = this . props ;
162
168
163
- if ( this . mountSpan && includeRender ) {
169
+ if ( this . _mountSpan && includeRender ) {
164
170
// If we were able to obtain the spanId of the mount activity, we should set the
165
171
// next activity as a child to the component mount activity.
166
- this . mountSpan . startChild ( {
172
+ this . _mountSpan . startChild ( {
167
173
description : `<${ name } >` ,
168
174
endTimestamp : timestampWithMs ( ) ,
169
175
op : `react.render` ,
170
- startTimestamp : this . mountSpan . endTimestamp ,
176
+ startTimestamp : this . _mountSpan . endTimestamp ,
171
177
} ) ;
172
178
}
173
179
}
@@ -221,22 +227,26 @@ function useProfiler(
221
227
hasRenderSpan : true ,
222
228
} ,
223
229
) : void {
224
- const [ mountActivity ] = React . useState ( ( ) => {
230
+ const [ mountSpan ] = React . useState ( ( ) => {
225
231
if ( options && options . disabled ) {
226
- return null ;
232
+ return undefined ;
227
233
}
228
234
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
+ } ) ;
231
241
}
232
242
233
- warnAboutTracing ( name ) ;
234
- return null ;
243
+ return undefined ;
235
244
} ) ;
236
245
237
246
React . useEffect ( ( ) => {
238
- const mountSpan = getActivitySpan ( mountActivity ) ;
239
- popActivity ( mountActivity ) ;
247
+ if ( mountSpan ) {
248
+ mountSpan . finish ( ) ;
249
+ }
240
250
241
251
return ( ) => {
242
252
if ( mountSpan && options . hasRenderSpan ) {
@@ -252,3 +262,15 @@ function useProfiler(
252
262
}
253
263
254
264
export { 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