@mastra/observability 1.0.0-beta.5 → 1.0.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/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);
@@ -5452,6 +5486,110 @@ var ModelSpanTracker = class {
5452
5486
  }
5453
5487
  };
5454
5488
 
5489
+ // src/spans/serialization.ts
5490
+ var DEFAULT_KEYS_TO_STRIP = /* @__PURE__ */ new Set([
5491
+ "logger",
5492
+ "experimental_providerMetadata",
5493
+ "providerMetadata",
5494
+ "steps",
5495
+ "tracingContext"
5496
+ ]);
5497
+ var DEFAULT_DEEP_CLEAN_OPTIONS = Object.freeze({
5498
+ keysToStrip: DEFAULT_KEYS_TO_STRIP,
5499
+ maxDepth: 6,
5500
+ maxStringLength: 1024,
5501
+ maxArrayLength: 50,
5502
+ maxObjectKeys: 50
5503
+ });
5504
+ function truncateString(s, maxChars) {
5505
+ if (s.length <= maxChars) {
5506
+ return s;
5507
+ }
5508
+ return s.slice(0, maxChars) + "\u2026[truncated]";
5509
+ }
5510
+ function deepClean(value, options = DEFAULT_DEEP_CLEAN_OPTIONS) {
5511
+ const { keysToStrip, maxDepth, maxStringLength, maxArrayLength, maxObjectKeys } = options;
5512
+ const seen = /* @__PURE__ */ new WeakSet();
5513
+ function helper(val, depth) {
5514
+ if (depth > maxDepth) {
5515
+ return "[MaxDepth]";
5516
+ }
5517
+ if (val === null || val === void 0) {
5518
+ return val;
5519
+ }
5520
+ if (typeof val === "string") {
5521
+ return truncateString(val, maxStringLength);
5522
+ }
5523
+ if (typeof val === "number" || typeof val === "boolean") {
5524
+ return val;
5525
+ }
5526
+ if (typeof val === "bigint") {
5527
+ return `${val}n`;
5528
+ }
5529
+ if (typeof val === "function") {
5530
+ return "[Function]";
5531
+ }
5532
+ if (typeof val === "symbol") {
5533
+ return val.description ? `[Symbol(${val.description})]` : "[Symbol]";
5534
+ }
5535
+ if (val instanceof Date) {
5536
+ return val;
5537
+ }
5538
+ if (val instanceof Error) {
5539
+ return {
5540
+ name: val.name,
5541
+ message: val.message ? truncateString(val.message, maxStringLength) : void 0
5542
+ };
5543
+ }
5544
+ if (typeof val === "object") {
5545
+ if (seen.has(val)) {
5546
+ return "[Circular]";
5547
+ }
5548
+ seen.add(val);
5549
+ }
5550
+ if (Array.isArray(val)) {
5551
+ const limitedArray = val.slice(0, maxArrayLength);
5552
+ const cleaned2 = limitedArray.map((item) => helper(item, depth + 1));
5553
+ if (val.length > maxArrayLength) {
5554
+ cleaned2.push(`[\u2026${val.length - maxArrayLength} more items]`);
5555
+ }
5556
+ return cleaned2;
5557
+ }
5558
+ if (typeof Buffer !== "undefined" && Buffer.isBuffer(val)) {
5559
+ return `[Buffer length=${val.length}]`;
5560
+ }
5561
+ if (ArrayBuffer.isView(val)) {
5562
+ const ctor = val.constructor?.name ?? "TypedArray";
5563
+ const byteLength = val.byteLength ?? "?";
5564
+ return `[${ctor} byteLength=${byteLength}]`;
5565
+ }
5566
+ if (val instanceof ArrayBuffer) {
5567
+ return `[ArrayBuffer byteLength=${val.byteLength}]`;
5568
+ }
5569
+ const cleaned = {};
5570
+ const entries = Object.entries(val);
5571
+ let keyCount = 0;
5572
+ for (const [key, v] of entries) {
5573
+ if (keysToStrip.has(key)) {
5574
+ continue;
5575
+ }
5576
+ if (keyCount >= maxObjectKeys) {
5577
+ cleaned["__truncated"] = `${entries.length - keyCount} more keys omitted`;
5578
+ break;
5579
+ }
5580
+ try {
5581
+ cleaned[key] = helper(v, depth + 1);
5582
+ keyCount++;
5583
+ } catch (error) {
5584
+ cleaned[key] = `[${error instanceof Error ? error.message : String(error)}]`;
5585
+ keyCount++;
5586
+ }
5587
+ }
5588
+ return cleaned;
5589
+ }
5590
+ return helper(value, 0);
5591
+ }
5592
+
5455
5593
  // src/spans/base.ts
