@mastra/observability 1.15.0-alpha.0 → 1.15.1-alpha.0

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,25 @@
1
1
  # @mastra/observability
2
2
 
3
+ ## 1.15.1-alpha.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Fixed auto-extracted metrics (duration, token usage, cost) being silently dropped when spans are filtered via `excludeSpanTypes` or `spanFilter`. Previously, excluding a span type to reduce per-span costs in platforms like Langfuse also suppressed its aggregate metrics. Metrics are now emitted independently of span export filtering. ([#18253](https://github.com/mastra-ai/mastra/pull/18253))
8
+
9
+ - Updated dependencies [[`65f255a`](https://github.com/mastra-ai/mastra/commit/65f255a38667beb6ceeadabfa9eb5059bfec8298), [`4a88c6e`](https://github.com/mastra-ai/mastra/commit/4a88c6e2bdce316f8d7551b4ec3449b0b06fc71c), [`87a17ef`](https://github.com/mastra-ai/mastra/commit/87a17efbd725aca6639febdc5e69e2abb3048689), [`e11ff30`](https://github.com/mastra-ai/mastra/commit/e11ff301408bf1731dca2fb7fbfcd8c819500a35), [`9d2c946`](https://github.com/mastra-ai/mastra/commit/9d2c946d0859e90ae4bcec5beeb1da7398d2ad1e), [`f1ec385`](https://github.com/mastra-ai/mastra/commit/f1ec385386f62b1a0847ec5353ae2bb169d1c3d9), [`e14986f`](https://github.com/mastra-ai/mastra/commit/e14986f6e5478d6384d04ff9a7f9a79a46a8b529), [`0be490f`](https://github.com/mastra-ai/mastra/commit/0be490fabb538c5a7de796ea0aff7d04a0bea1f3), [`0be490f`](https://github.com/mastra-ai/mastra/commit/0be490fabb538c5a7de796ea0aff7d04a0bea1f3), [`974f614`](https://github.com/mastra-ai/mastra/commit/974f614e083bd68278536f94453f7b320b86a3c7), [`31be1cf`](https://github.com/mastra-ai/mastra/commit/31be1cf5f2a7b5eef12f6123a40653b4d8115c16)]:
10
+ - @mastra/core@1.46.0-alpha.3
11
+
12
+ ## 1.15.0
13
+
14
+ ### Minor Changes
15
+
16
+ - Random bump ([#18178](https://github.com/mastra-ai/mastra/pull/18178))
17
+
18
+ ### Patch Changes
19
+
20
+ - Updated dependencies [[`7c0d868`](https://github.com/mastra-ai/mastra/commit/7c0d868d97d0fdbc04c14d0166dbf44d4c5a4a62), [`d9d2273`](https://github.com/mastra-ai/mastra/commit/d9d2273c702690c9a26eab2aebea879701d4355a), [`b04369d`](https://github.com/mastra-ai/mastra/commit/b04369d6b167c698ef103981171a8bf92808e756), [`8f3c262`](https://github.com/mastra-ai/mastra/commit/8f3c262587b335588a02d96b17fd6aca34c885b3)]:
21
+ - @mastra/core@1.45.0
22
+
3
23
  ## 1.15.0-alpha.0
4
24
 
5
25
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -2925,6 +2925,12 @@ var BaseObservabilityInstance = class extends base.MastraBase {
2925
2925
  * a span's `metadata.environment` isn't set.
2926
2926
  */
2927
2927
  #mastraEnvironment;
2928
+ /**
2929
+ * For excluded MODEL_GENERATION spans whose constructor clears `attributes`,
2930
+ * we stash the lightweight provider/model from creation options so
2931
+ * `captureExcludedModelUsage` can still build cost context.
2932
+ */
2933
+ #excludedModelMeta = /* @__PURE__ */ new WeakMap();
2928
2934
  constructor(config) {
2929
2935
  super({ component: logger.RegisteredLogger.OBSERVABILITY, name: config.serviceName });
2930
2936
  this.config = {
@@ -3030,6 +3036,13 @@ var BaseObservabilityInstance = class extends base.MastraBase {
3030
3036
  tags,
3031
3037
  requestContext
3032
3038
  });
3039
+ if (rest.type === observability.SpanType.MODEL_GENERATION && this.config.excludeSpanTypes?.includes(observability.SpanType.MODEL_GENERATION)) {
3040
+ const attrs = rest.attributes;
3041
+ const model = attrs?.responseModel ?? attrs?.model;
3042
+ if (attrs?.provider || model) {
3043
+ this.#excludedModelMeta.set(span, { provider: attrs?.provider, model });
3044
+ }
3045
+ }
3033
3046
  if (span.isEvent) {
3034
3047
  this.emitSpanEnded(span);
3035
3048
  } else {
@@ -3226,11 +3239,12 @@ var BaseObservabilityInstance = class extends base.MastraBase {
3226
3239
  return;
3227
3240
  }
3228
3241
  const rollupTarget = this.captureModelUsageRollup(span, options);
3242
+ const excludedModelUsage = this.captureExcludedModelUsage(span, options);
3229
3243
  originalEnd(options);
3230
3244
  if (rollupTarget) {
3231
3245
  this.applyUsageRollup(rollupTarget);
3232
3246
  }
3233
- this.emitSpanEnded(span);
3247
+ this.emitSpanEnded(span, excludedModelUsage);
3234
3248
  };
3235
3249
  span.update = (options) => {
3236
3250
  if (span.isEvent) {
@@ -3364,6 +3378,22 @@ var BaseObservabilityInstance = class extends base.MastraBase {
3364
3378
  }
3365
3379
  return exportedSpan;
3366
3380
  }
3381
+ /** Export an already-processed span, returning undefined if filtered out. */
3382
+ getProcessedSpanForExport(span) {
3383
+ if (!span.isValid) return void 0;
3384
+ if (span.isInternal && !this.config.includeInternalSpans) return void 0;
3385
+ if (this.config.excludeSpanTypes?.includes(span.type)) return void 0;
3386
+ const exportedSpan = span.exportSpan(this.config.includeInternalSpans);
3387
+ if (!exportedSpan) return void 0;
3388
+ if (this.config.spanFilter) {
3389
+ try {
3390
+ if (!this.config.spanFilter(exportedSpan)) return void 0;
3391
+ } catch (error) {
3392
+ this.logger.error(`[Observability] spanFilter error`, error);
3393
+ }
3394
+ }
3395
+ return exportedSpan;
3396
+ }
3367
3397
  /**
3368
3398
  * Emit a span started event.
3369
3399
  * Routes through the ObservabilityBus so exporters receive it via onTracingEvent.
@@ -3380,14 +3410,31 @@ var BaseObservabilityInstance = class extends base.MastraBase {
3380
3410
  * Emits any auto-extracted metrics while the live span tree is still available,
3381
3411
  * then routes the exported tracing event through the ObservabilityBus.
3382
3412
  */
3383
- emitSpanEnded(span) {
3384
- const exportedSpan = this.getSpanForExport(span);
3385
- if (exportedSpan) {
3413
+ emitSpanEnded(span, excludedModelUsage) {
3414
+ let processedSpan;
3415
+ let spanWasProcessed = false;
3416
+ if (span.isValid && !(span.isInternal && !this.config.includeInternalSpans)) {
3417
+ processedSpan = this.processSpan(span);
3418
+ spanWasProcessed = true;
3386
3419
  try {
3387
- emitAutoExtractedMetrics(span, this.getMetricsContext(span));
3420
+ if (processedSpan) {
3421
+ emitAutoExtractedMetrics(processedSpan, this.getMetricsContext(processedSpan));
3422
+ const processedAttrs = processedSpan.attributes;
3423
+ if (excludedModelUsage && !processedAttrs?.usage) {
3424
+ emitTokenMetricsForUsage(
3425
+ excludedModelUsage.usage,
3426
+ excludedModelUsage.provider,
3427
+ excludedModelUsage.model,
3428
+ this.getMetricsContext(processedSpan)
3429
+ );
3430
+ }
3431
+ }
3388
3432
  } catch (err) {
3389
3433
  this.logger.error("[Observability] Auto-extraction error:", err);
3390
3434
  }
3435
+ }
3436
+ const exportedSpan = spanWasProcessed ? processedSpan ? this.getProcessedSpanForExport(processedSpan) : void 0 : this.getSpanForExport(span);
3437
+ if (exportedSpan) {
3391
3438
  const event = { type: observability.TracingEventType.SPAN_ENDED, exportedSpan };
3392
3439
  this.emitTracingEvent(event);
3393
3440
  }
@@ -3423,6 +3470,26 @@ var BaseObservabilityInstance = class extends base.MastraBase {
3423
3470
  const model = endAttrs?.responseModel ?? endAttrs?.model ?? liveAttrs?.responseModel ?? liveAttrs?.model;
3424
3471
  return { ancestor, usage, provider, model };
3425
3472
  }
3473
+ /**
3474
+ * When a non-internal MODEL_GENERATION span is excluded by `excludeSpanTypes`,
3475
+ * the BaseSpan constructor clears start-time attributes and DefaultSpan.end()
3476
+ * drops end-time attributes before auto-extraction can read them. Capture
3477
+ * usage from end options and provider/model from the creation-time stash so
3478
+ * token and cost metrics still emit even though the trace span is filtered out.
3479
+ */
3480
+ captureExcludedModelUsage(span, endOptions) {
3481
+ if (span.type !== observability.SpanType.MODEL_GENERATION) return void 0;
3482
+ if (span.isInternal) return void 0;
3483
+ if (!this.config.excludeSpanTypes?.includes(observability.SpanType.MODEL_GENERATION)) return void 0;
3484
+ const endAttrs = endOptions?.attributes ?? void 0;
3485
+ const liveAttrs = span.attributes;
3486
+ const usage = endAttrs?.usage ?? liveAttrs?.usage;
3487
+ if (!usage) return void 0;
3488
+ const stashed = this.#excludedModelMeta.get(span);
3489
+ const provider = endAttrs?.provider ?? liveAttrs?.provider ?? stashed?.provider;
3490
+ const model = endAttrs?.responseModel ?? endAttrs?.model ?? liveAttrs?.responseModel ?? liveAttrs?.model ?? stashed?.model;
3491
+ return { usage, provider, model };
3492
+ }
3426
3493
  /**
3427
3494
  * Accumulate usage onto the ancestor's `internalUsage` attribute (for trace
3428
3495
  * UI visibility) and emit auto-extracted token metrics now, using the