@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/CHANGELOG.md +29 -0
- package/dist/index.cjs +27 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +27 -2
- package/dist/index.js.map +1 -1
- package/dist/instances/base.d.ts.map +1 -1
- package/dist/spans/base.d.ts +5 -0
- package/dist/spans/base.d.ts.map +1 -1
- package/dist/spans/default.d.ts.map +1 -1
- package/dist/spans/serialization.d.ts +6 -0
- package/dist/spans/serialization.d.ts.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# @mastra/observability
|
|
2
2
|
|
|
3
|
+
## 1.17.2-alpha.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Added `span.endTree()` for closing a span together with every descendant span that is still open, so an operation that is abandoned rather than completed can still emit a full trace. The options you pass are applied to every span it closes, so a force-closed child is distinguishable from one that finished on its own. ([#22278](https://github.com/mastra-ai/mastra/pull/22278))
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// Ends the span and any child spans still open beneath it, marking each canceled
|
|
11
|
+
workflowSpan.endTree({ attributes: { status: 'canceled' } });
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Repeat calls to `span.end()` are now ignored. A span that was force-closed this way keeps the state it was closed with and reports its end exactly once, even if the work it covered finishes later and ends the span again.
|
|
15
|
+
|
|
16
|
+
- Updated dependencies [[`b05f486`](https://github.com/mastra-ai/mastra/commit/b05f48612984d5fe2447ea2d6cdd5c604d285b97), [`7960688`](https://github.com/mastra-ai/mastra/commit/7960688828e04eaf3106e34f7758fa580257eef6)]:
|
|
17
|
+
- @mastra/core@1.62.0-alpha.10
|
|
18
|
+
|
|
19
|
+
## 1.17.2-alpha.1
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- Fix PostgreSQL observability writes failing on NUL characters and unpaired Unicode surrogates ([#21728](https://github.com/mastra-ai/mastra/pull/21728))
|
|
24
|
+
|
|
25
|
+
Span serialization truncated strings by UTF-16 code unit, so a cut inside an emoji left a lone surrogate that PostgreSQL rejected on the jsonb cast (`22P02`). NUL characters were rejected as well (`22P05`). Because observability events are inserted as a single multi-row statement, one malformed field discarded the entire batch.
|
|
26
|
+
|
|
27
|
+
Truncation now preserves complete surrogate pairs, and the v-next PostgreSQL observability encoder sanitizes NUL and unpaired surrogates before the jsonb cast, using the same sanitizer that workflow snapshots already rely on. Valid Unicode, including complete emoji, is preserved.
|
|
28
|
+
|
|
29
|
+
- Updated dependencies [[`2c85f42`](https://github.com/mastra-ai/mastra/commit/2c85f428e04ccd63ea31a7ec80b5b327afdad555), [`11bbeb9`](https://github.com/mastra-ai/mastra/commit/11bbeb9b108ef2264e05acefc6dafb9cbb342921), [`1a485f3`](https://github.com/mastra-ai/mastra/commit/1a485f3538f5ec64d58bd8b5e1e99de0c695c87b), [`0d37487`](https://github.com/mastra-ai/mastra/commit/0d37487d9f349388a3f1cef6a536cf9dcc4b6273), [`8661d7d`](https://github.com/mastra-ai/mastra/commit/8661d7d7179f0a024456aabdd8679bcecd09ac28), [`575e343`](https://github.com/mastra-ai/mastra/commit/575e343900451021d96110916497d334af7bc252), [`cacb839`](https://github.com/mastra-ai/mastra/commit/cacb8392d9e74189b56d857290b0615f98a2683d), [`b47b26e`](https://github.com/mastra-ai/mastra/commit/b47b26e6fe95cb8a3482be2c5e52de157fe59d0b), [`0d37487`](https://github.com/mastra-ai/mastra/commit/0d37487d9f349388a3f1cef6a536cf9dcc4b6273), [`c46eb09`](https://github.com/mastra-ai/mastra/commit/c46eb09ce4987509af57a0ac582c61241a6dd2f1), [`30ed33e`](https://github.com/mastra-ai/mastra/commit/30ed33ee14084a26019aba15fceadda6d6ddefaf), [`91ad69d`](https://github.com/mastra-ai/mastra/commit/91ad69d64994c89199b0c55399e64ed91c61df2f), [`8dc408d`](https://github.com/mastra-ai/mastra/commit/8dc408d34438f9e13297f792c11a5cfd6cf952e1), [`c92def1`](https://github.com/mastra-ai/mastra/commit/c92def10a13c822972c96f0a4ca6ffc1f4258aed), [`c5eaec5`](https://github.com/mastra-ai/mastra/commit/c5eaec5a860d80d0e3805e67db0414b87ac8cbed), [`e66b2ba`](https://github.com/mastra-ai/mastra/commit/e66b2ba100db63eaeab6e21e1ea34b113f2ec781)]:
|
|
30
|
+
- @mastra/core@1.62.0-alpha.3
|
|
31
|
+
|
|
3
32
|
## 1.17.2-alpha.0
|
|
4
33
|
|
|
5
34
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -246,10 +246,18 @@ function mergeSerializationOptions(userOptions) {
|
|
|
246
246
|
}
|
|
247
247
|
/**
|
|
248
248
|
* Hard-cap any string to prevent unbounded growth.
|
|
249
|
+
*
|
|
250
|
+
* The cut never splits a UTF-16 surrogate pair: if it would land immediately
|
|
251
|
+
* after a lone high surrogate (U+D800..U+DBFF), it backs off one code unit so
|
|
252
|
+
* the pair is dropped as a whole. `JSON.stringify` emits a lone `\ud83d` for a
|
|
253
|
+
* split pair, which PostgreSQL rejects on a jsonb cast with 22P02
|
|
254
|
+
* ("Unicode low surrogate must follow a high surrogate").
|
|
249
255
|
*/
|
|
250
256
|
function truncateString(s, maxChars) {
|
|
251
257
|
if (s.length <= maxChars) return s;
|
|
252
|
-
|
|
258
|
+
const code = s.charCodeAt(maxChars - 1);
|
|
259
|
+
const safeEnd = code >= 55296 && code <= 56319 ? maxChars - 1 : maxChars;
|
|
260
|
+
return s.slice(0, safeEnd) + "…[truncated]";
|
|
253
261
|
}
|
|
254
262
|
function formatSerializationError(error) {
|
|
255
263
|
return `[${error instanceof Error ? truncateString(error.message, 256) : "unknown error"}]`;
|
|
@@ -2710,7 +2718,7 @@ function getExternalParentId(options) {
|
|
|
2710
2718
|
if (parent.isInternal || parent.isExcluded) return parent.getParentSpanId(false);
|
|
2711
2719
|
return parent.id;
|
|
2712
2720
|
}
|
|
2713
|
-
var BaseSpan = class {
|
|
2721
|
+
var BaseSpan = class BaseSpan {
|
|
2714
2722
|
name;
|
|
2715
2723
|
type;
|
|
2716
2724
|
attributes;
|
|
@@ -2760,6 +2768,8 @@ var BaseSpan = class {
|
|
|
2760
2768
|
isExcluded;
|
|
2761
2769
|
/** Cached canonical correlation context for this live span */
|
|
2762
2770
|
correlationContext;
|
|
2771
|
+
/** Child spans that have started but not yet ended */
|
|
2772
|
+
#openChildren;
|
|
2763
2773
|
/**
|
|
2764
2774
|
* Subclasses can override to unconditionally mark the span as excluded.
|
|
2765
2775
|
* NoOpSpan uses this because it is never exported regardless of config.
|
|
@@ -2781,6 +2791,8 @@ var BaseSpan = class {
|
|
|
2781
2791
|
this.isEvent = options.isEvent ?? false;
|
|
2782
2792
|
this.tracingPolicy = options.tracingPolicy;
|
|
2783
2793
|
this.traceState = options.traceState;
|
|
2794
|
+
const parent = options.parent;
|
|
2795
|
+
if (!this.isEvent && parent instanceof BaseSpan && parent.isValid) (parent.#openChildren ??= /* @__PURE__ */ new Set()).add(this);
|
|
2784
2796
|
this.tags = !options.parent && options.tags?.length ? options.tags : void 0;
|
|
2785
2797
|
const entityParent = this.getParentSpan(false);
|
|
2786
2798
|
this.entityType = options.entityType ?? entityParent?.entityType;
|
|
@@ -2818,6 +2830,16 @@ var BaseSpan = class {
|
|
|
2818
2830
|
return value;
|
|
2819
2831
|
}
|
|
2820
2832
|
}
|
|
2833
|
+
/** End the span and any descendant spans that are still open, applying `options` to each */
|
|
2834
|
+
endTree(options) {
|
|
2835
|
+
if (this.#openChildren) for (const child of [...this.#openChildren]) child.endTree(options);
|
|
2836
|
+
this.end(options);
|
|
2837
|
+
}
|
|
2838
|
+
/** Release this span from its parent's open-child set once it has ended */
|
|
2839
|
+
detachFromParent() {
|
|
2840
|
+
const parent = this.parent;
|
|
2841
|
+
if (parent instanceof BaseSpan) parent.#openChildren?.delete(this);
|
|
2842
|
+
}
|
|
2821
2843
|
createChildSpan(options) {
|
|
2822
2844
|
return this.observabilityInstance.startSpan({
|
|
2823
2845
|
...options,
|
|
@@ -3021,7 +3043,9 @@ var DefaultSpan = class extends BaseSpan {
|
|
|
3021
3043
|
}
|
|
3022
3044
|
end(options) {
|
|
3023
3045
|
if (this.isEvent) return;
|
|
3046
|
+
if (this.endTime) return;
|
|
3024
3047
|
this.endTime = /* @__PURE__ */ new Date();
|
|
3048
|
+
this.detachFromParent();
|
|
3025
3049
|
if (options?.metadata) this.metadata = {
|
|
3026
3050
|
...this.metadata,
|
|
3027
3051
|
...deepClean(this.prepareSpanMetadata(options.metadata), this.deepCleanOptions)
|
|
@@ -3477,6 +3501,7 @@ var BaseObservabilityInstance = class extends _mastra_core_base.MastraBase {
|
|
|
3477
3501
|
this.logger.warn(`End event is not available on event spans`);
|
|
3478
3502
|
return;
|
|
3479
3503
|
}
|
|
3504
|
+
if (span.endTime) return;
|
|
3480
3505
|
const rollupTarget = this.captureModelUsageRollup(span, options);
|
|
3481
3506
|
const excludedModelUsage = this.captureExcludedModelUsage(span, options);
|
|
3482
3507
|
originalEnd(options);
|