@mastra/observability 1.17.2-alpha.0 → 1.17.2-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/dist/index.js CHANGED
@@ -221,10 +221,18 @@ function mergeSerializationOptions(userOptions) {
221
221
  }
222
222
  /**
223
223
  * Hard-cap any string to prevent unbounded growth.
224
+ *
225
+ * The cut never splits a UTF-16 surrogate pair: if it would land immediately
226
+ * after a lone high surrogate (U+D800..U+DBFF), it backs off one code unit so
227
+ * the pair is dropped as a whole. `JSON.stringify` emits a lone `\ud83d` for a
228
+ * split pair, which PostgreSQL rejects on a jsonb cast with 22P02
229
+ * ("Unicode low surrogate must follow a high surrogate").
224
230
  */
225
231
  function truncateString(s, maxChars) {
226
232
  if (s.length <= maxChars) return s;
227
- return s.slice(0, maxChars) + "…[truncated]";
233
+ const code = s.charCodeAt(maxChars - 1);
234
+ const safeEnd = code >= 55296 && code <= 56319 ? maxChars - 1 : maxChars;
235
+ return s.slice(0, safeEnd) + "…[truncated]";
228
236
  }
229
237
  function formatSerializationError(error) {
230
238
  return `[${error instanceof Error ? truncateString(error.message, 256) : "unknown error"}]`;
@@ -2685,7 +2693,7 @@ function getExternalParentId(options) {
2685
2693
  if (parent.isInternal || parent.isExcluded) return parent.getParentSpanId(false);
2686
2694
  return parent.id;
2687
2695
  }
2688
- var BaseSpan = class {
2696
+ var BaseSpan = class BaseSpan {
2689
2697
  name;
2690
2698
  type;
2691
2699
  attributes;
@@ -2735,6 +2743,8 @@ var BaseSpan = class {
2735
2743
  isExcluded;
2736
2744
  /** Cached canonical correlation context for this live span */
2737
2745
  correlationContext;
2746
+ /** Child spans that have started but not yet ended */
2747
+ #openChildren;
2738
2748
  /**
2739
2749
  * Subclasses can override to unconditionally mark the span as excluded.
2740
2750
  * NoOpSpan uses this because it is never exported regardless of config.
@@ -2756,6 +2766,8 @@ var BaseSpan = class {
2756
2766
  this.isEvent = options.isEvent ?? false;
2757
2767
  this.tracingPolicy = options.tracingPolicy;
2758
2768
  this.traceState = options.traceState;
2769
+ const parent = options.parent;
2770
+ if (!this.isEvent && parent instanceof BaseSpan && parent.isValid) (parent.#openChildren ??= /* @__PURE__ */ new Set()).add(this);
2759
2771
  this.tags = !options.parent && options.tags?.length ? options.tags : void 0;
2760
2772
  const entityParent = this.getParentSpan(false);
2761
2773
  this.entityType = options.entityType ?? entityParent?.entityType;
@@ -2793,6 +2805,16 @@ var BaseSpan = class {
2793
2805
  return value;
2794
2806
  }
2795
2807
  }
2808
+ /** End the span and any descendant spans that are still open, applying `options` to each */
2809
+ endTree(options) {
2810
+ if (this.#openChildren) for (const child of [...this.#openChildren]) child.endTree(options);
2811
+ this.end(options);
2812
+ }
2813
+ /** Release this span from its parent's open-child set once it has ended */
2814
+ detachFromParent() {
2815
+ const parent = this.parent;
2816
+ if (parent instanceof BaseSpan) parent.#openChildren?.delete(this);
2817
+ }
2796
2818
  createChildSpan(options) {
2797
2819
  return this.observabilityInstance.startSpan({
2798
2820
  ...options,
@@ -2996,7 +3018,9 @@ var DefaultSpan = class extends BaseSpan {
2996
3018
  }
2997
3019
  end(options) {
2998
3020
  if (this.isEvent) return;
3021
+ if (this.endTime) return;
2999
3022
  this.endTime = /* @__PURE__ */ new Date();
3023
+ this.detachFromParent();
3000
3024
  if (options?.metadata) this.metadata = {
3001
3025
  ...this.metadata,
3002
3026
  ...deepClean(this.prepareSpanMetadata(options.metadata), this.deepCleanOptions)
@@ -3452,6 +3476,7 @@ var BaseObservabilityInstance = class extends MastraBase {
3452
3476
  this.logger.warn(`End event is not available on event spans`);
3453
3477
  return;
3454
3478
  }
3479
+ if (span.endTime) return;
3455
3480
  const rollupTarget = this.captureModelUsageRollup(span, options);
3456
3481
  const excludedModelUsage = this.captureExcludedModelUsage(span, options);
3457
3482
  originalEnd(options);