1
1
import type { Attributes , Context , TextMapGetter } from '@opentelemetry/api'
2
- import { diag , SpanKind } from '@opentelemetry/api'
2
+ import { diag , SpanKind , TraceFlags } from '@opentelemetry/api'
3
3
import type {
4
4
ReadableSpan ,
5
5
Span ,
6
6
SpanProcessor ,
7
7
} from '@opentelemetry/sdk-trace-base'
8
-
9
- import { TraceFlags } from '@opentelemetry/api'
8
+ import { after } from 'next/server'
10
9
11
10
type AttributesFromHeaderFunc = < Carrier = unknown > (
12
11
headers : Carrier ,
@@ -15,41 +14,6 @@ type AttributesFromHeaderFunc = <Carrier = unknown>(
15
14
16
15
type AttributesFromHeaders = Record < string , string > | AttributesFromHeaderFunc
17
16
18
- /**
19
- * Helper ────────────────────────────────────────────────────────────────────
20
- * Try to obtain the callback that extends the lifetime of the request so that
21
- * our exporter has time to flush.
22
- *
23
- * Priority:
24
- * 1. `after(cb)` (Next.js 15)
25
- * 2. fallback (best-effort `setTimeout`)
26
- */
27
- function scheduleAfterResponse ( task : ( ) => Promise < void > ) {
28
- try {
29
- // avoid a hard dependency so this file can be imported outside a route.
30
- // `require` is evaluated lazily – if Next isn't around it will throw.
31
- // eslint-disable-next-line
32
- const mod = require ( 'next/server' ) as { after ?: ( cb : ( ) => void ) => void }
33
-
34
- if ( typeof mod . after === 'function' ) {
35
- mod . after ( ( ) => {
36
- // no await – Next treats sync or async the same,
37
- // we just fire the promise and let it resolve.
38
- void task ( )
39
- } )
40
- return
41
- }
42
- } catch {
43
- /* ignored – we're probably not inside a Next context */
44
- }
45
-
46
- // 2. Node / local fallback – try our best and hope the
47
- // process stays alive long enough.
48
- setTimeout ( ( ) => {
49
- void task ( )
50
- } , 0 )
51
- }
52
-
53
17
function isSampled ( traceFlags : number ) : boolean {
54
18
// Use bitwise AND to inspect the sampled flag
55
19
return ( traceFlags & TraceFlags . SAMPLED ) !== 0
@@ -113,7 +77,7 @@ export class NextCompositeSpanProcessor implements SpanProcessor {
113
77
// Attach request-specific attributes only on the root span
114
78
if ( isRoot && isSampled ( traceFlags ) ) {
115
79
// When the *response* (or prerender) is done, flush traces.
116
- scheduleAfterResponse ( async ( ) => {
80
+ after ( async ( ) => {
117
81
if ( this . rootSpanIds . has ( traceId ) ) {
118
82
// Root hasn’t finished yet – wait via onEnd().
119
83
const waiter = new Promise < void > ( ( resolve ) =>
0 commit comments