duron 0.3.0-beta.5 → 0.3.0-beta.7
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.
- package/dist/action.d.ts.map +1 -1
- package/dist/adapters/postgres/schema.d.ts.map +1 -1
- package/dist/adapters/postgres/schema.js +3 -1
- package/dist/client.d.ts +25 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +102 -2
- package/dist/step-manager.d.ts.map +1 -1
- package/dist/step-manager.js +28 -0
- package/dist/telemetry/adapter.d.ts +22 -0
- package/dist/telemetry/adapter.d.ts.map +1 -1
- package/dist/telemetry/adapter.js +6 -0
- package/dist/telemetry/index.d.ts +1 -1
- package/dist/telemetry/index.d.ts.map +1 -1
- package/dist/telemetry/local.d.ts +2 -1
- package/dist/telemetry/local.d.ts.map +1 -1
- package/dist/telemetry/local.js +63 -0
- package/dist/telemetry/noop.d.ts +2 -1
- package/dist/telemetry/noop.d.ts.map +1 -1
- package/dist/telemetry/noop.js +27 -0
- package/dist/telemetry/opentelemetry.d.ts +2 -1
- package/dist/telemetry/opentelemetry.d.ts.map +1 -1
- package/dist/telemetry/opentelemetry.js +110 -0
- package/migrations/postgres/20260119153838_flimsy_thor_girl/snapshot.json +12 -36
- package/package.json +1 -1
- package/src/action.ts +5 -11
- package/src/adapters/postgres/schema.ts +3 -1
- package/src/client.ts +187 -8
- package/src/step-manager.ts +43 -1
- package/src/telemetry/adapter.ts +174 -0
- package/src/telemetry/index.ts +3 -0
- package/src/telemetry/local.ts +93 -0
- package/src/telemetry/noop.ts +46 -0
- package/src/telemetry/opentelemetry.ts +145 -2
package/src/telemetry/adapter.ts
CHANGED
|
@@ -108,6 +108,106 @@ export interface AddSpanAttributeOptions {
|
|
|
108
108
|
value: string | number | boolean
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Options for starting a custom span with the tracer.
|
|
113
|
+
*/
|
|
114
|
+
export interface StartSpanOptions {
|
|
115
|
+
/**
|
|
116
|
+
* Span kind (internal, client, server, producer, consumer).
|
|
117
|
+
* @default 'internal'
|
|
118
|
+
*/
|
|
119
|
+
kind?: 'internal' | 'client' | 'server' | 'producer' | 'consumer'
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Initial attributes for the span.
|
|
123
|
+
*/
|
|
124
|
+
attributes?: Record<string, string | number | boolean>
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Parent span to use for context propagation.
|
|
128
|
+
* If not provided, uses the current active context.
|
|
129
|
+
*/
|
|
130
|
+
parentSpan?: TracerSpan
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* A span created by the Tracer for manual instrumentation.
|
|
135
|
+
*/
|
|
136
|
+
export interface TracerSpan {
|
|
137
|
+
/**
|
|
138
|
+
* Set an attribute on the span.
|
|
139
|
+
*
|
|
140
|
+
* @param key - The attribute key
|
|
141
|
+
* @param value - The attribute value
|
|
142
|
+
*/
|
|
143
|
+
setAttribute(key: string, value: string | number | boolean): void
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Set multiple attributes on the span.
|
|
147
|
+
*
|
|
148
|
+
* @param attributes - The attributes to set
|
|
149
|
+
*/
|
|
150
|
+
setAttributes(attributes: Record<string, string | number | boolean>): void
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Add an event to the span.
|
|
154
|
+
*
|
|
155
|
+
* @param name - The event name
|
|
156
|
+
* @param attributes - Optional event attributes
|
|
157
|
+
*/
|
|
158
|
+
addEvent(name: string, attributes?: Record<string, string | number | boolean>): void
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Record an exception on the span.
|
|
162
|
+
*
|
|
163
|
+
* @param error - The error to record
|
|
164
|
+
*/
|
|
165
|
+
recordException(error: Error): void
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Set the span status to OK.
|
|
169
|
+
*/
|
|
170
|
+
setStatusOk(): void
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Set the span status to error.
|
|
174
|
+
*
|
|
175
|
+
* @param message - Optional error message
|
|
176
|
+
*/
|
|
177
|
+
setStatusError(message?: string): void
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* End the span.
|
|
181
|
+
* After calling this, no more operations can be performed on the span.
|
|
182
|
+
*/
|
|
183
|
+
end(): void
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Check if this span is recording.
|
|
187
|
+
*/
|
|
188
|
+
isRecording(): boolean
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* A Tracer provides methods for creating spans.
|
|
193
|
+
* Similar to OpenTelemetry's Tracer interface.
|
|
194
|
+
*/
|
|
195
|
+
export interface Tracer {
|
|
196
|
+
/**
|
|
197
|
+
* The name of this tracer.
|
|
198
|
+
*/
|
|
199
|
+
readonly name: string
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Start a new span.
|
|
203
|
+
*
|
|
204
|
+
* @param name - The name of the span
|
|
205
|
+
* @param options - Optional span configuration
|
|
206
|
+
* @returns A TracerSpan for manual instrumentation
|
|
207
|
+
*/
|
|
208
|
+
startSpan(name: string, options?: StartSpanOptions): TracerSpan
|
|
209
|
+
}
|
|
210
|
+
|
|
111
211
|
/**
|
|
112
212
|
* Observe context provided to action and step handlers.
|
|
113
213
|
*/
|
|
@@ -136,6 +236,37 @@ export interface ObserveContext {
|
|
|
136
236
|
* @param attributes - Optional event attributes
|
|
137
237
|
*/
|
|
138
238
|
addSpanEvent(name: string, attributes?: Record<string, any>): void
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Get a tracer for manual instrumentation.
|
|
242
|
+
* Similar to OpenTelemetry's `trace.getTracer()` method.
|
|
243
|
+
*
|
|
244
|
+
* @param name - The name of the tracer (typically your service or library name)
|
|
245
|
+
* @returns A Tracer for creating custom spans
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* ```typescript
|
|
249
|
+
* const tracer = ctx.observe.getTracer('my-service')
|
|
250
|
+
*
|
|
251
|
+
* const span = tracer.startSpan('external-api-call', {
|
|
252
|
+
* kind: 'client',
|
|
253
|
+
* attributes: { 'api.endpoint': '/users' }
|
|
254
|
+
* })
|
|
255
|
+
*
|
|
256
|
+
* try {
|
|
257
|
+
* const result = await fetch('https://api.example.com/users')
|
|
258
|
+
* span.setStatusOk()
|
|
259
|
+
* return result
|
|
260
|
+
* } catch (error) {
|
|
261
|
+
* span.recordException(error)
|
|
262
|
+
* span.setStatusError(error.message)
|
|
263
|
+
* throw error
|
|
264
|
+
* } finally {
|
|
265
|
+
* span.end()
|
|
266
|
+
* }
|
|
267
|
+
* ```
|
|
268
|
+
*/
|
|
269
|
+
getTracer(name: string): Tracer
|
|
139
270
|
}
|
|
140
271
|
|
|
141
272
|
// ============================================================================
|
|
@@ -369,6 +500,41 @@ export abstract class TelemetryAdapter {
|
|
|
369
500
|
return this._addSpanAttribute(options)
|
|
370
501
|
}
|
|
371
502
|
|
|
503
|
+
// ============================================================================
|
|
504
|
+
// Tracer Methods
|
|
505
|
+
// ============================================================================
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Get a tracer for manual instrumentation.
|
|
509
|
+
* Similar to OpenTelemetry's `trace.getTracer()` method.
|
|
510
|
+
*
|
|
511
|
+
* @param name - The name of the tracer (typically your service or library name)
|
|
512
|
+
* @returns A Tracer for creating custom spans
|
|
513
|
+
*
|
|
514
|
+
* @example
|
|
515
|
+
* ```typescript
|
|
516
|
+
* const tracer = telemetry.getTracer('my-service')
|
|
517
|
+
*
|
|
518
|
+
* const span = tracer.startSpan('process-order', {
|
|
519
|
+
* attributes: { 'order.id': orderId }
|
|
520
|
+
* })
|
|
521
|
+
*
|
|
522
|
+
* try {
|
|
523
|
+
* // Do some work
|
|
524
|
+
* span.addEvent('order.validated')
|
|
525
|
+
* span.setStatusOk()
|
|
526
|
+
* } catch (error) {
|
|
527
|
+
* span.recordException(error)
|
|
528
|
+
* span.setStatusError(error.message)
|
|
529
|
+
* } finally {
|
|
530
|
+
* span.end()
|
|
531
|
+
* }
|
|
532
|
+
* ```
|
|
533
|
+
*/
|
|
534
|
+
getTracer(name: string): Tracer {
|
|
535
|
+
return this._getTracer(name)
|
|
536
|
+
}
|
|
537
|
+
|
|
372
538
|
// ============================================================================
|
|
373
539
|
// Context Methods
|
|
374
540
|
// ============================================================================
|
|
@@ -404,6 +570,9 @@ export abstract class TelemetryAdapter {
|
|
|
404
570
|
this.#logger?.error(err, 'Error adding span event')
|
|
405
571
|
})
|
|
406
572
|
},
|
|
573
|
+
getTracer: (name: string) => {
|
|
574
|
+
return this.getTracer(name)
|
|
575
|
+
},
|
|
407
576
|
}
|
|
408
577
|
}
|
|
409
578
|
|
|
@@ -465,4 +634,9 @@ export abstract class TelemetryAdapter {
|
|
|
465
634
|
* Internal method to add a span attribute.
|
|
466
635
|
*/
|
|
467
636
|
protected abstract _addSpanAttribute(options: AddSpanAttributeOptions): Promise<void>
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Internal method to get a tracer for manual instrumentation.
|
|
640
|
+
*/
|
|
641
|
+
protected abstract _getTracer(name: string): Tracer
|
|
468
642
|
}
|
package/src/telemetry/index.ts
CHANGED
|
@@ -9,8 +9,11 @@ export {
|
|
|
9
9
|
type Span,
|
|
10
10
|
type StartDatabaseSpanOptions,
|
|
11
11
|
type StartJobSpanOptions,
|
|
12
|
+
type StartSpanOptions,
|
|
12
13
|
type StartStepSpanOptions,
|
|
13
14
|
TelemetryAdapter,
|
|
15
|
+
type Tracer,
|
|
16
|
+
type TracerSpan,
|
|
14
17
|
} from './adapter.js'
|
|
15
18
|
export { LocalTelemetryAdapter, type LocalTelemetryAdapterOptions, localTelemetryAdapter } from './local.js'
|
|
16
19
|
export { NoopTelemetryAdapter, noopTelemetryAdapter } from './noop.js'
|
package/src/telemetry/local.ts
CHANGED
|
@@ -7,8 +7,11 @@ import {
|
|
|
7
7
|
type Span,
|
|
8
8
|
type StartDatabaseSpanOptions,
|
|
9
9
|
type StartJobSpanOptions,
|
|
10
|
+
type StartSpanOptions,
|
|
10
11
|
type StartStepSpanOptions,
|
|
11
12
|
TelemetryAdapter,
|
|
13
|
+
type Tracer,
|
|
14
|
+
type TracerSpan,
|
|
12
15
|
} from './adapter.js'
|
|
13
16
|
|
|
14
17
|
// ============================================================================
|
|
@@ -304,6 +307,96 @@ export class LocalTelemetryAdapter extends TelemetryAdapter {
|
|
|
304
307
|
},
|
|
305
308
|
})
|
|
306
309
|
}
|
|
310
|
+
|
|
311
|
+
// ============================================================================
|
|
312
|
+
// Tracer Methods
|
|
313
|
+
// ============================================================================
|
|
314
|
+
|
|
315
|
+
protected _getTracer(name: string): Tracer {
|
|
316
|
+
const adapter = this
|
|
317
|
+
|
|
318
|
+
return {
|
|
319
|
+
name,
|
|
320
|
+
|
|
321
|
+
startSpan(spanName: string, options?: StartSpanOptions): TracerSpan {
|
|
322
|
+
const spanId = `tracer:${name}:${globalThis.crypto.randomUUID()}`
|
|
323
|
+
const startTime = Date.now()
|
|
324
|
+
let ended = false
|
|
325
|
+
const attributes: Record<string, string | number | boolean> = {
|
|
326
|
+
...options?.attributes,
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Note: Local adapter tracer spans don't have a jobId context,
|
|
330
|
+
// so they can't be stored in the database. They're essentially no-ops
|
|
331
|
+
// but provide a consistent API for code that needs a tracer.
|
|
332
|
+
// For actual metrics storage, use ctx.observe within action/step handlers.
|
|
333
|
+
|
|
334
|
+
const tracerSpan: TracerSpan = {
|
|
335
|
+
setAttribute(key: string, value: string | number | boolean): void {
|
|
336
|
+
if (!ended) {
|
|
337
|
+
attributes[key] = value
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
|
|
341
|
+
setAttributes(attrs: Record<string, string | number | boolean>): void {
|
|
342
|
+
if (!ended) {
|
|
343
|
+
Object.assign(attributes, attrs)
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
|
|
347
|
+
addEvent(eventName: string, eventAttrs?: Record<string, string | number | boolean>): void {
|
|
348
|
+
if (!ended) {
|
|
349
|
+
adapter.logger?.debug({ spanId, event: eventName, attributes: eventAttrs }, 'Tracer span event')
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
|
|
353
|
+
recordException(error: Error): void {
|
|
354
|
+
if (!ended) {
|
|
355
|
+
attributes['error.message'] = error.message
|
|
356
|
+
attributes['error.name'] = error.name
|
|
357
|
+
adapter.logger?.debug({ spanId, error: error.message }, 'Tracer span exception')
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
|
|
361
|
+
setStatusOk(): void {
|
|
362
|
+
if (!ended) {
|
|
363
|
+
// biome-ignore lint/complexity/useLiteralKeys: Index signature requires bracket notation
|
|
364
|
+
attributes['status'] = 'ok'
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
|
|
368
|
+
setStatusError(message?: string): void {
|
|
369
|
+
if (!ended) {
|
|
370
|
+
// biome-ignore lint/complexity/useLiteralKeys: Index signature requires bracket notation
|
|
371
|
+
attributes['status'] = 'error'
|
|
372
|
+
if (message) {
|
|
373
|
+
attributes['status.message'] = message
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
|
|
378
|
+
end(): void {
|
|
379
|
+
if (!ended) {
|
|
380
|
+
ended = true
|
|
381
|
+
const duration = Date.now() - startTime
|
|
382
|
+
adapter.logger?.debug(
|
|
383
|
+
{ spanId, spanName, tracerName: name, durationMs: duration, attributes },
|
|
384
|
+
'Tracer span ended',
|
|
385
|
+
)
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
|
|
389
|
+
isRecording(): boolean {
|
|
390
|
+
return !ended
|
|
391
|
+
},
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
adapter.logger?.debug({ spanId, spanName, tracerName: name }, 'Tracer span started')
|
|
395
|
+
|
|
396
|
+
return tracerSpan
|
|
397
|
+
},
|
|
398
|
+
}
|
|
399
|
+
}
|
|
307
400
|
}
|
|
308
401
|
|
|
309
402
|
/**
|
package/src/telemetry/noop.ts
CHANGED
|
@@ -8,8 +8,41 @@ import {
|
|
|
8
8
|
type StartJobSpanOptions,
|
|
9
9
|
type StartStepSpanOptions,
|
|
10
10
|
TelemetryAdapter,
|
|
11
|
+
type Tracer,
|
|
12
|
+
type TracerSpan,
|
|
11
13
|
} from './adapter.js'
|
|
12
14
|
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Noop Tracer Span
|
|
17
|
+
// ============================================================================
|
|
18
|
+
|
|
19
|
+
const noopTracerSpan: TracerSpan = {
|
|
20
|
+
setAttribute() {
|
|
21
|
+
// No-op
|
|
22
|
+
},
|
|
23
|
+
setAttributes() {
|
|
24
|
+
// No-op
|
|
25
|
+
},
|
|
26
|
+
addEvent() {
|
|
27
|
+
// No-op
|
|
28
|
+
},
|
|
29
|
+
recordException() {
|
|
30
|
+
// No-op
|
|
31
|
+
},
|
|
32
|
+
setStatusOk() {
|
|
33
|
+
// No-op
|
|
34
|
+
},
|
|
35
|
+
setStatusError() {
|
|
36
|
+
// No-op
|
|
37
|
+
},
|
|
38
|
+
end() {
|
|
39
|
+
// No-op
|
|
40
|
+
},
|
|
41
|
+
isRecording() {
|
|
42
|
+
return false
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
|
|
13
46
|
// ============================================================================
|
|
14
47
|
// Noop Telemetry Adapter
|
|
15
48
|
// ============================================================================
|
|
@@ -84,6 +117,19 @@ export class NoopTelemetryAdapter extends TelemetryAdapter {
|
|
|
84
117
|
protected async _addSpanAttribute(_options: AddSpanAttributeOptions): Promise<void> {
|
|
85
118
|
// No-op
|
|
86
119
|
}
|
|
120
|
+
|
|
121
|
+
// ============================================================================
|
|
122
|
+
// Tracer Methods
|
|
123
|
+
// ============================================================================
|
|
124
|
+
|
|
125
|
+
protected _getTracer(name: string): Tracer {
|
|
126
|
+
return {
|
|
127
|
+
name,
|
|
128
|
+
startSpan(): TracerSpan {
|
|
129
|
+
return noopTracerSpan
|
|
130
|
+
},
|
|
131
|
+
}
|
|
132
|
+
}
|
|
87
133
|
}
|
|
88
134
|
|
|
89
135
|
/**
|
|
@@ -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:
|
|
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
|
/**
|