@@ -10,6 +10,7 @@ import {
1010 getDefaultCurrentScope ,
1111 isObjectLike ,
1212 startNewTrace ,
13+ timestampInSeconds ,
1314 withActiveSpan ,
1415 withScope ,
1516} from '@sentry/core' ;
@@ -61,16 +62,8 @@ function deriveOp(name: string): string | undefined {
6162 return undefined ;
6263}
6364
64- type HrTime = [ number , number ] ;
65-
6665const SENTRY_SPAN_SYMBOL = Symbol . for ( '@sentry/effect.SentrySpan' ) ;
6766
68- function nanosToHrTime ( nanos : bigint ) : HrTime {
69- const seconds = Number ( nanos / BigInt ( 1_000_000_000 ) ) ;
70- const remainingNanos = Number ( nanos % BigInt ( 1_000_000_000 ) ) ;
71- return [ seconds , remainingNanos ] ;
72- }
73-
7467interface SentrySpanLike extends EffectTracer . Span {
7568 readonly [ SENTRY_SPAN_SYMBOL ] : true ;
7669 readonly sentrySpan : Span ;
@@ -127,6 +120,7 @@ class SentrySpanWrapper implements SentrySpanLike {
127120 public status : EffectTracer . SpanStatus ;
128121 public readonly sentrySpan : Span ;
129122 public readonly annotations : Context . Context < never > ;
123+ private readonly _sentryStartTime : number ;
130124
131125 public constructor (
132126 public readonly name : string ,
@@ -136,6 +130,7 @@ class SentrySpanWrapper implements SentrySpanLike {
136130 startTime : bigint ,
137131 public readonly kind : EffectTracer . SpanKind ,
138132 existingSpan : Span ,
133+ sentryStartTime : number ,
139134 ) {
140135 this [ SENTRY_SPAN_SYMBOL ] = true as const ;
141136 this . _tag = 'Span' as const ;
@@ -144,6 +139,7 @@ class SentrySpanWrapper implements SentrySpanLike {
144139 this . links = [ ...links ] ;
145140 this . sentrySpan = existingSpan ;
146141 this . annotations = context ;
142+ this . _sentryStartTime = sentryStartTime ;
147143
148144 const spanContext = this . sentrySpan . spanContext ( ) ;
149145 this . spanId = spanContext . spanId ;
@@ -187,15 +183,31 @@ class SentrySpanWrapper implements SentrySpanLike {
187183 this . sentrySpan . setStatus ( { code : 1 } ) ;
188184 }
189185
190- this . sentrySpan . end ( nanosToHrTime ( endTime ) ) ;
186+ this . sentrySpan . end ( this . _toSentryTime ( endTime ) ) ;
191187 }
192188
193189 public event ( name : string , startTime : bigint , attributes ?: Record < string , unknown > ) : void {
194190 if ( ! this . sentrySpan . isRecording ( ) ) {
195191 return ;
196192 }
197193
198- this . sentrySpan . addEvent ( name , attributes as Parameters < Span [ 'addEvent' ] > [ 1 ] , nanosToHrTime ( startTime ) ) ;
194+ this . sentrySpan . addEvent ( name , attributes as Parameters < Span [ 'addEvent' ] > [ 1 ] , this . _toSentryTime ( startTime ) ) ;
195+ }
196+
197+ /**
198+ * Converts an Effect time to Sentry's clock by adding its offset from the span's start.
199+ *
200+ * Effect's clock doesn't correct for clock drift (e.g. after the device slept), so its absolute times can be off
201+ * from the Sentry spans around this one. Its durations are still correct, and this way we also respect end times
202+ * that were passed explicitly.
203+ */
204+ private _toSentryTime ( effectTime : bigint ) : number | undefined {
205+ // Effect passes 0 if tracer timing is disabled. Sentry then takes the current time.
206+ if ( ! effectTime || ! this . status . startTime ) {
207+ return undefined ;
208+ }
209+
210+ return this . _sentryStartTime + Number ( effectTime - this . status . startTime ) / 1e9 ;
199211 }
200212}
201213
@@ -381,11 +393,14 @@ function createSentrySpan(
381393 const op = deriveOp ( name ) ;
382394 const origin = deriveOrigin ( name ) ;
383395
396+ // Effect calls the tracer when the span starts, so we start it on Sentry's clock and convert later Effect times
397+ // relative to this (see `_toSentryTime`).
398+ const sentryStartTime = timestampInSeconds ( ) ;
384399 const newSpan = startSentrySpan (
385400 startInactiveSpan ,
386401 {
387402 name,
388- startTime : nanosToHrTime ( startTime ) ,
403+ startTime : sentryStartTime ,
389404 // Setting these to `undefined` would strip the core defaults instead of leaving them in place.
390405 attributes : {
391406 ...( op && { [ SENTRY_OP ] : op } ) ,
@@ -397,7 +412,7 @@ function createSentrySpan(
397412 ) ;
398413 markEffectSpan ( newSpan ) ;
399414
400- return new SentrySpanWrapper ( name , parent , context , links , startTime , kind , newSpan ) ;
415+ return new SentrySpanWrapper ( name , parent , context , links , startTime , kind , newSpan , sentryStartTime ) ;
401416}
402417
403418const makeSentryTracerV3 = (
0 commit comments