@mastra/observability 1.0.0-beta.6 → 1.0.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.
package/dist/index.js CHANGED
@@ -4487,24 +4487,31 @@ var ConsoleExporter = class extends BaseExporter {
4487
4487
  this.logger.info("ConsoleExporter shutdown");
4488
4488
  }
4489
4489
  };
4490
- function resolveTracingStorageStrategy(config, storage, logger) {
4490
+ function resolveTracingStorageStrategy(config, observability, storageName, logger) {
4491
4491
  if (config.strategy && config.strategy !== "auto") {
4492
- const hints = storage.tracingStrategy;
4492
+ const hints = observability.tracingStrategy;
4493
4493
  if (hints.supported.includes(config.strategy)) {
4494
4494
  return config.strategy;
4495
4495
  }
4496
4496
  logger.warn("User-specified tracing strategy not supported by storage adapter, falling back to auto-selection", {
4497
4497
  userStrategy: config.strategy,
4498
- storageAdapter: storage.constructor.name,
4498
+ storageAdapter: storageName,
4499
4499
  supportedStrategies: hints.supported,
4500
4500
  fallbackStrategy: hints.preferred
4501
4501
  });
4502
4502
  }
4503
- return storage.tracingStrategy.preferred;
4503
+ return observability.tracingStrategy.preferred;
4504
+ }
4505
+ function getStringOrNull(value) {
4506
+ return typeof value === "string" ? value : null;
4507
+ }
4508
+ function getObjectOrNull(value) {
4509
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
4504
4510
  }
4505
4511
  var DefaultExporter = class extends BaseExporter {
4506
4512
  name = "mastra-default-observability-exporter";
4507
4513
  #storage;
4514
+ #observability;
4508
4515
  #config;
4509
4516
  #resolvedStrategy;
4510
4517
  buffer;
@@ -4541,25 +4548,30 @@ var DefaultExporter = class extends BaseExporter {
4541
4548
  /**
4542
4549
  * Initialize the exporter (called after all dependencies are ready)
4543
4550
  */
4544
- init(options) {
4551
+ async init(options) {
4545
4552
  this.#storage = options.mastra?.getStorage();
4546
4553
  if (!this.#storage) {
4547
4554
  this.logger.warn("DefaultExporter disabled: Storage not available. Traces will not be persisted.");
4548
4555
  return;
4549
4556
  }
4550
- this.initializeStrategy(this.#storage);
4557
+ this.#observability = await this.#storage.getStore("observability");
4558
+ if (!this.#observability) {
4559
+ this.logger.warn("DefaultExporter disabled: Observability storage not available. Traces will not be persisted.");
4560
+ return;
4561
+ }
4562
+ this.initializeStrategy(this.#observability, this.#storage.constructor.name);
4551
4563
  }
4552
4564
  /**
4553
- * Initialize the resolved strategy once storage is available
4565
+ * Initialize the resolved strategy once observability store is available
4554
4566
  */
4555
- initializeStrategy(storage) {
4567
+ initializeStrategy(observability, storageName) {
4556
4568
  if (this.#strategyInitialized) return;
4557
- this.#resolvedStrategy = resolveTracingStorageStrategy(this.#config, storage, this.logger);
4569
+ this.#resolvedStrategy = resolveTracingStorageStrategy(this.#config, observability, storageName, this.logger);
4558
4570
  this.#strategyInitialized = true;
4559
4571
  this.logger.debug("tracing storage exporter initialized", {
4560
4572
  strategy: this.#resolvedStrategy,
4561
4573
  source: this.#config.strategy !== "auto" ? "user" : "auto",
4562
- storageAdapter: storage.constructor.name,
4574
+ storageAdapter: storageName,
4563
4575
  maxBatchSize: this.#config.maxBatchSize,
4564
4576
  maxBatchWaitMs: this.#config.maxBatchWaitMs
4565
4577
  });
@@ -4732,22 +4744,44 @@ var DefaultExporter = class extends BaseExporter {
4732
4744
  }
4733
4745
  }
4734
4746
  buildCreateRecord(span) {
4747
+ const metadata = span.metadata ?? {};
4735
4748
  return {
4736
4749
  traceId: span.traceId,
4737
4750
  spanId: span.id,
4738
4751
  parentSpanId: span.parentSpanId ?? null,
4739
4752
  name: span.name,
4740
- scope: null,
4753
+ // Entity identification - from span
4754
+ entityType: span.entityType ?? null,
4755
+ entityId: span.entityId ?? null,
4756
+ entityName: span.entityName ?? null,
4757
+ // Identity & Tenancy - extracted from metadata if present
4758
+ userId: getStringOrNull(metadata.userId),
4759
+ organizationId: getStringOrNull(metadata.organizationId),
4760
+ resourceId: getStringOrNull(metadata.resourceId),
4761
+ // Correlation IDs - extracted from metadata if present
4762
+ runId: getStringOrNull(metadata.runId),
4763
+ sessionId: getStringOrNull(metadata.sessionId),
4764
+ threadId: getStringOrNull(metadata.threadId),
4765
+ requestId: getStringOrNull(metadata.requestId),
4766
+ // Deployment context - extracted from metadata if present
4767
+ environment: getStringOrNull(metadata.environment),
4768
+ source: getStringOrNull(metadata.source),
4769
+ serviceName: getStringOrNull(metadata.serviceName),
4770
+ scope: getObjectOrNull(metadata.scope),
4771
+ // Span data
4741
4772
  spanType: span.type,
4742
4773
  attributes: this.serializeAttributes(span),
4743
4774
  metadata: span.metadata ?? null,
4775
+ // Keep all metadata including extracted fields
4776
+ tags: span.tags ?? null,
4744
4777
  links: null,
4778
+ input: span.input ?? null,
4779
+ output: span.output ?? null,
4780
+ error: span.errorInfo ?? null,
4781
+ isEvent: span.isEvent,
4782
+ // Timestamps
4745
4783
  startedAt: span.startTime,
4746
- endedAt: span.endTime ?? null,
4747
- input: span.input,
4748
- output: span.output,
4749
- error: span.errorInfo,
4750
- isEvent: span.isEvent
4784
+ endedAt: span.endTime ?? null
4751
4785
  };
4752
4786
  }
4753
4787
  buildUpdateRecord(span) {
@@ -4760,36 +4794,36 @@ var DefaultExporter = class extends BaseExporter {
4760
4794
  endedAt: span.endTime ?? null,
4761
4795
  input: span.input,
4762
4796
  output: span.output,
4763
- error: span.errorInfo
4797
+ error: span.errorInfo ?? null
4764
4798
  };
4765
4799
  }
4766
4800
  /**
4767
4801
  * Handles realtime strategy - processes each event immediately
4768
4802
  */
4769
- async handleRealtimeEvent(event, storage) {
4803
+ async handleRealtimeEvent(event, observability) {
4770
4804
  const span = event.exportedSpan;
4771
4805
  const spanKey = this.buildSpanKey(span.traceId, span.id);
4772
4806
  if (span.isEvent) {
4773
4807
  if (event.type === TracingEventType.SPAN_ENDED) {
4774
- await storage.createSpan(this.buildCreateRecord(event.exportedSpan));
4808
+ await observability.createSpan({ span: this.buildCreateRecord(event.exportedSpan) });
4775
4809
  } else {
4776
4810
  this.logger.warn(`Tracing event type not implemented for event spans: ${event.type}`);
4777
4811
  }
4778
4812
  } else {
4779
4813
  switch (event.type) {
4780
4814
  case TracingEventType.SPAN_STARTED:
4781
- await storage.createSpan(this.buildCreateRecord(event.exportedSpan));
4815
+ await observability.createSpan({ span: this.buildCreateRecord(event.exportedSpan) });
4782
4816
  this.allCreatedSpans.add(spanKey);
4783
4817
  break;
4784
4818
  case TracingEventType.SPAN_UPDATED:
4785
- await storage.updateSpan({
4819
+ await observability.updateSpan({
4786
4820
  traceId: span.traceId,
4787
4821
  spanId: span.id,
4788
4822
  updates: this.buildUpdateRecord(span)
4789
4823
  });
4790
4824
  break;
4791
4825
  case TracingEventType.SPAN_ENDED:
4792
- await storage.updateSpan({
4826
+ await observability.updateSpan({
4793
4827
  traceId: span.traceId,
4794
4828
  spanId: span.id,
4795
4829
  updates: this.buildUpdateRecord(span)
@@ -4843,8 +4877,8 @@ var DefaultExporter = class extends BaseExporter {
4843
4877
  * Flushes the current buffer to storage with retry logic
4844
4878
  */
4845
4879
  async flush() {
4846
- if (!this.#storage) {
4847
- this.logger.debug("Cannot flush traces. Mastra storage is not initialized");
4880
+ if (!this.#observability) {
4881
+ this.logger.debug("Cannot flush traces. Observability storage is not initialized");
4848
4882
  return;
4849
4883
  }
4850
4884
  if (this.#flushTimer) {
@@ -4868,7 +4902,7 @@ var DefaultExporter = class extends BaseExporter {
4868
4902
  totalSize: this.buffer.totalSize
4869
4903
  };
4870
4904
  this.resetBuffer();
4871
- await this.flushWithRetries(this.#storage, bufferCopy, 0);
4905
+ await this.flushWithRetries(this.#observability, bufferCopy, 0);
4872
4906
  const elapsed = Date.now() - startTime;
4873
4907
  this.logger.debug("Batch flushed", {
4874
4908
  strategy: this.#resolvedStrategy,
@@ -4881,11 +4915,11 @@ var DefaultExporter = class extends BaseExporter {
4881
4915
  /**
4882
4916
  * Attempts to flush with exponential backoff retry logic
4883
4917
  */
4884
- async flushWithRetries(storage, buffer, attempt) {
4918
+ async flushWithRetries(observability, buffer, attempt) {
4885
4919
  try {
4886
4920
  if (this.#resolvedStrategy === "batch-with-updates") {
4887
4921
  if (buffer.creates.length > 0) {
4888
- await storage.batchCreateSpans({ records: buffer.creates });
4922
+ await observability.batchCreateSpans({ records: buffer.creates });
4889
4923
  }
4890
4924
  if (buffer.updates.length > 0) {
4891
4925
  const sortedUpdates = buffer.updates.sort((a, b) => {
@@ -4895,11 +4929,11 @@ var DefaultExporter = class extends BaseExporter {
4895
4929
  if (spanCompare !== 0) return spanCompare;
4896
4930
  return a.sequenceNumber - b.sequenceNumber;
4897
4931
  });
4898
- await storage.batchUpdateSpans({ records: sortedUpdates });
4932
+ await observability.batchUpdateSpans({ records: sortedUpdates });
4899
4933
  }
4900
4934
  } else if (this.#resolvedStrategy === "insert-only") {
4901
4935
  if (buffer.insertOnly.length > 0) {
4902
- await storage.batchCreateSpans({ records: buffer.insertOnly });
4936
+ await observability.batchCreateSpans({ records: buffer.insertOnly });
4903
4937
  }
4904
4938
  }
4905
4939
  for (const spanKey of buffer.completedSpans) {
@@ -4915,7 +4949,7 @@ var DefaultExporter = class extends BaseExporter {
4915
4949
  error: error instanceof Error ? error.message : String(error)
4916
4950
  });
4917
4951
  await new Promise((resolve) => setTimeout(resolve, retryDelay));
4918
- return this.flushWithRetries(storage, buffer, attempt + 1);
4952
+ return this.flushWithRetries(observability, buffer, attempt + 1);
4919
4953
  } else {
4920
4954
  this.logger.error("Batch flush failed after all retries, dropping batch", {
4921
4955
  finalAttempt: attempt + 1,
@@ -4930,16 +4964,16 @@ var DefaultExporter = class extends BaseExporter {
4930
4964
  }
4931
4965
  }
4932
4966
  async _exportTracingEvent(event) {
4933
- if (!this.#storage) {
4934
- this.logger.debug("Cannot store traces. Mastra storage is not initialized");
4967
+ if (!this.#observability) {
4968
+ this.logger.debug("Cannot store traces. Observability storage is not initialized");
4935
4969
  return;
4936
4970
  }
4937
4971
  if (!this.#strategyInitialized) {
4938
- this.initializeStrategy(this.#storage);
4972
+ this.initializeStrategy(this.#observability, this.#storage?.constructor.name ?? "Unknown");
4939
4973
  }
4940
4974
  switch (this.#resolvedStrategy) {
4941
4975
  case "realtime":
4942
- await this.handleRealtimeEvent(event, this.#storage);
4976
+ await this.handleRealtimeEvent(event, this.#observability);
4943
4977
  break;
4944
4978
  case "batch-with-updates":
4945
4979
  this.handleBatchWithUpdatesEvent(event);
@@ -5100,9 +5134,14 @@ var ModelSpanTracker = class {
5100
5134
  this.#modelSpan?.update(options);
5101
5135
  }
5102
5136
  /**
5103
- * Start a new Model execution step
5137
+ * Start a new Model execution step.
5138
+ * This should be called at the beginning of LLM execution to capture accurate startTime.
5139
+ * The step-start chunk payload can be passed later via updateStep() if needed.
5104
5140
  */
5105
- #startStepSpan(payload) {
5141
+ startStep(payload) {
5142
+ if (this.#currentStepSpan) {
5143
+ return;
5144
+ }
5106
5145
  this.#currentStepSpan = this.#modelSpan?.createChildSpan({
5107
5146
  name: `step: ${this.#stepIndex}`,
5108
5147
  type: SpanType.MODEL_STEP,
@@ -5115,6 +5154,22 @@ var ModelSpanTracker = class {
5115
5154
  });
5116
5155
  this.#chunkSequence = 0;
5117
5156
  }
5157
+ /**
5158
+ * Update the current step span with additional payload data.
5159
+ * Called when step-start chunk arrives with request/warnings info.
5160
+ */
5161
+ updateStep(payload) {
5162
+ if (!this.#currentStepSpan || !payload) {
5163
+ return;
5164
+ }
5165
+ this.#currentStepSpan.update({
5166
+ input: payload.request,
5167
+ attributes: {
5168
+ ...payload.messageId ? { messageId: payload.messageId } : {},
5169
+ ...payload.warnings?.length ? { warnings: payload.warnings } : {}
5170
+ }
5171
+ });
5172
+ }
5118
5173
  /**
5119
5174
  * End the current Model execution step with token usage, finish reason, output, and metadata
5120
5175
  */
@@ -5149,7 +5204,7 @@ var ModelSpanTracker = class {
5149
5204
  */
5150
5205
  #startChunkSpan(chunkType, initialData) {
5151
5206
  if (!this.#currentStepSpan) {
5152
- this.#startStepSpan();
5207
+ this.startStep();
5153
5208
  }
5154
5209
  this.#currentChunkSpan = this.#currentStepSpan?.createChildSpan({
5155
5210
  name: `chunk: '${chunkType}'`,
@@ -5189,7 +5244,7 @@ var ModelSpanTracker = class {
5189
5244
  */
5190
5245
  #createEventSpan(chunkType, output) {
5191
5246
  if (!this.#currentStepSpan) {
5192
- this.#startStepSpan();
5247
+ this.startStep();
5193
5248
  }
5194
5249
  const span = this.#currentStepSpan?.createEventSpan({
5195
5250
  name: `chunk: '${chunkType}'`,
@@ -5308,7 +5363,7 @@ var ModelSpanTracker = class {
5308
5363
  let acc = this.#toolOutputAccumulators.get(toolCallId);
5309
5364
  if (!acc) {
5310
5365
  if (!this.#currentStepSpan) {
5311
- this.#startStepSpan();
5366
+ this.startStep();
5312
5367
  }
5313
5368
  acc = {
5314
5369
  toolName: toolName || "unknown",
@@ -5408,7 +5463,11 @@ var ModelSpanTracker = class {
5408
5463
  this.#handleObjectChunk(chunk);
5409
5464
  break;
5410
5465
  case "step-start":
5411
- this.#startStepSpan(chunk.payload);
5466
+ if (this.#currentStepSpan) {
5467
+ this.updateStep(chunk.payload);
5468
+ } else {
5469
+ this.startStep(chunk.payload);
5470
+ }
5412
5471
  break;
5413
5472
  case "step-finish":
5414
5473
  this.#endStepSpan(chunk.payload);
@@ -5615,6 +5674,12 @@ var BaseSpan = class {
5615
5674
  metadata;
5616
5675
  tags;
5617
5676
  traceState;
5677
+ /** Entity type that created the span (e.g., agent, workflow) */
5678
+ entityType;
5679
+ /** Entity ID that created the span */
5680
+ entityId;
5681
+ /** Entity name that created the span */
5682
+ entityName;
5618
5683
  /** Parent span ID (for root spans that are children of external spans) */
5619
5684
  parentSpanId;
5620
5685
  constructor(options, observabilityInstance) {
@@ -5629,6 +5694,9 @@ var BaseSpan = class {
5629
5694
  this.isInternal = isSpanInternal(this.type, options.tracingPolicy?.internal);
5630
5695
  this.traceState = options.traceState;
5631
5696
  this.tags = !options.parent && options.tags?.length ? options.tags : void 0;
5697
+ this.entityType = options.entityType;
5698
+ this.entityId = options.entityId;
5699
+ this.entityName = options.entityName;
5632
5700
  if (this.isEvent) {
5633
5701
  this.output = deepClean(options.output);
5634
5702
  } else {
@@ -5682,6 +5750,9 @@ var BaseSpan = class {
5682
5750
  traceId: this.traceId,
5683
5751
  name: this.name,
5684
5752
  type: this.type,
5753
+ entityType: this.entityType,
5754
+ entityId: this.entityId,
5755
+ entityName: this.entityName,
5685
5756
  attributes: this.attributes,
5686
5757
  metadata: this.metadata,
5687
5758
  startTime: this.startTime,