abxbus 2.4.23 → 2.4.26

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.
@@ -8,11 +8,12 @@ import {
8
8
  type SpanAttributeValue,
9
9
  type SpanAttributes,
10
10
  type SpanContext,
11
+ type TimeInput,
11
12
  type Tracer,
12
13
  } from '@opentelemetry/api'
13
14
  import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
14
15
  import { resourceFromAttributes } from '@opentelemetry/resources'
15
- import { BasicTracerProvider, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
16
+ import { BasicTracerProvider, BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'
16
17
  import type { SpanLimits, SpanProcessor } from '@opentelemetry/sdk-trace-base'
17
18
  import { SpanImpl } from '@opentelemetry/sdk-trace-base/build/src/Span.js'
18
19
 
@@ -29,7 +30,7 @@ export type OtelTracingSpanFactoryInput = {
29
30
  span_context: SpanContext
30
31
  parent_span_context?: SpanContext
31
32
  attributes: SpanAttributes
32
- start_time?: Date
33
+ start_time?: TimeInput
33
34
  }
34
35
 
35
36
  export type OtelTracingSpanFactory = (input: OtelTracingSpanFactoryInput) => Span
@@ -53,7 +54,6 @@ export type OtelTracingMiddlewareOptions = {
53
54
  otlp_endpoint?: string
54
55
  service_name?: string
55
56
  instrumentation_name?: string
56
- root_span_name?: string | ((eventbus: EventBus, event: BaseEvent) => string)
57
57
  root_span_attributes?: SpanAttributes | ((eventbus: EventBus, event: BaseEvent) => SpanAttributes)
58
58
  }
59
59
 
@@ -62,10 +62,7 @@ export class OtelTracingMiddleware implements EventBusMiddleware {
62
62
  private readonly trace_api: OpenTelemetryTraceApi
63
63
  private readonly span_factory?: OtelTracingSpanFactory
64
64
  private readonly span_provider?: OtelTracingSpanProvider
65
- private readonly root_span_name: OtelTracingMiddlewareOptions['root_span_name']
66
65
  private readonly root_span_attributes: OtelTracingMiddlewareOptions['root_span_attributes']
67
- private readonly root_spans = new Map<string, Span>()
68
- private readonly root_contexts = new Map<string, Context>()
69
66
  private readonly event_spans = new Map<string, Span>()
70
67
  private readonly event_contexts = new Map<string, Context>()
71
68
  private readonly handler_spans = new Map<string, Span>()
@@ -80,7 +77,6 @@ export class OtelTracingMiddleware implements EventBusMiddleware {
80
77
  (this.span_provider
81
78
  ? createProviderSpanFactory(this.trace_api, this.span_provider, options.instrumentation_name ?? 'abxbus')
82
79
  : undefined)
83
- this.root_span_name = options.root_span_name
84
80
  this.root_span_attributes = options.root_span_attributes
85
81
  }
86
82
 
@@ -118,22 +114,14 @@ export class OtelTracingMiddleware implements EventBusMiddleware {
118
114
  return existing
119
115
  }
120
116
 
121
- const parent_context = this.parentContextForEvent(event) ?? this.startRootSpan(eventbus, event)
122
- const start_time = dateFromIso(event.event_started_at)
117
+ const parent_context = this.parentContextForEvent(event) ?? ROOT_CONTEXT
118
+ const start_time = timeInputFromIso(event.event_started_at)
123
119
  const span = this.tracer.startSpan(
124
120
  eventSpanName(eventbus, event),
125
121
  {
126
- attributes: compactAttributes({
127
- 'abxbus.bus.id': eventbus.id,
128
- 'abxbus.bus.name': eventbus.name,
129
- 'abxbus.event.id': event.event_id,
130
- 'abxbus.event.type': event.event_type,
131
- 'abxbus.event.version': event.event_version,
132
- 'abxbus.event.session_id': stringValue((event as { session_id?: unknown }).session_id),
133
- 'abxbus.event.parent_id': event.event_parent_id,
134
- 'abxbus.event.emitted_by_handler_id': event.event_emitted_by_handler_id,
135
- 'abxbus.event.path': event.event_path.join(' '),
136
- }),
122
+ attributes: event.event_parent_id
123
+ ? eventStartedSpanAttributes(eventbus, event)
124
+ : topLevelEventStartedSpanAttributes(this.root_span_attributes, eventbus, event),
137
125
  startTime: start_time,
138
126
  },
139
127
  parent_context
@@ -157,19 +145,13 @@ export class OtelTracingMiddleware implements EventBusMiddleware {
157
145
  span.setStatus({ code: SpanStatusCode.OK })
158
146
  }
159
147
  span.setAttributes(
160
- compactAttributes({
161
- 'abxbus.event.status': event.event_status,
162
- 'abxbus.event.result_count': event.event_results.size,
163
- 'abxbus.event.error_count': event.event_errors.length,
164
- 'abxbus.event.child_count': event.event_children.length,
165
- })
148
+ event.event_parent_id ? eventSpanAttributes(eventbus, event) : topLevelEventSpanAttributes(this.root_span_attributes, eventbus, event)
166
149
  )
167
- const start_time = dateFromIso(event.event_started_at)
168
- const end_time = endTimeAfterStart(start_time, dateFromIso(event.event_completed_at))
150
+ const start_time = epochNsFromIso(event.event_started_at)
151
+ const end_time = endTimeAfterStart(start_time, epochNsFromIso(event.event_completed_at))
169
152
  span.end(end_time)
170
153
  this.event_spans.delete(event.event_id)
171
154
  this.event_contexts.delete(event.event_id)
172
- this.completeRootSpan(event.event_id, start_time, end_time)
173
155
  }
174
156
 
175
157
  private startHandlerSpan(eventbus: EventBus, event: BaseEvent, event_result: EventResult): Span {
@@ -183,18 +165,8 @@ export class OtelTracingMiddleware implements EventBusMiddleware {
183
165
  const span = this.tracer.startSpan(
184
166
  handlerSpanName(event, event_result),
185
167
  {
186
- attributes: compactAttributes({
187
- 'abxbus.bus.id': eventbus.id,
188
- 'abxbus.bus.name': eventbus.name,
189
- 'abxbus.event.id': event.event_id,
190
- 'abxbus.event.type': event.event_type,
191
- 'abxbus.handler.id': event_result.handler_id,
192
- 'abxbus.handler.name': event_result.handler_name,
193
- 'abxbus.handler.file_path': event_result.handler_file_path,
194
- 'abxbus.handler.event_pattern': event_result.handler.event_pattern,
195
- 'abxbus.event_result.id': event_result.id,
196
- }),
197
- startTime: dateFromIso(event_result.started_at),
168
+ attributes: handlerSpanAttributes(eventbus, event, event_result),
169
+ startTime: timeInputFromIso(event_result.started_at),
198
170
  },
199
171
  parent_context
200
172
  )
@@ -206,7 +178,6 @@ export class OtelTracingMiddleware implements EventBusMiddleware {
206
178
 
207
179
  private completeHandlerSpan(eventbus: EventBus, event: BaseEvent, event_result: EventResult): void {
208
180
  if (this.span_factory) {
209
- this.completeHandlerSpanWithFactory(eventbus, event, event_result)
210
181
  return
211
182
  }
212
183
 
@@ -220,59 +191,12 @@ export class OtelTracingMiddleware implements EventBusMiddleware {
220
191
  } else {
221
192
  span.setStatus({ code: SpanStatusCode.OK })
222
193
  }
223
- span.setAttributes(
224
- compactAttributes({
225
- 'abxbus.event_result.status': event_result.status,
226
- 'abxbus.handler.child_count': event_result.event_children.length,
227
- })
228
- )
229
- span.end(endTimeAfterStart(dateFromIso(event_result.started_at), dateFromIso(event_result.completed_at)))
194
+ span.setAttributes(handlerSpanAttributes(eventbus, event, event_result))
195
+ span.end(endTimeAfterStart(epochNsFromIso(event_result.started_at), epochNsFromIso(event_result.completed_at)))
230
196
  this.handler_spans.delete(event_result.id)
231
197
  this.handler_contexts.delete(handlerSpanKey(event_result.event_id, event_result.handler_id))
232
198
  }
233
199
 
234
- private startRootSpan(eventbus: EventBus, event: BaseEvent): Context {
235
- const existing = this.root_contexts.get(event.event_id)
236
- if (existing) {
237
- return existing
238
- }
239
-
240
- const session_id = stringValue((event as { session_id?: unknown }).session_id)
241
- const root_attributes = resolveAttributes(this.root_span_attributes, eventbus, event)
242
- const root_span = this.tracer.startSpan(
243
- resolveRootSpanName(this.root_span_name, eventbus, event),
244
- {
245
- attributes: compactAttributes({
246
- ...root_attributes,
247
- 'abxbus.trace.root': true,
248
- 'abxbus.bus.id': eventbus.id,
249
- 'abxbus.bus.name': eventbus.name,
250
- 'abxbus.root_event.id': event.event_id,
251
- 'abxbus.root_event.type': event.event_type,
252
- 'abxbus.root_event.session_id': session_id,
253
- }),
254
- startTime: dateFromIso(event.event_started_at),
255
- },
256
- ROOT_CONTEXT
257
- )
258
- const root_context = this.trace_api.setSpan(ROOT_CONTEXT, root_span)
259
- this.root_spans.set(event.event_id, root_span)
260
- this.root_contexts.set(event.event_id, root_context)
261
- return root_context
262
- }
263
-
264
- private completeRootSpan(event_id: string, start_time: Date | undefined, end_time: Date | undefined): void {
265
- const root_span = this.root_spans.get(event_id)
266
- if (!root_span) {
267
- return
268
- }
269
-
270
- root_span.setStatus({ code: SpanStatusCode.OK })
271
- root_span.end(endTimeAfterStart(start_time, end_time))
272
- this.root_spans.delete(event_id)
273
- this.root_contexts.delete(event_id)
274
- }
275
-
276
200
  private parentContextForEvent(event: BaseEvent): Context | undefined {
277
201
  if (event.event_parent_id && event.event_emitted_by_handler_id) {
278
202
  const handler_context = this.handler_contexts.get(handlerSpanKey(event.event_parent_id, event.event_emitted_by_handler_id))
@@ -285,56 +209,77 @@ export class OtelTracingMiddleware implements EventBusMiddleware {
285
209
  }
286
210
 
287
211
  private completeEventSpanWithFactory(eventbus: EventBus, event: BaseEvent): void {
288
- const root_event = rootEventForEvent(eventbus, event)
289
- const trace_id = traceIdForRootEvent(root_event.event_id)
290
- const event_context = eventSpanContext(trace_id, event.event_id)
291
- const start_time = dateFromIso(event.event_started_at)
292
- const end_time = endTimeAfterStart(start_time, dateFromIso(event.event_completed_at))
293
-
294
- if (!event.event_parent_id) {
295
- const root_span = this.span_factory!({
296
- name: resolveRootSpanName(this.root_span_name, eventbus, event),
297
- span_context: rootSpanContext(trace_id, event.event_id),
298
- attributes: rootSpanAttributes(this.root_span_attributes, eventbus, event),
299
- start_time,
300
- })
301
- root_span.setStatus({ code: SpanStatusCode.OK })
302
- root_span.end(end_time)
212
+ if (event.event_parent_id) {
213
+ return
303
214
  }
304
215
 
216
+ const top_level_event = event._event_original ?? event
217
+ const trace_id = traceIdForRootEvent(top_level_event.event_id)
218
+ this.exportEventTreeWithFactory(eventbus, top_level_event, trace_id, undefined, new Set<string>())
219
+ }
220
+
221
+ private exportEventTreeWithFactory(
222
+ eventbus: EventBus,
223
+ event: BaseEvent,
224
+ trace_id: string,
225
+ parent_span_context: SpanContext | undefined,
226
+ visited_event_ids: Set<string>
227
+ ): void {
228
+ const original_event = event._event_original ?? event
229
+ if (visited_event_ids.has(original_event.event_id)) {
230
+ return
231
+ }
232
+ visited_event_ids.add(original_event.event_id)
233
+
234
+ const start_time = epochNsFromIso(original_event.event_started_at)
235
+ const span_context = eventSpanContext(trace_id, original_event.event_id)
305
236
  const span = this.span_factory!({
306
- name: eventSpanName(eventbus, event),
307
- span_context: event_context,
308
- parent_span_context: parentSpanContextForEvent(event, trace_id),
309
- attributes: eventSpanAttributes(eventbus, event),
310
- start_time,
237
+ name: eventSpanName(eventbus, original_event),
238
+ span_context,
239
+ parent_span_context,
240
+ attributes: original_event.event_parent_id
241
+ ? eventSpanAttributes(eventbus, original_event)
242
+ : topLevelEventSpanAttributes(this.root_span_attributes, eventbus, original_event),
243
+ start_time: timeInputFromEpochNs(start_time),
311
244
  })
312
- if (event.event_errors.length > 0) {
313
- recordSpanError(span, event.event_errors[0])
245
+ if (original_event.event_errors.length > 0) {
246
+ recordSpanError(span, original_event.event_errors[0])
314
247
  } else {
315
248
  span.setStatus({ code: SpanStatusCode.OK })
316
249
  }
317
- span.end(end_time)
250
+ span.end(endTimeAfterStart(start_time, epochNsFromIso(original_event.event_completed_at)))
251
+
252
+ for (const event_result of original_event.event_results.values()) {
253
+ const handler_context = this.exportHandlerSpanWithFactory(eventbus, original_event, event_result, trace_id, span_context)
254
+ for (const child of event_result.event_children) {
255
+ this.exportEventTreeWithFactory(eventbus, child, trace_id, handler_context, visited_event_ids)
256
+ }
257
+ }
318
258
  }
319
259
 
320
- private completeHandlerSpanWithFactory(eventbus: EventBus, event: BaseEvent, event_result: EventResult): void {
321
- const root_event = rootEventForEvent(eventbus, event)
322
- const trace_id = traceIdForRootEvent(root_event.event_id)
323
- const start_time = dateFromIso(event_result.started_at)
260
+ private exportHandlerSpanWithFactory(
261
+ eventbus: EventBus,
262
+ event: BaseEvent,
263
+ event_result: EventResult,
264
+ trace_id: string,
265
+ parent_span_context: SpanContext
266
+ ): SpanContext {
267
+ const start_time = epochNsFromIso(event_result.started_at)
268
+ const span_context = handlerSpanContext(trace_id, event_result.event_id, event_result.handler_id)
324
269
  const span = this.span_factory!({
325
270
  name: handlerSpanName(event, event_result),
326
- span_context: handlerSpanContext(trace_id, event_result.event_id, event_result.handler_id),
327
- parent_span_context: eventSpanContext(trace_id, event.event_id),
271
+ span_context,
272
+ parent_span_context,
328
273
  attributes: handlerSpanAttributes(eventbus, event, event_result),
329
- start_time,
274
+ start_time: timeInputFromEpochNs(start_time),
330
275
  })
331
-
332
276
  if (event_result.error !== undefined) {
333
277
  recordSpanError(span, event_result.error)
334
278
  } else {
335
279
  span.setStatus({ code: SpanStatusCode.OK })
336
280
  }
337
- span.end(endTimeAfterStart(start_time, dateFromIso(event_result.completed_at)))
281
+ span.end(endTimeAfterStart(start_time, epochNsFromIso(event_result.completed_at)))
282
+ return span_context
338
283
  }
339
284
  }
340
285
 
@@ -356,10 +301,13 @@ function createOtlpSpanProvider(options: OtelTracingMiddlewareOptions): OtelTrac
356
301
  'service.name': options.service_name ?? 'abxbus',
357
302
  }),
358
303
  spanProcessors: [
359
- new SimpleSpanProcessor(
304
+ new BatchSpanProcessor(
360
305
  new OTLPTraceExporter({
361
306
  url: normalizeOtlpTracesEndpoint(options.otlp_endpoint!),
362
- })
307
+ }),
308
+ {
309
+ scheduledDelayMillis: 100,
310
+ }
363
311
  ),
364
312
  ],
365
313
  })
@@ -403,92 +351,64 @@ function normalizeOtlpTracesEndpoint(endpoint: string): string {
403
351
  return trimmed.endsWith('/v1/traces') ? trimmed : `${trimmed}/v1/traces`
404
352
  }
405
353
 
354
+ function eventStartedSpanAttributes(eventbus: EventBus, event: BaseEvent): SpanAttributes {
355
+ return compactAttributes({
356
+ 'abxbus.event_bus.id': eventbus.id,
357
+ 'abxbus.event_bus.name': eventbus.name,
358
+ 'abxbus.event_id': event.event_id,
359
+ 'abxbus.event_type': event.event_type,
360
+ 'abxbus.event_version': event.event_version,
361
+ 'abxbus.session_id': stringValue((event as { session_id?: unknown }).session_id),
362
+ 'abxbus.event_parent_id': event.event_parent_id,
363
+ 'abxbus.event_emitted_by_handler_id': event.event_emitted_by_handler_id,
364
+ 'abxbus.event_path': event.event_path.join(' '),
365
+ })
366
+ }
367
+
406
368
  function eventSpanAttributes(eventbus: EventBus, event: BaseEvent): SpanAttributes {
407
369
  return compactAttributes({
408
- 'abxbus.bus.id': eventbus.id,
409
- 'abxbus.bus.name': eventbus.name,
410
- 'abxbus.event.id': event.event_id,
411
- 'abxbus.event.type': event.event_type,
412
- 'abxbus.event.version': event.event_version,
413
- 'abxbus.event.session_id': stringValue((event as { session_id?: unknown }).session_id),
414
- 'abxbus.event.parent_id': event.event_parent_id,
415
- 'abxbus.event.emitted_by_handler_id': event.event_emitted_by_handler_id,
416
- 'abxbus.event.path': event.event_path.join(' '),
417
- 'abxbus.event.status': event.event_status,
418
- 'abxbus.event.result_count': event.event_results.size,
419
- 'abxbus.event.error_count': event.event_errors.length,
420
- 'abxbus.event.child_count': event.event_children.length,
370
+ ...eventStartedSpanAttributes(eventbus, event),
371
+ 'abxbus.event_status': event.event_status,
421
372
  })
422
373
  }
423
374
 
424
375
  function handlerSpanAttributes(eventbus: EventBus, event: BaseEvent, event_result: EventResult): SpanAttributes {
425
376
  return compactAttributes({
426
- 'abxbus.bus.id': eventbus.id,
427
- 'abxbus.bus.name': eventbus.name,
428
- 'abxbus.event.id': event.event_id,
429
- 'abxbus.event.type': event.event_type,
430
- 'abxbus.handler.id': event_result.handler_id,
431
- 'abxbus.handler.name': event_result.handler_name,
432
- 'abxbus.handler.file_path': event_result.handler_file_path,
433
- 'abxbus.handler.event_pattern': event_result.handler.event_pattern,
434
- 'abxbus.event_result.id': event_result.id,
435
- 'abxbus.event_result.status': event_result.status,
436
- 'abxbus.handler.child_count': event_result.event_children.length,
377
+ 'abxbus.event_bus.id': eventbus.id,
378
+ 'abxbus.event_bus.name': eventbus.name,
379
+ 'abxbus.event_id': event.event_id,
380
+ 'abxbus.event_type': event.event_type,
381
+ 'abxbus.handler_id': event_result.handler_id,
382
+ 'abxbus.handler_name': event_result.handler_name,
383
+ 'abxbus.handler_file_path': event_result.handler_file_path,
384
+ 'abxbus.handler_event_pattern': event_result.handler.event_pattern,
385
+ 'abxbus.event_result_id': event_result.id,
386
+ 'abxbus.event_result_status': event_result.status,
437
387
  })
438
388
  }
439
389
 
440
- function rootSpanAttributes(
390
+ function topLevelEventStartedSpanAttributes(
441
391
  root_span_attributes: OtelTracingMiddlewareOptions['root_span_attributes'],
442
392
  eventbus: EventBus,
443
393
  event: BaseEvent
444
394
  ): SpanAttributes {
445
- const session_id = stringValue((event as { session_id?: unknown }).session_id)
446
395
  return compactAttributes({
396
+ ...eventStartedSpanAttributes(eventbus, event),
447
397
  ...resolveAttributes(root_span_attributes, eventbus, event),
448
398
  'abxbus.trace.root': true,
449
- 'abxbus.bus.id': eventbus.id,
450
- 'abxbus.bus.name': eventbus.name,
451
- 'abxbus.root_event.id': event.event_id,
452
- 'abxbus.root_event.type': event.event_type,
453
- 'abxbus.root_event.session_id': session_id,
454
- 'abxbus.root_event.status': event.event_status,
455
- 'abxbus.root_event.error_count': event.event_errors.length,
456
- 'abxbus.root_event.child_count': event.event_children.length,
457
399
  })
458
400
  }
459
401
 
460
- function rootEventForEvent(eventbus: EventBus, event: BaseEvent): BaseEvent {
461
- let current = event._event_original ?? event
462
- const seen = new Set<string>()
463
- while (current.event_parent_id && !seen.has(current.event_id)) {
464
- seen.add(current.event_id)
465
- const parent = eventbus.findEventById(current.event_parent_id)
466
- if (!parent) {
467
- break
468
- }
469
- current = parent._event_original ?? parent
470
- }
471
- return current
472
- }
473
-
474
- function parentSpanContextForEvent(event: BaseEvent, trace_id: string): SpanContext {
475
- if (!event.event_parent_id) {
476
- return rootSpanContext(trace_id, event.event_id)
477
- }
478
-
479
- if (event.event_emitted_by_handler_id) {
480
- return handlerSpanContext(trace_id, event.event_parent_id, event.event_emitted_by_handler_id)
481
- }
482
-
483
- return eventSpanContext(trace_id, event.event_parent_id)
484
- }
485
-
486
- function rootSpanContext(trace_id: string, event_id: string): SpanContext {
487
- return {
488
- traceId: trace_id,
489
- spanId: deterministicSpanId(`abxbus.root:${event_id}`),
490
- traceFlags: 1,
491
- }
402
+ function topLevelEventSpanAttributes(
403
+ root_span_attributes: OtelTracingMiddlewareOptions['root_span_attributes'],
404
+ eventbus: EventBus,
405
+ event: BaseEvent
406
+ ): SpanAttributes {
407
+ return compactAttributes({
408
+ ...eventSpanAttributes(eventbus, event),
409
+ ...resolveAttributes(root_span_attributes, eventbus, event),
410
+ 'abxbus.trace.root': true,
411
+ })
492
412
  }
493
413
 
494
414
  function eventSpanContext(trace_id: string, event_id: string): SpanContext {
@@ -529,27 +449,45 @@ function fnv1a64Hex(input: string): string {
529
449
  return hash.toString(16).padStart(16, '0')
530
450
  }
531
451
 
532
- function dateFromIso(value: string | null | undefined): Date | undefined {
452
+ const ISO_EPOCH_NS_REGEX = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(?:\.(\d{1,9}))?(Z|[+-]\d{2}:\d{2})$/
453
+ const NS_PER_SECOND = 1_000_000_000n
454
+ const NS_PER_MS = 1_000_000n
455
+
456
+ function epochNsFromIso(value: string | null | undefined): bigint | undefined {
533
457
  if (value == null) {
534
458
  return undefined
535
459
  }
536
- const date = new Date(value)
537
- return Number.isNaN(date.getTime()) ? undefined : date
460
+ const match = ISO_EPOCH_NS_REGEX.exec(value)
461
+ if (!match) {
462
+ return undefined
463
+ }
464
+ const [, base, fraction = '', timezone] = match
465
+ const base_ms = Date.parse(`${base}.000${timezone}`)
466
+ if (Number.isNaN(base_ms)) {
467
+ return undefined
468
+ }
469
+ return BigInt(base_ms) * NS_PER_MS + BigInt(fraction.padEnd(9, '0'))
538
470
  }
539
471
 
540
- function endTimeAfterStart(start_time: Date | undefined, end_time: Date | undefined): Date | undefined {
541
- if (!start_time || !end_time) {
542
- return end_time
543
- }
472
+ function timeInputFromIso(value: string | null | undefined): TimeInput | undefined {
473
+ return timeInputFromEpochNs(epochNsFromIso(value))
474
+ }
544
475
 
545
- return end_time.getTime() > start_time.getTime() ? end_time : new Date(start_time.getTime() + 1)
476
+ function timeInputFromEpochNs(epoch_ns: bigint | undefined): TimeInput | undefined {
477
+ if (epoch_ns === undefined) {
478
+ return undefined
479
+ }
480
+ const seconds = epoch_ns / NS_PER_SECOND
481
+ const nanos = epoch_ns % NS_PER_SECOND
482
+ return [Number(seconds), Number(nanos)]
546
483
  }
547
484
 
548
- function resolveRootSpanName(root_span_name: OtelTracingMiddlewareOptions['root_span_name'], eventbus: EventBus, event: BaseEvent): string {
549
- if (typeof root_span_name === 'function') {
550
- return root_span_name(eventbus, event)
485
+ function endTimeAfterStart(start_time: bigint | undefined, end_time: bigint | undefined): TimeInput | undefined {
486
+ if (start_time === undefined || end_time === undefined) {
487
+ return timeInputFromEpochNs(end_time)
551
488
  }
552
- return root_span_name ?? `abxbus.trace ${eventbus.name}`
489
+
490
+ return timeInputFromEpochNs(end_time > start_time ? end_time : start_time + 1n)
553
491
  }
554
492
 
555
493
  function resolveAttributes(