duron 0.3.0-beta.6 → 0.3.0-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import type { Span as OTelSpan, Tracer, TracerProvider } from '@opentelemetry/api'
1
+ import type { Span as OTelSpan, Tracer as OTelTracer, TracerProvider } from '@opentelemetry/api'
2
2
 
3
3
  import {
4
4
  type AddSpanAttributeOptions,
@@ -8,8 +8,11 @@ import {
8
8
  type Span,
9
9
  type StartDatabaseSpanOptions,
10
10
  type StartJobSpanOptions,
11
+ type StartSpanOptions,
11
12
  type StartStepSpanOptions,
12
13
  TelemetryAdapter,
14
+ type Tracer,
15
+ type TracerSpan,
13
16
  } from './adapter.js'
14
17
 
15
18
  // ============================================================================
@@ -52,8 +55,9 @@ export class OpenTelemetryAdapter extends TelemetryAdapter {
52
55
  #serviceName: string
53
56
  #tracerProvider: TracerProvider | null
54
57
  #traceDatabaseQueries: boolean
55
- #tracer: Tracer | null = null
58
+ #tracer: OTelTracer | null = null
56
59
  #spanMap = new Map<string, OTelSpan>()
60
+ #tracerCache = new Map<string, Tracer>()
57
61
 
58
62
  constructor(options: OpenTelemetryAdapterOptions = {}) {
59
63
  super()
@@ -298,6 +302,145 @@ export class OpenTelemetryAdapter extends TelemetryAdapter {
298
302
  extSpan.otelSpan.setAttribute(options.key, options.value)
299
303
  }
300
304
  }
305
+
306
+ // ============================================================================
307
+ // Tracer Methods
308
+ // ============================================================================
309
+
310
+ protected _getTracer(name: string): Tracer {
311
+ // Return cached tracer if available
312
+ const cached = this.#tracerCache.get(name)
313
+ if (cached) {
314
+ return cached
315
+ }
316
+
317
+ const adapter = this
318
+
319
+ const tracer: Tracer = {
320
+ name,
321
+
322
+ startSpan(spanName: string, options?: StartSpanOptions): TracerSpan {
323
+ // We need to dynamically get the OpenTelemetry API
324
+ // Since _getTracer is synchronous, we need to handle this carefully
325
+ let otelSpan: OTelSpan | null = null
326
+ let api: typeof import('@opentelemetry/api') | null = null
327
+ let ended = false
328
+
329
+ // Initialize the span asynchronously but return synchronously
330
+ const initPromise = (async () => {
331
+ api = await import('@opentelemetry/api')
332
+
333
+ // Get the tracer
334
+ let otelTracer: OTelTracer
335
+ if (adapter.#tracerProvider) {
336
+ otelTracer = adapter.#tracerProvider.getTracer(name)
337
+ } else {
338
+ otelTracer = api.trace.getTracer(name)
339
+ }
340
+
341
+ // Map kind
342
+ let spanKind = api.SpanKind.INTERNAL
343
+ if (options?.kind === 'client') spanKind = api.SpanKind.CLIENT
344
+ else if (options?.kind === 'server') spanKind = api.SpanKind.SERVER
345
+ else if (options?.kind === 'producer') spanKind = api.SpanKind.PRODUCER
346
+ else if (options?.kind === 'consumer') spanKind = api.SpanKind.CONSUMER
347
+
348
+ // Get parent context
349
+ let parentContext = api.context.active()
350
+ if (options?.parentSpan) {
351
+ const parentOtelSpan = (options.parentSpan as any)._otelSpan as OTelSpan | undefined
352
+ if (parentOtelSpan) {
353
+ parentContext = api.trace.setSpan(api.context.active(), parentOtelSpan)
354
+ }
355
+ }
356
+
357
+ otelSpan = otelTracer.startSpan(
358
+ spanName,
359
+ {
360
+ kind: spanKind,
361
+ attributes: options?.attributes,
362
+ },
363
+ parentContext,
364
+ )
365
+ })()
366
+
367
+ const tracerSpan: TracerSpan & { _otelSpan?: OTelSpan } = {
368
+ setAttribute(key: string, value: string | number | boolean): void {
369
+ initPromise.then(() => {
370
+ if (otelSpan && !ended) {
371
+ otelSpan.setAttribute(key, value)
372
+ }
373
+ })
374
+ },
375
+
376
+ setAttributes(attributes: Record<string, string | number | boolean>): void {
377
+ initPromise.then(() => {
378
+ if (otelSpan && !ended) {
379
+ otelSpan.setAttributes(attributes)
380
+ }
381
+ })
382
+ },
383
+
384
+ addEvent(eventName: string, attributes?: Record<string, string | number | boolean>): void {
385
+ initPromise.then(() => {
386
+ if (otelSpan && !ended) {
387
+ otelSpan.addEvent(eventName, attributes)
388
+ }
389
+ })
390
+ },
391
+
392
+ recordException(error: Error): void {
393
+ initPromise.then(() => {
394
+ if (otelSpan && !ended) {
395
+ otelSpan.recordException(error)
396
+ }
397
+ })
398
+ },
399
+
400
+ setStatusOk(): void {
401
+ initPromise.then(() => {
402
+ if (otelSpan && api && !ended) {
403
+ otelSpan.setStatus({ code: api.SpanStatusCode.OK })
404
+ }
405
+ })
406
+ },
407
+
408
+ setStatusError(message?: string): void {
409
+ initPromise.then(() => {
410
+ if (otelSpan && api && !ended) {
411
+ otelSpan.setStatus({ code: api.SpanStatusCode.ERROR, message })
412
+ }
413
+ })
414
+ },
415
+
416
+ end(): void {
417
+ initPromise.then(() => {
418
+ if (otelSpan && !ended) {
419
+ ended = true
420
+ otelSpan.end()
421
+ }
422
+ })
423
+ },
424
+
425
+ isRecording(): boolean {
426
+ return otelSpan?.isRecording() ?? false
427
+ },
428
+ }
429
+
430
+ // Store reference for parent context propagation
431
+ initPromise.then(() => {
432
+ if (otelSpan) {
433
+ ;(tracerSpan as any)._otelSpan = otelSpan
434
+ }
435
+ })
436
+
437
+ return tracerSpan
438
+ },
439
+ }
440
+
441
+ this.#tracerCache.set(name, tracer)
442
+ return tracer
443
+ }
301
444
  }
302
445
 
303
446
  /**