@@ -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