5456
5594
  function isSpanInternal(spanType, flags) {
5457
5595
  if (flags === void 0 || flags === InternalSpans.NONE) {
@@ -5511,6 +5649,12 @@ var BaseSpan = class {
5511
5649
  metadata;
5512
5650
  tags;
5513
5651
  traceState;
5652
+ /** Entity type that created the span (e.g., agent, workflow) */
5653
+ entityType;
5654
+ /** Entity ID that created the span */
5655
+ entityId;
5656
+ /** Entity name that created the span */
5657
+ entityName;
5514
5658
  /** Parent span ID (for root spans that are children of external spans) */
5515
5659
  parentSpanId;
5516
5660
  constructor(options, observabilityInstance) {
@@ -5525,6 +5669,9 @@ var BaseSpan = class {
5525
5669
  this.isInternal = isSpanInternal(this.type, options.tracingPolicy?.internal);
5526
5670
  this.traceState = options.traceState;
5527
5671
  this.tags = !options.parent && options.tags?.length ? options.tags : void 0;
5672
+ this.entityType = options.entityType;
5673
+ this.entityId = options.entityId;
5674
+ this.entityName = options.entityName;
5528
5675
  if (this.isEvent) {
5529
5676
  this.output = deepClean(options.output);
5530
5677
  } else {
@@ -5578,6 +5725,9 @@ var BaseSpan = class {
5578
5725
  traceId: this.traceId,
5579
5726
  name: this.name,
5580
5727
  type: this.type,
5728
+ entityType: this.entityType,
5729
+ entityId: this.entityId,
5730
+ entityName: this.entityName,
5581
5731
  attributes: this.attributes,
5582
5732
  metadata: this.metadata,
5583
5733
  startTime: this.startTime,
@@ -5618,49 +5768,6 @@ var BaseSpan = class {
5618
5768
  return fn();
5619
5769
  }
5620
5770
  };
5621
- var DEFAULT_KEYS_TO_STRIP = /* @__PURE__ */ new Set([
5622
- "logger",
5623
- "experimental_providerMetadata",
5624
- "providerMetadata",
5625
- "steps",
5626
- "tracingContext"
5627
- ]);
5628
- function deepClean(value, options = {}, _seen = /* @__PURE__ */ new WeakSet(), _depth = 0) {
5629
- const { keysToStrip = DEFAULT_KEYS_TO_STRIP, maxDepth = 10 } = options;
5630
- if (_depth > maxDepth) {
5631
- return "[MaxDepth]";
5632
- }
5633
- if (value === null || typeof value !== "object") {
5634
- try {
5635
- JSON.stringify(value);
5636
- return value;
5637
- } catch (error) {
5638
- return `[${error instanceof Error ? error.message : String(error)}]`;
5639
- }
5640
- }
5641
- if (_seen.has(value)) {
5642
- return "[Circular]";
5643
- }
5644
- _seen.add(value);
5645
- if (value instanceof Date) {
5646
- return value;
5647
- }
5648
- if (Array.isArray(value)) {
5649
- return value.map((item) => deepClean(item, options, _seen, _depth + 1));
5650
- }
5651
- const cleaned = {};
5652
- for (const [key, val] of Object.entries(value)) {
5653
- if (keysToStrip.has(key)) {
5654
- continue;
5655
- }
5656
- try {
5657
- cleaned[key] = deepClean(val, options, _seen, _depth + 1);
5658
- } catch (error) {
5659
- cleaned[key] = `[${error instanceof Error ? error.message : String(error)}]`;
5660
- }
5661
- }
5662
- return cleaned;
5663
- }
5664
5771
  var DefaultSpan = class extends BaseSpan {
5665
5772
  id;
5666
5773
  traceId;
@@ -6538,6 +6645,6 @@ function buildTracingOptions(...updaters) {
6538
6645
  return updaters.reduce((opts, updater) => updater(opts), {});
6539
6646
  }
6540
6647
 
6541
- export { BaseExporter, BaseObservabilityInstance, BaseSpan, CloudExporter, ConsoleExporter, DefaultExporter, DefaultObservabilityInstance, DefaultSpan, ModelSpanTracker, NoOpSpan, Observability, SamplingStrategyType, SensitiveDataFilter, TestExporter, buildTracingOptions, deepClean, getExternalParentId, observabilityConfigValueSchema, observabilityInstanceConfigSchema, observabilityRegistryConfigSchema, samplingStrategySchema };
6648
+ export { BaseExporter, BaseObservabilityInstance, BaseSpan, CloudExporter, ConsoleExporter, DEFAULT_DEEP_CLEAN_OPTIONS, DEFAULT_KEYS_TO_STRIP, DefaultExporter, DefaultObservabilityInstance, DefaultSpan, ModelSpanTracker, NoOpSpan, Observability, SamplingStrategyType, SensitiveDataFilter, TestExporter, buildTracingOptions, deepClean, getExternalParentId, observabilityConfigValueSchema, observabilityInstanceConfigSchema, observabilityRegistryConfigSchema, samplingStrategySchema, truncateString };
6542
6649
  //# sourceMappingURL=index.js.map
6543
6650
  //# sourceMappingURL=index.js.map