1
1
import { getMainCarrier , Hub } from '@sentry/hub' ;
2
2
import { SpanContext } from '@sentry/types' ;
3
- import { isInstanceOf } from '@sentry/utils' ;
4
3
5
4
import { Span } from './span' ;
6
5
7
- /**
8
- * Checks whether given value is instance of Span
9
- * @param span value to check
10
- */
11
- function isSpanInstance ( span : unknown ) : span is Span {
12
- return isInstanceOf ( span , Span ) ;
13
- }
14
-
15
6
/** Returns all trace headers that are currently on the top scope. */
16
7
function traceHeaders ( ) : { [ key : string ] : string } {
17
8
// @ts -ignore
@@ -33,36 +24,42 @@ function traceHeaders(): { [key: string]: string } {
33
24
* and attach a `SpanRecorder`. If it's of type `SpanContext` and there is already a `Span` on the Scope,
34
25
* the created Span will have a reference to it and become it's child. Otherwise it'll crete a new `Span`.
35
26
*
36
- * @param span Already constructed span which should be started or properties with which the span should be created
27
+ * @param spanContext Already constructed span or properties with which the span should be created
37
28
*/
38
- function startSpan ( spanOrSpanContext ?: Span | SpanContext , forceNoChild : boolean = false ) : Span {
29
+ function startSpan ( spanContext ?: SpanContext ) : Span {
39
30
// @ts -ignore
40
- const that = this as Hub ;
41
- const scope = that . getScope ( ) ;
42
- const client = that . getClient ( ) ;
31
+ const hub = this as Hub ;
32
+ const scope = hub . getScope ( ) ;
33
+ const client = hub . getClient ( ) ;
43
34
let span ;
44
35
45
- if ( ! isSpanInstance ( spanOrSpanContext ) && ! forceNoChild ) {
46
- if ( scope ) {
47
- const parentSpan = scope . getSpan ( ) as Span ;
48
- if ( parentSpan ) {
49
- span = parentSpan . child ( spanOrSpanContext ) ;
50
- }
36
+ // This flag determines if we already added the span as a child to the span that currently lives on the scope
37
+ // If we do not have this, we will add it later on twice to the span recorder and therefore have too many spans
38
+ let addedAsChild = false ;
39
+
40
+ if ( scope ) {
41
+ const parentSpan = scope . getSpan ( ) as Span ;
42
+ if ( parentSpan ) {
43
+ span = parentSpan . child ( spanContext ) ;
44
+ addedAsChild = true ;
51
45
}
52
46
}
53
47
54
- if ( ! isSpanInstance ( span ) ) {
55
- span = new Span ( spanOrSpanContext , that ) ;
48
+ if ( ! span ) {
49
+ span = new Span ( spanContext , hub ) ;
56
50
}
57
51
58
- if ( span . sampled === undefined && span . transaction !== undefined ) {
52
+ // We only roll the dice on sampling for "root" spans (transactions) because the childs inherit this state
53
+ if ( span . sampled === undefined && span . isRootSpan ( ) ) {
59
54
const sampleRate = ( client && client . getOptions ( ) . tracesSampleRate ) || 0 ;
60
55
span . sampled = Math . random ( ) < sampleRate ;
61
56
}
62
57
63
- if ( span . sampled ) {
58
+ // We only want to create a span list if we sampled the transaction
59
+ // in case we will discard the span anyway because sampled == false, we safe memory and do not store child spans
60
+ if ( span . sampled && ! addedAsChild ) {
64
61
const experimentsOptions = ( client && client . getOptions ( ) . _experiments ) || { } ;
65
- span . initFinishedSpans ( experimentsOptions . maxSpans as number ) ;
62
+ span . initSpanRecorder ( experimentsOptions . maxSpans as number ) ;
66
63
}
67
64
68
65
return span ;
0 commit comments