@@ -20,6 +20,7 @@ import {
2020import  { 
2121  BatchSpanProcessor , 
2222  NodeTracerProvider , 
23+   ReadableSpan , 
2324  SimpleSpanProcessor , 
2425  SpanExporter , 
2526}  from  "@opentelemetry/sdk-trace-node" ; 
@@ -85,6 +86,7 @@ export type TracingSDKConfig = {
8586  forceFlushTimeoutMillis ?: number ; 
8687  resource ?: IResource ; 
8788  instrumentations ?: Instrumentation [ ] ; 
89+   exporters ?: SpanExporter [ ] ; 
8890  diagLogLevel ?: TracingDiagnosticLogLevel ; 
8991} ; 
9092
@@ -111,6 +113,8 @@ export class TracingSDK {
111113      . merge ( 
112114        new  Resource ( { 
113115          [ SemanticResourceAttributes . CLOUD_PROVIDER ] : "trigger.dev" , 
116+           [ SemanticResourceAttributes . SERVICE_NAME ] :
117+             getEnvVar ( "OTEL_SERVICE_NAME" )  ??  "trigger.dev" , 
114118          [ SemanticInternalAttributes . TRIGGER ] : true , 
115119          [ SemanticInternalAttributes . CLI_VERSION ] : VERSION , 
116120        } ) 
@@ -153,6 +157,25 @@ export class TracingSDK {
153157      ) 
154158    ) ; 
155159
160+     const  externalTraceId  =  crypto . randomUUID ( ) ; 
161+ 
162+     for  ( const  exporter  of  config . exporters  ??  [ ] )  { 
163+       traceProvider . addSpanProcessor ( 
164+         getEnvVar ( "OTEL_BATCH_PROCESSING_ENABLED" )  ===  "1" 
165+           ? new  BatchSpanProcessor ( new  ExternalSpanExporterWrapper ( exporter ,  externalTraceId ) ,  { 
166+               maxExportBatchSize : parseInt ( getEnvVar ( "OTEL_SPAN_MAX_EXPORT_BATCH_SIZE" )  ??  "64" ) , 
167+               scheduledDelayMillis : parseInt ( 
168+                 getEnvVar ( "OTEL_SPAN_SCHEDULED_DELAY_MILLIS" )  ??  "200" 
169+               ) , 
170+               exportTimeoutMillis : parseInt ( 
171+                 getEnvVar ( "OTEL_SPAN_EXPORT_TIMEOUT_MILLIS" )  ??  "30000" 
172+               ) , 
173+               maxQueueSize : parseInt ( getEnvVar ( "OTEL_SPAN_MAX_QUEUE_SIZE" )  ??  "512" ) , 
174+             } ) 
175+           : new  SimpleSpanProcessor ( new  ExternalSpanExporterWrapper ( exporter ,  externalTraceId ) ) 
176+       ) ; 
177+     } 
178+ 
156179    traceProvider . register ( ) ; 
157180
158181    registerInstrumentations ( { 
@@ -236,3 +259,49 @@ function setLogLevel(level: TracingDiagnosticLogLevel) {
236259
237260  diag . setLogger ( new  DiagConsoleLogger ( ) ,  diagLogLevel ) ; 
238261} 
262+ 
263+ class  ExternalSpanExporterWrapper  { 
264+   constructor ( 
265+     private  underlyingExporter : SpanExporter , 
266+     private  externalTraceId : string 
267+   )  { } 
268+ 
269+   private  transformSpan ( span : ReadableSpan ) : ReadableSpan  |  undefined  { 
270+     if  ( span . attributes [ SemanticInternalAttributes . SPAN_PARTIAL ] )  { 
271+       // Skip partial spans 
272+       return ; 
273+     } 
274+ 
275+     const  spanContext  =  span . spanContext ( ) ; 
276+ 
277+     return  { 
278+       ...span , 
279+       spanContext : ( )  =>  ( {  ...spanContext ,  traceId : this . externalTraceId  } ) , 
280+       parentSpanId : span . attributes [ SemanticInternalAttributes . SPAN_ATTEMPT ] 
281+         ? undefined 
282+         : span . parentSpanId , 
283+     } ; 
284+   } 
285+ 
286+   export ( spans : any [ ] ,  resultCallback : ( result : any )  =>  void ) : void   { 
287+     try  { 
288+       const  modifiedSpans  =  spans . map ( this . transformSpan . bind ( this ) ) ; 
289+       this . underlyingExporter . export ( 
290+         modifiedSpans . filter ( Boolean )  as  ReadableSpan [ ] , 
291+         resultCallback 
292+       ) ; 
293+     }  catch  ( e )  { 
294+       console . error ( e ) ; 
295+     } 
296+   } 
297+ 
298+   shutdown ( ) : Promise < void >  { 
299+     return  this . underlyingExporter . shutdown ( ) ; 
300+   } 
301+ 
302+   forceFlush ?( ) : Promise < void >  { 
303+     return  this . underlyingExporter . forceFlush 
304+       ? this . underlyingExporter . forceFlush ( ) 
305+       : Promise . resolve ( ) ; 
306+   } 
307+ } 
0 commit comments