1
- import type { Span , Tracer } from '@opentelemetry/api' ;
1
+ import type { Context , Span , SpanOptions , Tracer } from '@opentelemetry/api' ;
2
2
import { context } from '@opentelemetry/api' ;
3
3
import { SpanStatusCode , trace } from '@opentelemetry/api' ;
4
4
import { suppressTracing } from '@opentelemetry/core' ;
@@ -7,6 +7,7 @@ import type { Client, Scope } from '@sentry/types';
7
7
8
8
import { InternalSentrySemanticAttributes } from './semanticAttributes' ;
9
9
import type { OpenTelemetryClient , OpenTelemetrySpanContext } from './types' ;
10
+ import { getContextFromScope } from './utils/contextData' ;
10
11
import { setSpanMetadata } from './utils/spanData' ;
11
12
12
13
/**
@@ -18,17 +19,19 @@ import { setSpanMetadata } from './utils/spanData';
18
19
*
19
20
* Note that you'll always get a span passed to the callback, it may just be a NonRecordingSpan if the span is not sampled.
20
21
*/
21
- export function startSpan < T > ( spanContext : OpenTelemetrySpanContext , callback : ( span : Span ) => T ) : T {
22
+ export function startSpan < T > ( options : OpenTelemetrySpanContext , callback : ( span : Span ) => T ) : T {
22
23
const tracer = getTracer ( ) ;
23
24
24
- const { name } = spanContext ;
25
+ const { name } = options ;
25
26
26
- const activeCtx = context . active ( ) ;
27
- const shouldSkipSpan = spanContext . onlyIfParent && ! trace . getSpan ( activeCtx ) ;
27
+ const activeCtx = getContext ( options . scope ) ;
28
+ const shouldSkipSpan = options . onlyIfParent && ! trace . getSpan ( activeCtx ) ;
28
29
const ctx = shouldSkipSpan ? suppressTracing ( activeCtx ) : activeCtx ;
29
30
31
+ const spanContext = getSpanContext ( options ) ;
32
+
30
33
return tracer . startActiveSpan ( name , spanContext , ctx , span => {
31
- _applySentryAttributesToSpan ( span , spanContext ) ;
34
+ _applySentryAttributesToSpan ( span , options ) ;
32
35
33
36
return handleCallbackErrors (
34
37
( ) => callback ( span ) ,
@@ -49,17 +52,19 @@ export function startSpan<T>(spanContext: OpenTelemetrySpanContext, callback: (s
49
52
*
50
53
* Note that you'll always get a span passed to the callback, it may just be a NonRecordingSpan if the span is not sampled.
51
54
*/
52
- export function startSpanManual < T > ( spanContext : OpenTelemetrySpanContext , callback : ( span : Span ) => T ) : T {
55
+ export function startSpanManual < T > ( options : OpenTelemetrySpanContext , callback : ( span : Span ) => T ) : T {
53
56
const tracer = getTracer ( ) ;
54
57
55
- const { name } = spanContext ;
58
+ const { name } = options ;
56
59
57
- const activeCtx = context . active ( ) ;
58
- const shouldSkipSpan = spanContext . onlyIfParent && ! trace . getSpan ( activeCtx ) ;
60
+ const activeCtx = getContext ( options . scope ) ;
61
+ const shouldSkipSpan = options . onlyIfParent && ! trace . getSpan ( activeCtx ) ;
59
62
const ctx = shouldSkipSpan ? suppressTracing ( activeCtx ) : activeCtx ;
60
63
64
+ const spanContext = getSpanContext ( options ) ;
65
+
61
66
return tracer . startActiveSpan ( name , spanContext , ctx , span => {
62
- _applySentryAttributesToSpan ( span , spanContext ) ;
67
+ _applySentryAttributesToSpan ( span , options ) ;
63
68
64
69
return handleCallbackErrors (
65
70
( ) => callback ( span ) ,
@@ -85,18 +90,20 @@ export const startActiveSpan = startSpan;
85
90
* or you didn't set `tracesSampleRate` or `tracesSampler`, this function will not generate spans
86
91
* and the `span` returned from the callback will be undefined.
87
92
*/
88
- export function startInactiveSpan ( spanContext : OpenTelemetrySpanContext ) : Span {
93
+ export function startInactiveSpan ( options : OpenTelemetrySpanContext ) : Span {
89
94
const tracer = getTracer ( ) ;
90
95
91
- const { name } = spanContext ;
96
+ const { name } = options ;
92
97
93
- const activeCtx = context . active ( ) ;
94
- const shouldSkipSpan = spanContext . onlyIfParent && ! trace . getSpan ( activeCtx ) ;
98
+ const activeCtx = getContext ( options . scope ) ;
99
+ const shouldSkipSpan = options . onlyIfParent && ! trace . getSpan ( activeCtx ) ;
95
100
const ctx = shouldSkipSpan ? suppressTracing ( activeCtx ) : activeCtx ;
96
101
102
+ const spanContext = getSpanContext ( options ) ;
103
+
97
104
const span = tracer . startSpan ( name , spanContext , ctx ) ;
98
105
99
- _applySentryAttributesToSpan ( span , spanContext ) ;
106
+ _applySentryAttributesToSpan ( span , options ) ;
100
107
101
108
return span ;
102
109
}
@@ -120,8 +127,9 @@ function getTracer(): Tracer {
120
127
return ( client && client . tracer ) || trace . getTracer ( '@sentry/opentelemetry' , SDK_VERSION ) ;
121
128
}
122
129
123
- function _applySentryAttributesToSpan ( span : Span , spanContext : OpenTelemetrySpanContext ) : void {
124
- const { origin, op, source, metadata } = spanContext ;
130
+ function _applySentryAttributesToSpan ( span : Span , options : OpenTelemetrySpanContext ) : void {
131
+ // eslint-disable-next-line deprecation/deprecation
132
+ const { origin, op, source, metadata } = options ;
125
133
126
134
if ( origin ) {
127
135
span . setAttribute ( InternalSentrySemanticAttributes . ORIGIN , origin ) ;
@@ -139,3 +147,32 @@ function _applySentryAttributesToSpan(span: Span, spanContext: OpenTelemetrySpan
139
147
setSpanMetadata ( span , metadata ) ;
140
148
}
141
149
}
150
+
151
+ function getSpanContext ( options : OpenTelemetrySpanContext ) : SpanOptions {
152
+ const { startTime, attributes, kind } = options ;
153
+
154
+ // OTEL expects timestamps in ms, not seconds
155
+ const fixedStartTime = typeof startTime === 'number' ? ensureTimestampInMilliseconds ( startTime ) : startTime ;
156
+
157
+ return {
158
+ attributes,
159
+ kind,
160
+ startTime : fixedStartTime ,
161
+ } ;
162
+ }
163
+
164
+ function ensureTimestampInMilliseconds ( timestamp : number ) : number {
165
+ const isMs = timestamp < 9999999999 ;
166
+ return isMs ? timestamp * 1000 : timestamp ;
167
+ }
168
+
169
+ function getContext ( scope ?: Scope ) : Context {
170
+ if ( scope ) {
171
+ const ctx = getContextFromScope ( scope ) ;
172
+ if ( ctx ) {
173
+ return ctx ;
174
+ }
175
+ }
176
+
177
+ return context . active ( ) ;
178
+ }
0 commit comments