@mastra/observability 1.9.2-alpha.0 → 1.10.0-alpha.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # @mastra/observability
2
2
 
3
+ ## 1.10.0-alpha.2
4
+
5
+ ### Minor Changes
6
+
7
+ - Changed `MODEL_CHUNK` `tool-result` span `output` handling. ([#15495](https://github.com/mastra-ai/mastra/pull/15495))
8
+
9
+ **What changed**
10
+ - `MODEL_CHUNK` spans for `tool-result` now omit `output` for locally executed tools.
11
+ - `TOOL_CALL` remains the canonical span for locally executed tool result payloads.
12
+ - `MODEL_CHUNK` spans for provider-executed `tool-result` chunks still include `output`.
13
+ - `MODEL_CHUNK` metadata still includes `toolCallId`, `toolName`, and `providerExecuted`.
14
+
15
+ **Why**
16
+ This reduces duplicate tool result payloads in traces without dropping provider-emitted tool results that may not have a matching `TOOL_CALL` span.
17
+
18
+ ### Patch Changes
19
+
20
+ - Updated dependencies [[`8786a61`](https://github.com/mastra-ai/mastra/commit/8786a61fa54ba265f85eeff9985ca39863d18bb6), [`8fb2405`](https://github.com/mastra-ai/mastra/commit/8fb2405138f2d208b7962ad03f121ca25bcc28c5)]:
21
+ - @mastra/core@1.26.0-alpha.7
22
+
23
+ ## 1.9.2-alpha.1
24
+
25
+ ### Patch Changes
26
+
27
+ - Improved tracing overhead when filtering spans. Spans dropped by `excludeSpanTypes` or the internal-span filter (`includeInternalSpans: false`) now skip payload serialization and retention entirely instead of paying the cost and discarding at export time. ([#15487](https://github.com/mastra-ai/mastra/pull/15487))
28
+
29
+ - Updated dependencies [[`6315317`](https://github.com/mastra-ai/mastra/commit/63153175fe9a7b224e5be7c209bbebc01dd9b0d5), [`9d3b24b`](https://github.com/mastra-ai/mastra/commit/9d3b24b19407ae9c09586cf7766d38dc4dff4a69)]:
30
+ - @mastra/core@1.26.0-alpha.6
31
+
3
32
  ## 1.9.2-alpha.0
4
33
 
5
34
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -19152,14 +19152,16 @@ var ModelSpanTracker = class {
19152
19152
  dynamic,
19153
19153
  providerExecuted,
19154
19154
  providerMetadata,
19155
- // Output - the actual result
19155
+ // Keep provider-executed results on MODEL_CHUNK because they come
19156
+ // from the model/provider stream and may not have a sibling TOOL_CALL span.
19157
+ // For locally executed tools, the canonical payload lives on TOOL_CALL.
19156
19158
  result} = chunk.payload || {};
19157
19159
  const metadata = { toolCallId, toolName };
19158
19160
  if (isError !== void 0) metadata.isError = isError;
19159
19161
  if (dynamic !== void 0) metadata.dynamic = dynamic;
19160
19162
  if (providerExecuted !== void 0) metadata.providerExecuted = providerExecuted;
19161
19163
  if (providerMetadata !== void 0) metadata.providerMetadata = providerMetadata;
19162
- this.#createEventSpan(chunk.type, result, { metadata });
19164
+ this.#createEventSpan(chunk.type, providerExecuted ? result : void 0, { metadata });
19163
19165
  break;
19164
19166
  }
19165
19167
  }
@@ -19239,32 +19241,58 @@ var BaseSpan = class {
19239
19241
  parentSpanId;
19240
19242
  /** Deep clean options for serialization */
19241
19243
  deepCleanOptions;
19244
+ /**
19245
+ * Whether this span is filtered out before export. When true, BaseSpan/
19246
+ * DefaultSpan skip attaching attributes/input/output/errorInfo/requestContext
19247
+ * entirely -- they are never read on excluded spans, and skipping avoids
19248
+ * both the deepClean cost and holding references to large payloads for
19249
+ * the lifetime of the span. Set when excludeSpanTypes drops the type,
19250
+ * when the span is internal and includeInternalSpans is false, or when
19251
+ * the subclass is always excluded (e.g., NoOpSpan).
19252
+ *
19253
+ * Note: metadata is still attached and deepCleaned because it is read in
19254
+ * process by getCorrelationContext() and by getLoggerContext() /
19255
+ * getMetricsContext() (which structuredClone it).
19256
+ */
19257
+ isExcluded;
19242
19258
  /** Cached canonical correlation context for this live span */
19243
19259
  correlationContext;
19260
+ /**
19261
+ * Subclasses can override to unconditionally mark the span as excluded.
19262
+ * NoOpSpan uses this because it is never exported regardless of config.
19263
+ */
19264
+ get alwaysExcluded() {
19265
+ return false;
19266
+ }
19244
19267
  constructor(options, observabilityInstance) {
19245
- const serializationOptions = observabilityInstance.getConfig().serializationOptions;
19246
- this.deepCleanOptions = mergeSerializationOptions(serializationOptions);
19268
+ const observabilityConfig = observabilityInstance.getConfig();
19269
+ this.deepCleanOptions = mergeSerializationOptions(observabilityConfig.serializationOptions);
19247
19270
  this.name = options.name;
19248
19271
  this.type = options.type;
19249
- this.attributes = deepClean(options.attributes, this.deepCleanOptions) || {};
19272
+ this.isInternal = isSpanInternal(this.type, options.tracingPolicy?.internal);
19273
+ this.isExcluded = this.alwaysExcluded || observabilityConfig.excludeSpanTypes?.includes(this.type) === true || this.isInternal && !observabilityConfig.includeInternalSpans;
19250
19274
  this.metadata = deepClean(
19251
19275
  options.parent?.metadata || options.metadata ? { ...options.parent?.metadata, ...options.metadata } : void 0,
19252
19276
  this.deepCleanOptions
19253
19277
  );
19254
- if (options.requestContext && options.requestContext.size() > 0) {
19255
- this.requestContext = deepClean(options.requestContext.all, this.deepCleanOptions);
19256
- }
19257
19278
  this.parent = options.parent;
19258
19279
  this.startTime = options.startTime ?? /* @__PURE__ */ new Date();
19259
19280
  this.observabilityInstance = observabilityInstance;
19260
19281
  this.isEvent = options.isEvent ?? false;
19261
- this.isInternal = isSpanInternal(this.type, options.tracingPolicy?.internal);
19262
19282
  this.traceState = options.traceState;
19263
19283
  this.tags = !options.parent && options.tags?.length ? options.tags : void 0;
19264
19284
  const entityParent = this.getParentSpan(false);
19265
19285
  this.entityType = options.entityType ?? entityParent?.entityType;
19266
19286
  this.entityId = options.entityId ?? entityParent?.entityId;
19267
19287
  this.entityName = options.entityName ?? entityParent?.entityName;
19288
+ if (this.isExcluded) {
19289
+ this.attributes = {};
19290
+ return;
19291
+ }
19292
+ this.attributes = deepClean(options.attributes, this.deepCleanOptions) || {};
19293
+ if (options.requestContext && options.requestContext.size() > 0) {
19294
+ this.requestContext = deepClean(options.requestContext.all, this.deepCleanOptions);
19295
+ }
19268
19296
  if (this.isEvent) {
19269
19297
  this.output = deepClean(options.output, this.deepCleanOptions);
19270
19298
  } else {
@@ -19468,46 +19496,51 @@ var DefaultSpan = class extends BaseSpan {
19468
19496
  return;
19469
19497
  }
19470
19498
  this.endTime = /* @__PURE__ */ new Date();
19499
+ if (options?.metadata) {
19500
+ this.metadata = { ...this.metadata, ...deepClean(options.metadata, this.deepCleanOptions) };
19501
+ }
19502
+ if (this.isExcluded) {
19503
+ return;
19504
+ }
19471
19505
  if (options?.output !== void 0) {
19472
19506
  this.output = deepClean(options.output, this.deepCleanOptions);
19473
19507
  }
19474
19508
  if (options?.attributes) {
19475
19509
  this.attributes = { ...this.attributes, ...deepClean(options.attributes, this.deepCleanOptions) };
19476
19510
  }
19477
- if (options?.metadata) {
19478
- this.metadata = { ...this.metadata, ...deepClean(options.metadata, this.deepCleanOptions) };
19479
- }
19480
19511
  }
19481
19512
  error(options) {
19482
19513
  if (this.isEvent) {
19483
19514
  return;
19484
19515
  }
19485
19516
  const { error: error48, endSpan = true, attributes, metadata } = options;
19486
- this.errorInfo = deepClean(
19487
- error48 instanceof error$1.MastraError ? {
19488
- id: error48.id,
19489
- details: error48.details,
19490
- category: error48.category,
19491
- domain: error48.domain,
19492
- message: error48.message,
19493
- name: error48.name,
19494
- // Prefer the original cause's stack when available. MastraError wraps
19495
- // thrown errors, so its own stack points to the wrapping site rather
19496
- // than where the underlying error was thrown.
19497
- stack: error48.cause instanceof Error && error48.cause.stack || error48.stack
19498
- } : {
19499
- message: error48.message,
19500
- name: error48.name,
19501
- stack: error48.stack
19502
- },
19503
- this.deepCleanOptions
19504
- );
19505
- if (attributes) {
19506
- this.attributes = { ...this.attributes, ...deepClean(attributes, this.deepCleanOptions) };
19507
- }
19508
19517
  if (metadata) {
19509
19518
  this.metadata = { ...this.metadata, ...deepClean(metadata, this.deepCleanOptions) };
19510
19519
  }
19520
+ if (!this.isExcluded) {
19521
+ this.errorInfo = deepClean(
19522
+ error48 instanceof error$1.MastraError ? {
19523
+ id: error48.id,
19524
+ details: error48.details,
19525
+ category: error48.category,
19526
+ domain: error48.domain,
19527
+ message: error48.message,
19528
+ name: error48.name,
19529
+ // Prefer the original cause's stack when available. MastraError wraps
19530
+ // thrown errors, so its own stack points to the wrapping site rather
19531
+ // than where the underlying error was thrown.
19532
+ stack: error48.cause instanceof Error && error48.cause.stack || error48.stack
19533
+ } : {
19534
+ message: error48.message,
19535
+ name: error48.name,
19536
+ stack: error48.stack
19537
+ },
19538
+ this.deepCleanOptions
19539
+ );
19540
+ if (attributes) {
19541
+ this.attributes = { ...this.attributes, ...deepClean(attributes, this.deepCleanOptions) };
19542
+ }
19543
+ }
19511
19544
  if (endSpan) {
19512
19545
  this.end();
19513
19546
  } else {
@@ -19521,6 +19554,12 @@ var DefaultSpan = class extends BaseSpan {
19521
19554
  if (options.name !== void 0) {
19522
19555
  this.name = options.name;
19523
19556
  }
19557
+ if (options.metadata) {
19558
+ this.metadata = { ...this.metadata, ...deepClean(options.metadata, this.deepCleanOptions) };
19559
+ }
19560
+ if (this.isExcluded) {
19561
+ return;
19562
+ }
19524
19563
  if (options.input !== void 0) {
19525
19564
  this.input = deepClean(options.input, this.deepCleanOptions);
19526
19565
  }
@@ -19530,9 +19569,6 @@ var DefaultSpan = class extends BaseSpan {
19530
19569
  if (options.attributes) {
19531
19570
  this.attributes = { ...this.attributes, ...deepClean(options.attributes, this.deepCleanOptions) };
19532
19571
  }
19533
- if (options.metadata) {
19534
- this.metadata = { ...this.metadata, ...deepClean(options.metadata, this.deepCleanOptions) };
19535
- }
19536
19572
  }
19537
19573
  get isValid() {
19538
19574
  return true;
@@ -19608,6 +19644,10 @@ var NoOpSpan = class extends BaseSpan {
19608
19644
  get isValid() {
19609
19645
  return false;
19610
19646
  }
19647
+ // NoOpSpan is never exported, so treat it as always excluded.
19648
+ get alwaysExcluded() {
19649
+ return true;
19650
+ }
19611
19651
  };
19612
19652
 
19613
19653
  // src/instances/base.ts