@mastra/observability 1.12.0 → 1.13.0-alpha.1
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 +28 -0
- package/dist/exporters/default.d.ts.map +1 -1
- package/dist/exporters/mastra-storage.d.ts +2 -0
- package/dist/exporters/mastra-storage.d.ts.map +1 -1
- package/dist/features.d.ts.map +1 -1
- package/dist/index.cjs +179 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +179 -12
- package/dist/index.js.map +1 -1
- package/dist/instances/base.d.ts +35 -1
- package/dist/instances/base.d.ts.map +1 -1
- package/dist/metrics/auto-extract.d.ts +11 -1
- package/dist/metrics/auto-extract.d.ts.map +1 -1
- package/dist/usage.d.ts +7 -0
- package/dist/usage.d.ts.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -16012,7 +16012,10 @@ var DefaultExporter = class extends BaseExporter {
|
|
|
16012
16012
|
deferredUpdates.length = 0;
|
|
16013
16013
|
this.emitDrop("tracing", "unsupported-storage", events.length + deferredCountAtEntry, error48);
|
|
16014
16014
|
} else {
|
|
16015
|
-
deferredUpdates.length
|
|
16015
|
+
const newlyDeferred = deferredUpdates.length - deferredCountAtEntry;
|
|
16016
|
+
if (newlyDeferred > 0) {
|
|
16017
|
+
deferredUpdates.splice(deferredUpdates.length - newlyDeferred, newlyDeferred);
|
|
16018
|
+
}
|
|
16016
16019
|
const dropped = this.#eventBuffer.reAddUpdates(events);
|
|
16017
16020
|
this.emitDrop("tracing", "retry-exhausted", dropped.length, error48);
|
|
16018
16021
|
}
|
|
@@ -16711,6 +16714,7 @@ var MastraStorageExporter = class extends BaseExporter {
|
|
|
16711
16714
|
#observabilityStorage;
|
|
16712
16715
|
#resolvedStrategy;
|
|
16713
16716
|
#flushTimer;
|
|
16717
|
+
#emitDropEvent;
|
|
16714
16718
|
// Signals whose storage methods threw "not implemented" — skip on future flushes
|
|
16715
16719
|
#unsupportedSignals = /* @__PURE__ */ new Set();
|
|
16716
16720
|
constructor(config2 = {}) {
|
|
@@ -16732,6 +16736,7 @@ var MastraStorageExporter = class extends BaseExporter {
|
|
|
16732
16736
|
async init(options) {
|
|
16733
16737
|
try {
|
|
16734
16738
|
this.#isInitializing = true;
|
|
16739
|
+
this.#emitDropEvent = options.emitDropEvent;
|
|
16735
16740
|
this.#storage = options.mastra?.getStorage();
|
|
16736
16741
|
if (!this.#storage) {
|
|
16737
16742
|
this.logger.warn("MastraStorageExporter disabled: Storage not available. Traces will not be persisted.");
|
|
@@ -16817,21 +16822,54 @@ var MastraStorageExporter = class extends BaseExporter {
|
|
|
16817
16822
|
this.scheduleFlush();
|
|
16818
16823
|
}
|
|
16819
16824
|
}
|
|
16825
|
+
sanitizeDropError(error48) {
|
|
16826
|
+
if (error48 instanceof MastraError) {
|
|
16827
|
+
return {
|
|
16828
|
+
id: error48.id,
|
|
16829
|
+
domain: String(error48.domain),
|
|
16830
|
+
message: error48.message
|
|
16831
|
+
};
|
|
16832
|
+
}
|
|
16833
|
+
if (error48 instanceof Error) {
|
|
16834
|
+
return { message: error48.message };
|
|
16835
|
+
}
|
|
16836
|
+
return { message: String(error48) };
|
|
16837
|
+
}
|
|
16838
|
+
emitDrop(signal, reason, count, error48) {
|
|
16839
|
+
if (count === 0) return;
|
|
16840
|
+
const dropEvent = {
|
|
16841
|
+
type: "drop",
|
|
16842
|
+
signal,
|
|
16843
|
+
reason,
|
|
16844
|
+
count,
|
|
16845
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
16846
|
+
exporterName: this.name,
|
|
16847
|
+
...this.#observabilityStorage ? { storageName: this.#observabilityStorage.constructor.name } : {},
|
|
16848
|
+
...error48 === void 0 ? {} : { error: this.sanitizeDropError(error48) }
|
|
16849
|
+
};
|
|
16850
|
+
this.#emitDropEvent?.(dropEvent);
|
|
16851
|
+
}
|
|
16820
16852
|
/**
|
|
16821
16853
|
* Flush a batch of create events for a single signal type.
|
|
16822
16854
|
* On "not implemented" errors, disables the signal for future flushes.
|
|
16823
16855
|
* On other errors, re-adds events to the buffer for retry.
|
|
16824
16856
|
*/
|
|
16825
16857
|
async flushCreates(signal, events, storageCall) {
|
|
16826
|
-
if (
|
|
16858
|
+
if (events.length === 0) return;
|
|
16859
|
+
if (this.#unsupportedSignals.has(signal)) {
|
|
16860
|
+
this.emitDrop(signal, "unsupported-storage", events.length);
|
|
16861
|
+
return;
|
|
16862
|
+
}
|
|
16827
16863
|
try {
|
|
16828
16864
|
await storageCall(events);
|
|
16829
16865
|
} catch (error48) {
|
|
16830
16866
|
if (error48 instanceof MastraError && error48.domain === ErrorDomain.MASTRA_OBSERVABILITY && error48.id.endsWith("_NOT_IMPLEMENTED")) {
|
|
16831
16867
|
this.logger.warn(error48.message);
|
|
16832
16868
|
this.#unsupportedSignals.add(signal);
|
|
16869
|
+
this.emitDrop(signal, "unsupported-storage", events.length, error48);
|
|
16833
16870
|
} else {
|
|
16834
|
-
this.#eventBuffer.reAddCreates(events);
|
|
16871
|
+
const dropped = this.#eventBuffer.reAddCreates(events);
|
|
16872
|
+
this.emitDrop(signal, "retry-exhausted", dropped.length, error48);
|
|
16835
16873
|
}
|
|
16836
16874
|
}
|
|
16837
16875
|
}
|
|
@@ -16840,7 +16878,12 @@ var MastraStorageExporter = class extends BaseExporter {
|
|
|
16840
16878
|
* When `isEnd` is true, successfully flushed spans are removed from tracking.
|
|
16841
16879
|
*/
|
|
16842
16880
|
async flushSpanUpdates(events, deferredUpdates, isEnd) {
|
|
16843
|
-
|
|
16881
|
+
const deferredCountAtEntry = deferredUpdates.length;
|
|
16882
|
+
if (events.length === 0) return;
|
|
16883
|
+
if (this.#unsupportedSignals.has("tracing")) {
|
|
16884
|
+
this.emitDrop("tracing", "unsupported-storage", events.length);
|
|
16885
|
+
return;
|
|
16886
|
+
}
|
|
16844
16887
|
const partials = [];
|
|
16845
16888
|
for (const event of events) {
|
|
16846
16889
|
const span = event.exportedSpan;
|
|
@@ -16864,9 +16907,15 @@ var MastraStorageExporter = class extends BaseExporter {
|
|
|
16864
16907
|
if (error48 instanceof MastraError && error48.domain === ErrorDomain.MASTRA_OBSERVABILITY && error48.id.endsWith("_NOT_IMPLEMENTED")) {
|
|
16865
16908
|
this.logger.warn(error48.message);
|
|
16866
16909
|
this.#unsupportedSignals.add("tracing");
|
|
16867
|
-
} else {
|
|
16868
16910
|
deferredUpdates.length = 0;
|
|
16869
|
-
this
|
|
16911
|
+
this.emitDrop("tracing", "unsupported-storage", events.length + deferredCountAtEntry, error48);
|
|
16912
|
+
} else {
|
|
16913
|
+
const newlyDeferred = deferredUpdates.length - deferredCountAtEntry;
|
|
16914
|
+
if (newlyDeferred > 0) {
|
|
16915
|
+
deferredUpdates.splice(deferredUpdates.length - newlyDeferred, newlyDeferred);
|
|
16916
|
+
}
|
|
16917
|
+
const dropped = this.#eventBuffer.reAddUpdates(events);
|
|
16918
|
+
this.emitDrop("tracing", "retry-exhausted", dropped.length, error48);
|
|
16870
16919
|
}
|
|
16871
16920
|
}
|
|
16872
16921
|
}
|
|
@@ -16942,17 +16991,17 @@ var MastraStorageExporter = class extends BaseExporter {
|
|
|
16942
16991
|
(events) => this.#observabilityStorage.batchCreateFeedback({ feedbacks: events.map((f) => buildFeedbackRecord(f)) })
|
|
16943
16992
|
),
|
|
16944
16993
|
this.flushCreates(
|
|
16945
|
-
"
|
|
16994
|
+
"log",
|
|
16946
16995
|
createLogEvents,
|
|
16947
16996
|
(events) => this.#observabilityStorage.batchCreateLogs({ logs: events.map((l) => buildLogRecord(l)) })
|
|
16948
16997
|
),
|
|
16949
16998
|
this.flushCreates(
|
|
16950
|
-
"
|
|
16999
|
+
"metric",
|
|
16951
17000
|
createMetricEvents,
|
|
16952
17001
|
(events) => this.#observabilityStorage.batchCreateMetrics({ metrics: events.map((m) => buildMetricRecord(m)) })
|
|
16953
17002
|
),
|
|
16954
17003
|
this.flushCreates(
|
|
16955
|
-
"
|
|
17004
|
+
"score",
|
|
16956
17005
|
createScoreEvents,
|
|
16957
17006
|
(events) => this.#observabilityStorage.batchCreateScores({ scores: events.map((s) => buildScoreRecord(s)) })
|
|
16958
17007
|
),
|
|
@@ -16966,7 +17015,13 @@ var MastraStorageExporter = class extends BaseExporter {
|
|
|
16966
17015
|
await this.flushSpanUpdates(updateSpanEvents, deferredUpdates, false);
|
|
16967
17016
|
await this.flushSpanUpdates(endSpanEvents, deferredUpdates, true);
|
|
16968
17017
|
if (deferredUpdates.length > 0) {
|
|
16969
|
-
this.#
|
|
17018
|
+
if (this.#unsupportedSignals.has("tracing")) {
|
|
17019
|
+
this.emitDrop("tracing", "unsupported-storage", deferredUpdates.length);
|
|
17020
|
+
deferredUpdates.length = 0;
|
|
17021
|
+
} else {
|
|
17022
|
+
const dropped = this.#eventBuffer.reAddUpdates(deferredUpdates);
|
|
17023
|
+
this.emitDrop("tracing", "retry-exhausted", dropped.length);
|
|
17024
|
+
}
|
|
16970
17025
|
}
|
|
16971
17026
|
const elapsed = Date.now() - startTime;
|
|
16972
17027
|
this.logger.debug("Batch flushed", {
|
|
@@ -19021,6 +19076,7 @@ var PricingRegistry = class _PricingRegistry {
|
|
|
19021
19076
|
constructor(pricingModels) {
|
|
19022
19077
|
this.pricingModels = pricingModels;
|
|
19023
19078
|
}
|
|
19079
|
+
pricingModels;
|
|
19024
19080
|
static globalRegistry = null;
|
|
19025
19081
|
static fromText(pricingModelText) {
|
|
19026
19082
|
return new _PricingRegistry(parsePricingModelText(pricingModelText));
|
|
@@ -19424,6 +19480,9 @@ function emitTokenMetrics(span, metrics) {
|
|
|
19424
19480
|
}
|
|
19425
19481
|
emitUsageMetrics(attrs, attrs.usage, metrics);
|
|
19426
19482
|
}
|
|
19483
|
+
function emitTokenMetricsForUsage(usage, provider, model, metrics) {
|
|
19484
|
+
emitUsageMetrics({ provider, model }, usage, metrics);
|
|
19485
|
+
}
|
|
19427
19486
|
function emitAutoExtractedMetrics(span, metrics) {
|
|
19428
19487
|
emitDurationMetrics(span, metrics);
|
|
19429
19488
|
emitTokenMetrics(span, metrics);
|
|
@@ -19585,6 +19644,46 @@ function extractUsageMetrics(usage, providerMetadata) {
|
|
|
19585
19644
|
function sumDefinedValues(obj, keys) {
|
|
19586
19645
|
return keys.reduce((sum, key) => sum + (obj[key] ?? 0), 0);
|
|
19587
19646
|
}
|
|
19647
|
+
function addOptional(a, b) {
|
|
19648
|
+
if (a === void 0 && b === void 0) return void 0;
|
|
19649
|
+
return (a ?? 0) + (b ?? 0);
|
|
19650
|
+
}
|
|
19651
|
+
function mergeInputDetails(a, b) {
|
|
19652
|
+
if (!a) return b ? { ...b } : void 0;
|
|
19653
|
+
if (!b) return { ...a };
|
|
19654
|
+
return {
|
|
19655
|
+
text: addOptional(a.text, b.text),
|
|
19656
|
+
cacheRead: addOptional(a.cacheRead, b.cacheRead),
|
|
19657
|
+
cacheWrite: addOptional(a.cacheWrite, b.cacheWrite),
|
|
19658
|
+
audio: addOptional(a.audio, b.audio),
|
|
19659
|
+
image: addOptional(a.image, b.image)
|
|
19660
|
+
};
|
|
19661
|
+
}
|
|
19662
|
+
function mergeOutputDetails(a, b) {
|
|
19663
|
+
if (!a) return b ? { ...b } : void 0;
|
|
19664
|
+
if (!b) return { ...a };
|
|
19665
|
+
return {
|
|
19666
|
+
text: addOptional(a.text, b.text),
|
|
19667
|
+
reasoning: addOptional(a.reasoning, b.reasoning),
|
|
19668
|
+
audio: addOptional(a.audio, b.audio),
|
|
19669
|
+
image: addOptional(a.image, b.image)
|
|
19670
|
+
};
|
|
19671
|
+
}
|
|
19672
|
+
function addUsageStats(a, b) {
|
|
19673
|
+
if (!a) {
|
|
19674
|
+
return {
|
|
19675
|
+
...b,
|
|
19676
|
+
inputDetails: b.inputDetails ? { ...b.inputDetails } : void 0,
|
|
19677
|
+
outputDetails: b.outputDetails ? { ...b.outputDetails } : void 0
|
|
19678
|
+
};
|
|
19679
|
+
}
|
|
19680
|
+
return {
|
|
19681
|
+
inputTokens: addOptional(a.inputTokens, b.inputTokens),
|
|
19682
|
+
outputTokens: addOptional(a.outputTokens, b.outputTokens),
|
|
19683
|
+
inputDetails: mergeInputDetails(a.inputDetails, b.inputDetails),
|
|
19684
|
+
outputDetails: mergeOutputDetails(a.outputDetails, b.outputDetails)
|
|
19685
|
+
};
|
|
19686
|
+
}
|
|
19588
19687
|
|
|
19589
19688
|
// src/model-tracing.ts
|
|
19590
19689
|
function supportsModelInference() {
|
|
@@ -21114,7 +21213,7 @@ var BaseObservabilityInstance = class extends MastraBase {
|
|
|
21114
21213
|
* This ensures all spans emit events regardless of implementation
|
|
21115
21214
|
*/
|
|
21116
21215
|
wireSpanLifecycle(span) {
|
|
21117
|
-
if (!this.config.includeInternalSpans && span.isInternal) {
|
|
21216
|
+
if (!this.config.includeInternalSpans && span.isInternal && span.type !== SpanType.MODEL_GENERATION) {
|
|
21118
21217
|
return;
|
|
21119
21218
|
}
|
|
21120
21219
|
const originalEnd = span.end.bind(span);
|
|
@@ -21124,7 +21223,11 @@ var BaseObservabilityInstance = class extends MastraBase {
|
|
|
21124
21223
|
this.logger.warn(`End event is not available on event spans`);
|
|
21125
21224
|
return;
|
|
21126
21225
|
}
|
|
21226
|
+
const rollupTarget = this.captureModelUsageRollup(span, options);
|
|
21127
21227
|
originalEnd(options);
|
|
21228
|
+
if (rollupTarget) {
|
|
21229
|
+
this.applyUsageRollup(rollupTarget);
|
|
21230
|
+
}
|
|
21128
21231
|
this.emitSpanEnded(span);
|
|
21129
21232
|
};
|
|
21130
21233
|
span.update = (options) => {
|
|
@@ -21298,6 +21401,70 @@ var BaseObservabilityInstance = class extends MastraBase {
|
|
|
21298
21401
|
this.emitTracingEvent(event);
|
|
21299
21402
|
}
|
|
21300
21403
|
}
|
|
21404
|
+
/**
|
|
21405
|
+
* When an internal MODEL_GENERATION span ends, capture the rollup payload
|
|
21406
|
+
* (usage, provider, model, target ancestor) needed to attribute its cost
|
|
21407
|
+
* to the closest exported ancestor span. Returns undefined when no rollup
|
|
21408
|
+
* applies — non-MODEL_GENERATION spans, spans that will be exported, or
|
|
21409
|
+
* spans whose usage isn't available at end time.
|
|
21410
|
+
*/
|
|
21411
|
+
captureModelUsageRollup(span, endOptions) {
|
|
21412
|
+
if (span.type !== SpanType.MODEL_GENERATION) return void 0;
|
|
21413
|
+
if (!span.isInternal || this.config.includeInternalSpans) return void 0;
|
|
21414
|
+
const endAttrs = endOptions?.attributes ?? void 0;
|
|
21415
|
+
const liveAttrs = span.attributes;
|
|
21416
|
+
const usage = endAttrs?.usage ?? liveAttrs?.usage;
|
|
21417
|
+
if (!usage) return void 0;
|
|
21418
|
+
const ancestor = this.findExportedAncestor(span);
|
|
21419
|
+
if (!ancestor) return void 0;
|
|
21420
|
+
const provider = endAttrs?.provider ?? liveAttrs?.provider;
|
|
21421
|
+
const model = endAttrs?.responseModel ?? endAttrs?.model ?? liveAttrs?.responseModel ?? liveAttrs?.model;
|
|
21422
|
+
return { ancestor, usage, provider, model };
|
|
21423
|
+
}
|
|
21424
|
+
/**
|
|
21425
|
+
* Accumulate usage onto the ancestor's `internalUsage` attribute (for trace
|
|
21426
|
+
* UI visibility) and emit auto-extracted token metrics now, using the
|
|
21427
|
+
* ancestor's metrics context so cost / token labels point at the visible
|
|
21428
|
+
* span instead of the hidden agent that incurred them.
|
|
21429
|
+
*/
|
|
21430
|
+
applyUsageRollup(target) {
|
|
21431
|
+
const { ancestor, usage, provider, model } = target;
|
|
21432
|
+
const attrs = ancestor.attributes;
|
|
21433
|
+
attrs.internalUsage = addUsageStats(attrs.internalUsage, usage);
|
|
21434
|
+
try {
|
|
21435
|
+
emitTokenMetricsForUsage(usage, provider, model, this.getMetricsContext(ancestor));
|
|
21436
|
+
} catch (err) {
|
|
21437
|
+
this.logger.error("[Observability] Usage rollup metric emission error:", err);
|
|
21438
|
+
}
|
|
21439
|
+
}
|
|
21440
|
+
/**
|
|
21441
|
+
* Walk up the parent chain to find the closest ancestor that will actually
|
|
21442
|
+
* reach exporters. Skips both internal-filtered ancestors and ancestors
|
|
21443
|
+
* whose type matches `excludeSpanTypes`, so the rollup target is one whose
|
|
21444
|
+
* mutated `internalUsage` attribute is visible in exported traces.
|
|
21445
|
+
*
|
|
21446
|
+
* Note: this does not preemptively run `spanFilter` — that filter can be
|
|
21447
|
+
* async and have side effects, so the rare case of a `spanFilter`-dropped
|
|
21448
|
+
* ancestor falls through.
|
|
21449
|
+
*/
|
|
21450
|
+
findExportedAncestor(span) {
|
|
21451
|
+
let ancestor = span.parent;
|
|
21452
|
+
while (ancestor && this.isFilteredFromExport(ancestor)) {
|
|
21453
|
+
ancestor = ancestor.parent;
|
|
21454
|
+
}
|
|
21455
|
+
return ancestor;
|
|
21456
|
+
}
|
|
21457
|
+
/**
|
|
21458
|
+
* Returns true when a span would be dropped by `getSpanForExport` for a
|
|
21459
|
+
* reason cheap to check up-front (internal-span filtering or
|
|
21460
|
+
* `excludeSpanTypes`). Used by `findExportedAncestor` to skip rollup
|
|
21461
|
+
* targets that would silently lose their `internalUsage` attribute.
|
|
21462
|
+
*/
|
|
21463
|
+
isFilteredFromExport(span) {
|
|
21464
|
+
if (span.isInternal && !this.config.includeInternalSpans) return true;
|
|
21465
|
+
if (this.config.excludeSpanTypes?.includes(span.type)) return true;
|
|
21466
|
+
return false;
|
|
21467
|
+
}
|
|
21301
21468
|
/**
|
|
21302
21469
|
* Emit a tracing event through the bus.
|
|
21303
21470
|
*
|
|
@@ -22248,7 +22415,7 @@ var Observability = class extends MastraBase {
|
|
|
22248
22415
|
};
|
|
22249
22416
|
|
|
22250
22417
|
// src/features.ts
|
|
22251
|
-
var observabilityFeatures = /* @__PURE__ */ new Set(["model-inference-span"]);
|
|
22418
|
+
var observabilityFeatures = /* @__PURE__ */ new Set(["model-inference-span", "internal-usage-rollup"]);
|
|
22252
22419
|
|
|
22253
22420
|
// src/tracing-options.ts
|
|
22254
22421
|
function buildTracingOptions(...updaters) {
|