@mastra/observability 1.5.1 → 1.6.0-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 +18 -0
- package/dist/bus/observability-bus.d.ts +4 -21
- package/dist/bus/observability-bus.d.ts.map +1 -1
- package/dist/context/logger.d.ts +6 -10
- package/dist/context/logger.d.ts.map +1 -1
- package/dist/context/metrics.d.ts +18 -11
- package/dist/context/metrics.d.ts.map +1 -1
- package/dist/exporters/test.d.ts.map +1 -1
- package/dist/index.cjs +701 -267
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +698 -268
- package/dist/index.js.map +1 -1
- package/dist/instances/base.d.ts +6 -22
- package/dist/instances/base.d.ts.map +1 -1
- package/dist/metrics/auto-extract.d.ts +8 -28
- package/dist/metrics/auto-extract.d.ts.map +1 -1
- package/dist/metrics/estimator.d.ts +9 -0
- package/dist/metrics/estimator.d.ts.map +1 -0
- package/dist/metrics/index.d.ts +0 -1
- package/dist/metrics/index.d.ts.map +1 -1
- package/dist/metrics/pricing-data.jsonl +4682 -0
- package/dist/metrics/pricing-model.d.ts +43 -0
- package/dist/metrics/pricing-model.d.ts.map +1 -0
- package/dist/metrics/pricing-registry.d.ts +13 -0
- package/dist/metrics/pricing-registry.d.ts.map +1 -0
- package/dist/metrics/types.d.ts +29 -0
- package/dist/metrics/types.d.ts.map +1 -0
- package/dist/metrics/usage-metrics.d.ts +8 -0
- package/dist/metrics/usage-metrics.d.ts.map +1 -0
- package/dist/spans/base.d.ts +5 -1
- package/dist/spans/base.d.ts.map +1 -1
- package/dist/usage.d.ts.map +1 -1
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { MastraBase } from '@mastra/core/base';
|
|
2
2
|
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
3
3
|
import { ConsoleLogger, LogLevel, RegisteredLogger } from '@mastra/core/logger';
|
|
4
|
-
import { TracingEventType,
|
|
4
|
+
import { TracingEventType, DEFAULT_BLOCKED_LABELS, SpanType, InternalSpans } from '@mastra/core/observability';
|
|
5
5
|
import { fetchWithRetry, getNestedValue, setNestedValue } from '@mastra/core/utils';
|
|
6
6
|
import { buildUpdateSpanRecord, buildFeedbackRecord, buildLogRecord, buildMetricRecord, buildScoreRecord, buildCreateSpanRecord } from '@mastra/core/storage';
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import { createRequire } from 'module';
|
|
9
|
+
import path from 'path';
|
|
7
10
|
import { TransformStream } from 'stream/web';
|
|
8
11
|
|
|
9
12
|
var __defProp = Object.defineProperty;
|
|
@@ -777,10 +780,10 @@ function mergeDefs(...defs) {
|
|
|
777
780
|
function cloneDef(schema) {
|
|
778
781
|
return mergeDefs(schema._zod.def);
|
|
779
782
|
}
|
|
780
|
-
function getElementAtPath(obj,
|
|
781
|
-
if (!
|
|
783
|
+
function getElementAtPath(obj, path2) {
|
|
784
|
+
if (!path2)
|
|
782
785
|
return obj;
|
|
783
|
-
return
|
|
786
|
+
return path2.reduce((acc, key) => acc?.[key], obj);
|
|
784
787
|
}
|
|
785
788
|
function promiseAllObject(promisesObj) {
|
|
786
789
|
const keys = Object.keys(promisesObj);
|
|
@@ -1163,11 +1166,11 @@ function aborted(x, startIndex = 0) {
|
|
|
1163
1166
|
}
|
|
1164
1167
|
return false;
|
|
1165
1168
|
}
|
|
1166
|
-
function prefixIssues(
|
|
1169
|
+
function prefixIssues(path2, issues) {
|
|
1167
1170
|
return issues.map((iss) => {
|
|
1168
1171
|
var _a2;
|
|
1169
1172
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
1170
|
-
iss.path.unshift(
|
|
1173
|
+
iss.path.unshift(path2);
|
|
1171
1174
|
return iss;
|
|
1172
1175
|
});
|
|
1173
1176
|
}
|
|
@@ -1350,7 +1353,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
|
|
|
1350
1353
|
}
|
|
1351
1354
|
function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
1352
1355
|
const result = { errors: [] };
|
|
1353
|
-
const processError = (error49,
|
|
1356
|
+
const processError = (error49, path2 = []) => {
|
|
1354
1357
|
var _a2, _b;
|
|
1355
1358
|
for (const issue2 of error49.issues) {
|
|
1356
1359
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -1360,7 +1363,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
|
1360
1363
|
} else if (issue2.code === "invalid_element") {
|
|
1361
1364
|
processError({ issues: issue2.issues }, issue2.path);
|
|
1362
1365
|
} else {
|
|
1363
|
-
const fullpath = [...
|
|
1366
|
+
const fullpath = [...path2, ...issue2.path];
|
|
1364
1367
|
if (fullpath.length === 0) {
|
|
1365
1368
|
result.errors.push(mapper(issue2));
|
|
1366
1369
|
continue;
|
|
@@ -1392,8 +1395,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
|
1392
1395
|
}
|
|
1393
1396
|
function toDotPath(_path) {
|
|
1394
1397
|
const segs = [];
|
|
1395
|
-
const
|
|
1396
|
-
for (const seg of
|
|
1398
|
+
const path2 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
1399
|
+
for (const seg of path2) {
|
|
1397
1400
|
if (typeof seg === "number")
|
|
1398
1401
|
segs.push(`[${seg}]`);
|
|
1399
1402
|
else if (typeof seg === "symbol")
|
|
@@ -13365,13 +13368,13 @@ function resolveRef(ref, ctx) {
|
|
|
13365
13368
|
if (!ref.startsWith("#")) {
|
|
13366
13369
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
13367
13370
|
}
|
|
13368
|
-
const
|
|
13369
|
-
if (
|
|
13371
|
+
const path2 = ref.slice(1).split("/").filter(Boolean);
|
|
13372
|
+
if (path2.length === 0) {
|
|
13370
13373
|
return ctx.rootSchema;
|
|
13371
13374
|
}
|
|
13372
13375
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
13373
|
-
if (
|
|
13374
|
-
const key =
|
|
13376
|
+
if (path2[0] === defsKey) {
|
|
13377
|
+
const key = path2[1];
|
|
13375
13378
|
if (!key || !ctx.defs[key]) {
|
|
13376
13379
|
throw new Error(`Reference not found: ${ref}`);
|
|
13377
13380
|
}
|
|
@@ -15890,7 +15893,8 @@ var TestExporter = class extends BaseExporter {
|
|
|
15890
15893
|
this.#trackEvent("log");
|
|
15891
15894
|
if (this.#config.storeLogs) {
|
|
15892
15895
|
const log = event.log;
|
|
15893
|
-
const
|
|
15896
|
+
const traceId = log.correlationContext?.traceId;
|
|
15897
|
+
const logMessage = `[TestExporter] log.${log.level}: "${log.message}"${traceId ? ` (trace: ${traceId.slice(-8)})` : ""}`;
|
|
15894
15898
|
this.#debugLogs.push(logMessage);
|
|
15895
15899
|
}
|
|
15896
15900
|
this.#logEvents.push(event);
|
|
@@ -16007,7 +16011,7 @@ var TestExporter = class extends BaseExporter {
|
|
|
16007
16011
|
getByTraceId(traceId) {
|
|
16008
16012
|
const events = this.#tracingEvents.filter((e) => e.exportedSpan.traceId === traceId);
|
|
16009
16013
|
const spans = this.#getUniqueSpansFromEvents(events);
|
|
16010
|
-
const logs = this.#logEvents.filter((e) => e.log.traceId === traceId).map((e) => e.log);
|
|
16014
|
+
const logs = this.#logEvents.filter((e) => e.log.correlationContext?.traceId === traceId).map((e) => e.log);
|
|
16011
16015
|
const scores = this.#scoreEvents.filter((e) => e.score.traceId === traceId).map((e) => e.score);
|
|
16012
16016
|
const feedback = this.#feedbackEvents.filter((e) => e.feedback.traceId === traceId).map((e) => e.feedback);
|
|
16013
16017
|
return { events, spans, logs, scores, feedback };
|
|
@@ -16074,7 +16078,7 @@ var TestExporter = class extends BaseExporter {
|
|
|
16074
16078
|
traceIds.add(event.exportedSpan.traceId);
|
|
16075
16079
|
}
|
|
16076
16080
|
for (const event of this.#logEvents) {
|
|
16077
|
-
if (event.log.traceId) traceIds.add(event.log.traceId);
|
|
16081
|
+
if (event.log.correlationContext?.traceId) traceIds.add(event.log.correlationContext.traceId);
|
|
16078
16082
|
}
|
|
16079
16083
|
for (const event of this.#scoreEvents) {
|
|
16080
16084
|
traceIds.add(event.score.traceId);
|
|
@@ -16109,7 +16113,7 @@ var TestExporter = class extends BaseExporter {
|
|
|
16109
16113
|
* Get logs for a specific trace
|
|
16110
16114
|
*/
|
|
16111
16115
|
getLogsByTraceId(traceId) {
|
|
16112
|
-
return this.#logEvents.filter((e) => e.log.traceId === traceId).map((e) => e.log);
|
|
16116
|
+
return this.#logEvents.filter((e) => e.log.correlationContext?.traceId === traceId).map((e) => e.log);
|
|
16113
16117
|
}
|
|
16114
16118
|
// ============================================================================
|
|
16115
16119
|
// Metric Query Methods
|
|
@@ -16692,23 +16696,23 @@ Run with { updateSnapshot: true } to update.`
|
|
|
16692
16696
|
* Deep compare two values, supporting special markers like __or__ and __any__.
|
|
16693
16697
|
* Collects all mismatches into the provided array.
|
|
16694
16698
|
*/
|
|
16695
|
-
#deepCompareWithMarkers(actual, expected,
|
|
16699
|
+
#deepCompareWithMarkers(actual, expected, path2, mismatches) {
|
|
16696
16700
|
if (this.#isOrMarker(expected)) {
|
|
16697
16701
|
const allowedValues = expected.__or__;
|
|
16698
16702
|
const matches = allowedValues.some((allowed) => {
|
|
16699
16703
|
const tempMismatches = [];
|
|
16700
|
-
this.#deepCompareWithMarkers(actual, allowed,
|
|
16704
|
+
this.#deepCompareWithMarkers(actual, allowed, path2, tempMismatches);
|
|
16701
16705
|
return tempMismatches.length === 0;
|
|
16702
16706
|
});
|
|
16703
16707
|
if (!matches) {
|
|
16704
|
-
mismatches.push({ path, expected: { __or__: allowedValues }, actual });
|
|
16708
|
+
mismatches.push({ path: path2, expected: { __or__: allowedValues }, actual });
|
|
16705
16709
|
}
|
|
16706
16710
|
return;
|
|
16707
16711
|
}
|
|
16708
16712
|
if (this.#isAnyMarker(expected)) {
|
|
16709
16713
|
const typeConstraint = expected.__any__;
|
|
16710
16714
|
if (actual === null || actual === void 0) {
|
|
16711
|
-
mismatches.push({ path, expected: { __any__: typeConstraint }, actual });
|
|
16715
|
+
mismatches.push({ path: path2, expected: { __any__: typeConstraint }, actual });
|
|
16712
16716
|
return;
|
|
16713
16717
|
}
|
|
16714
16718
|
if (typeConstraint === true) {
|
|
@@ -16717,7 +16721,7 @@ Run with { updateSnapshot: true } to update.`
|
|
|
16717
16721
|
const actualType = Array.isArray(actual) ? "array" : typeof actual;
|
|
16718
16722
|
if (actualType !== typeConstraint) {
|
|
16719
16723
|
mismatches.push({
|
|
16720
|
-
path,
|
|
16724
|
+
path: path2,
|
|
16721
16725
|
expected: { __any__: typeConstraint },
|
|
16722
16726
|
actual: `(${actualType}) ${JSON.stringify(actual).slice(0, 50)}...`
|
|
16723
16727
|
});
|
|
@@ -16726,21 +16730,21 @@ Run with { updateSnapshot: true } to update.`
|
|
|
16726
16730
|
}
|
|
16727
16731
|
if (Array.isArray(expected)) {
|
|
16728
16732
|
if (!Array.isArray(actual)) {
|
|
16729
|
-
mismatches.push({ path, expected, actual });
|
|
16733
|
+
mismatches.push({ path: path2, expected, actual });
|
|
16730
16734
|
return;
|
|
16731
16735
|
}
|
|
16732
16736
|
if (actual.length !== expected.length) {
|
|
16733
|
-
mismatches.push({ path: `${
|
|
16737
|
+
mismatches.push({ path: `${path2}.length`, expected: expected.length, actual: actual.length });
|
|
16734
16738
|
return;
|
|
16735
16739
|
}
|
|
16736
16740
|
for (let i = 0; i < expected.length; i++) {
|
|
16737
|
-
this.#deepCompareWithMarkers(actual[i], expected[i], `${
|
|
16741
|
+
this.#deepCompareWithMarkers(actual[i], expected[i], `${path2}[${i}]`, mismatches);
|
|
16738
16742
|
}
|
|
16739
16743
|
return;
|
|
16740
16744
|
}
|
|
16741
16745
|
if (expected !== null && typeof expected === "object") {
|
|
16742
16746
|
if (actual === null || typeof actual !== "object" || Array.isArray(actual)) {
|
|
16743
|
-
mismatches.push({ path, expected, actual });
|
|
16747
|
+
mismatches.push({ path: path2, expected, actual });
|
|
16744
16748
|
return;
|
|
16745
16749
|
}
|
|
16746
16750
|
const expectedObj = expected;
|
|
@@ -16751,11 +16755,11 @@ Run with { updateSnapshot: true } to update.`
|
|
|
16751
16755
|
}
|
|
16752
16756
|
if (!(key in actualObj)) {
|
|
16753
16757
|
if (expectedObj[key] !== void 0) {
|
|
16754
|
-
mismatches.push({ path: `${
|
|
16758
|
+
mismatches.push({ path: `${path2}.${key}`, expected: expectedObj[key], actual: void 0 });
|
|
16755
16759
|
}
|
|
16756
16760
|
continue;
|
|
16757
16761
|
}
|
|
16758
|
-
this.#deepCompareWithMarkers(actualObj[key], expectedObj[key], `${
|
|
16762
|
+
this.#deepCompareWithMarkers(actualObj[key], expectedObj[key], `${path2}.${key}`, mismatches);
|
|
16759
16763
|
}
|
|
16760
16764
|
for (const key of Object.keys(actualObj)) {
|
|
16761
16765
|
if (this.#isMetadataKey(key)) {
|
|
@@ -16763,14 +16767,14 @@ Run with { updateSnapshot: true } to update.`
|
|
|
16763
16767
|
}
|
|
16764
16768
|
if (!(key in expectedObj)) {
|
|
16765
16769
|
if (actualObj[key] !== void 0) {
|
|
16766
|
-
mismatches.push({ path: `${
|
|
16770
|
+
mismatches.push({ path: `${path2}.${key}`, expected: void 0, actual: actualObj[key] });
|
|
16767
16771
|
}
|
|
16768
16772
|
}
|
|
16769
16773
|
}
|
|
16770
16774
|
return;
|
|
16771
16775
|
}
|
|
16772
16776
|
if (actual !== expected) {
|
|
16773
|
-
mismatches.push({ path, expected, actual });
|
|
16777
|
+
mismatches.push({ path: path2, expected, actual });
|
|
16774
16778
|
}
|
|
16775
16779
|
}
|
|
16776
16780
|
/**
|
|
@@ -16983,120 +16987,6 @@ var BaseObservabilityEventBus = class _BaseObservabilityEventBus extends MastraB
|
|
|
16983
16987
|
this.subscribers.clear();
|
|
16984
16988
|
}
|
|
16985
16989
|
};
|
|
16986
|
-
var AutoExtractedMetrics = class {
|
|
16987
|
-
constructor(observabilityBus) {
|
|
16988
|
-
this.observabilityBus = observabilityBus;
|
|
16989
|
-
}
|
|
16990
|
-
/**
|
|
16991
|
-
* Route a tracing event to the appropriate handler.
|
|
16992
|
-
* SPAN_ENDED emits duration and token metrics (for model spans).
|
|
16993
|
-
*/
|
|
16994
|
-
processTracingEvent(event) {
|
|
16995
|
-
if (event.type === TracingEventType.SPAN_ENDED) {
|
|
16996
|
-
this.onSpanEnded(event.exportedSpan);
|
|
16997
|
-
}
|
|
16998
|
-
}
|
|
16999
|
-
/** Emit duration and token metrics when a span ends. */
|
|
17000
|
-
onSpanEnded(span) {
|
|
17001
|
-
const labels = this.extractLabels(span);
|
|
17002
|
-
const durationMetricName = this.getDurationMetricName(span);
|
|
17003
|
-
if (durationMetricName && span.startTime && span.endTime) {
|
|
17004
|
-
const durationMs = span.endTime.getTime() - span.startTime.getTime();
|
|
17005
|
-
const durationLabels = { ...labels };
|
|
17006
|
-
durationLabels.status = span.errorInfo ? "error" : "ok";
|
|
17007
|
-
this.observabilityBus.emitMetric(durationMetricName, durationMs, durationLabels);
|
|
17008
|
-
}
|
|
17009
|
-
if (span.type === SpanType.MODEL_GENERATION) {
|
|
17010
|
-
const attrs = span.attributes;
|
|
17011
|
-
if (attrs?.usage) {
|
|
17012
|
-
this.extractTokenMetrics(attrs.usage, labels);
|
|
17013
|
-
}
|
|
17014
|
-
}
|
|
17015
|
-
}
|
|
17016
|
-
/** Build base metric labels from a span's entity and model attributes. */
|
|
17017
|
-
extractLabels(span) {
|
|
17018
|
-
const labels = {};
|
|
17019
|
-
if (span.entityType) labels.entity_type = span.entityType;
|
|
17020
|
-
const entityName = span.entityName ?? span.entityId;
|
|
17021
|
-
if (entityName) labels.entity_name = entityName;
|
|
17022
|
-
if (span.type === SpanType.MODEL_GENERATION) {
|
|
17023
|
-
const attrs = span.attributes;
|
|
17024
|
-
if (attrs?.model) labels.model = attrs.model;
|
|
17025
|
-
if (attrs?.provider) labels.provider = attrs.provider;
|
|
17026
|
-
}
|
|
17027
|
-
return labels;
|
|
17028
|
-
}
|
|
17029
|
-
/** Emit token usage metrics from UsageStats. */
|
|
17030
|
-
extractTokenMetrics(usage, labels) {
|
|
17031
|
-
const emit = (name, value) => this.observabilityBus.emitMetric(name, value, labels);
|
|
17032
|
-
const emitNonZero = (name, value) => {
|
|
17033
|
-
if (value > 0) emit(name, value);
|
|
17034
|
-
};
|
|
17035
|
-
emit("mastra_model_total_input_tokens", usage.inputTokens ?? 0);
|
|
17036
|
-
emit("mastra_model_total_output_tokens", usage.outputTokens ?? 0);
|
|
17037
|
-
if (usage.inputDetails) {
|
|
17038
|
-
emitNonZero("mastra_model_input_text_tokens", usage.inputDetails.text ?? 0);
|
|
17039
|
-
emitNonZero("mastra_model_input_cache_read_tokens", usage.inputDetails.cacheRead ?? 0);
|
|
17040
|
-
emitNonZero("mastra_model_input_cache_write_tokens", usage.inputDetails.cacheWrite ?? 0);
|
|
17041
|
-
emitNonZero("mastra_model_input_audio_tokens", usage.inputDetails.audio ?? 0);
|
|
17042
|
-
emitNonZero("mastra_model_input_image_tokens", usage.inputDetails.image ?? 0);
|
|
17043
|
-
}
|
|
17044
|
-
if (usage.outputDetails) {
|
|
17045
|
-
emitNonZero("mastra_model_output_text_tokens", usage.outputDetails.text ?? 0);
|
|
17046
|
-
emitNonZero("mastra_model_output_reasoning_tokens", usage.outputDetails.reasoning ?? 0);
|
|
17047
|
-
emitNonZero("mastra_model_output_audio_tokens", usage.outputDetails.audio ?? 0);
|
|
17048
|
-
emitNonZero("mastra_model_output_image_tokens", usage.outputDetails.image ?? 0);
|
|
17049
|
-
}
|
|
17050
|
-
}
|
|
17051
|
-
/** Map a span type to its `*_duration_ms` metric name, or `null` for unsupported types. */
|
|
17052
|
-
getDurationMetricName(span) {
|
|
17053
|
-
switch (span.type) {
|
|
17054
|
-
case SpanType.AGENT_RUN:
|
|
17055
|
-
return "mastra_agent_duration_ms";
|
|
17056
|
-
case SpanType.TOOL_CALL:
|
|
17057
|
-
return "mastra_tool_duration_ms";
|
|
17058
|
-
case SpanType.WORKFLOW_RUN:
|
|
17059
|
-
return "mastra_workflow_duration_ms";
|
|
17060
|
-
case SpanType.MODEL_GENERATION:
|
|
17061
|
-
return "mastra_model_duration_ms";
|
|
17062
|
-
default:
|
|
17063
|
-
return null;
|
|
17064
|
-
}
|
|
17065
|
-
}
|
|
17066
|
-
};
|
|
17067
|
-
var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
17068
|
-
var CardinalityFilter = class {
|
|
17069
|
-
blockedLabels;
|
|
17070
|
-
blockUUIDs;
|
|
17071
|
-
/**
|
|
17072
|
-
* @param config - Optional configuration. When omitted, uses
|
|
17073
|
-
* {@link DEFAULT_BLOCKED_LABELS} and blocks UUID-valued labels.
|
|
17074
|
-
*/
|
|
17075
|
-
constructor(config2) {
|
|
17076
|
-
const blocked = config2?.blockedLabels ?? [...DEFAULT_BLOCKED_LABELS];
|
|
17077
|
-
this.blockedLabels = new Set(blocked.map((l) => l.toLowerCase()));
|
|
17078
|
-
this.blockUUIDs = config2?.blockUUIDs ?? true;
|
|
17079
|
-
}
|
|
17080
|
-
/**
|
|
17081
|
-
* Return a copy of `labels` with blocked keys and UUID values removed.
|
|
17082
|
-
*
|
|
17083
|
-
* @param labels - Raw metric labels to filter.
|
|
17084
|
-
* @returns A new object containing only the allowed labels.
|
|
17085
|
-
*/
|
|
17086
|
-
filterLabels(labels) {
|
|
17087
|
-
const filtered = {};
|
|
17088
|
-
for (const [key, value] of Object.entries(labels)) {
|
|
17089
|
-
if (this.blockedLabels.has(key.toLowerCase())) {
|
|
17090
|
-
continue;
|
|
17091
|
-
}
|
|
17092
|
-
if (this.blockUUIDs && UUID_REGEX.test(value)) {
|
|
17093
|
-
continue;
|
|
17094
|
-
}
|
|
17095
|
-
filtered[key] = value;
|
|
17096
|
-
}
|
|
17097
|
-
return filtered;
|
|
17098
|
-
}
|
|
17099
|
-
};
|
|
17100
16990
|
function routeToHandler(handler, event, logger) {
|
|
17101
16991
|
try {
|
|
17102
16992
|
switch (event.type) {
|
|
@@ -17141,39 +17031,13 @@ function catchAsyncResult(result, handlerName, signal, logger) {
|
|
|
17141
17031
|
|
|
17142
17032
|
// src/bus/observability-bus.ts
|
|
17143
17033
|
var MAX_FLUSH_ITERATIONS = 3;
|
|
17144
|
-
function isTracingEvent(event) {
|
|
17145
|
-
return event.type === TracingEventType.SPAN_STARTED || event.type === TracingEventType.SPAN_UPDATED || event.type === TracingEventType.SPAN_ENDED;
|
|
17146
|
-
}
|
|
17147
17034
|
var ObservabilityBus = class extends BaseObservabilityEventBus {
|
|
17148
17035
|
exporters = [];
|
|
17149
17036
|
bridge;
|
|
17150
|
-
autoExtractor;
|
|
17151
|
-
cardinalityFilter;
|
|
17152
17037
|
/** In-flight handler promises from routeToHandler. Self-cleaning via .finally(). */
|
|
17153
17038
|
pendingHandlers = /* @__PURE__ */ new Set();
|
|
17154
|
-
constructor(
|
|
17039
|
+
constructor() {
|
|
17155
17040
|
super({ name: "ObservabilityBus" });
|
|
17156
|
-
this.cardinalityFilter = config2?.cardinalityFilter ?? new CardinalityFilter();
|
|
17157
|
-
if (config2?.autoExtractMetrics !== false) {
|
|
17158
|
-
this.autoExtractor = new AutoExtractedMetrics(this);
|
|
17159
|
-
}
|
|
17160
|
-
}
|
|
17161
|
-
/**
|
|
17162
|
-
* Emit a metric event with validation and cardinality filtering.
|
|
17163
|
-
* Non-finite or negative values are silently dropped.
|
|
17164
|
-
* This is the single entry point for all metric emission (auto-extracted and user-defined).
|
|
17165
|
-
*/
|
|
17166
|
-
emitMetric(name, value, labels) {
|
|
17167
|
-
if (!Number.isFinite(value) || value < 0) return;
|
|
17168
|
-
const filteredLabels = this.cardinalityFilter.filterLabels(labels);
|
|
17169
|
-
const exportedMetric = {
|
|
17170
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
17171
|
-
name,
|
|
17172
|
-
value,
|
|
17173
|
-
labels: filteredLabels
|
|
17174
|
-
};
|
|
17175
|
-
const event = { type: "metric", metric: exportedMetric };
|
|
17176
|
-
this.emit(event);
|
|
17177
17041
|
}
|
|
17178
17042
|
/**
|
|
17179
17043
|
* Register an exporter to receive routed events.
|
|
@@ -17239,8 +17103,8 @@ var ObservabilityBus = class extends BaseObservabilityEventBus {
|
|
|
17239
17103
|
return this.bridge;
|
|
17240
17104
|
}
|
|
17241
17105
|
/**
|
|
17242
|
-
* Emit an event: route to exporter/bridge handlers,
|
|
17243
|
-
*
|
|
17106
|
+
* Emit an event: route to exporter/bridge handlers, then forward to base
|
|
17107
|
+
* class for subscriber delivery.
|
|
17244
17108
|
*
|
|
17245
17109
|
* emit() is synchronous — async handler promises are tracked internally
|
|
17246
17110
|
* and can be drained via flush().
|
|
@@ -17252,13 +17116,6 @@ var ObservabilityBus = class extends BaseObservabilityEventBus {
|
|
|
17252
17116
|
if (this.bridge) {
|
|
17253
17117
|
this.trackPromise(routeToHandler(this.bridge, event, this.logger));
|
|
17254
17118
|
}
|
|
17255
|
-
if (this.autoExtractor && isTracingEvent(event)) {
|
|
17256
|
-
try {
|
|
17257
|
-
this.autoExtractor.processTracingEvent(event);
|
|
17258
|
-
} catch (err) {
|
|
17259
|
-
this.logger.error("[ObservabilityBus] Auto-extraction error:", err);
|
|
17260
|
-
}
|
|
17261
|
-
}
|
|
17262
17119
|
super.emit(event);
|
|
17263
17120
|
}
|
|
17264
17121
|
/**
|
|
@@ -17326,13 +17183,13 @@ var LOG_LEVEL_PRIORITY = {
|
|
|
17326
17183
|
var LoggerContextImpl = class {
|
|
17327
17184
|
config;
|
|
17328
17185
|
/**
|
|
17329
|
-
* Create a logger context.
|
|
17186
|
+
* Create a logger context. Context and metadata are defensively copied so
|
|
17330
17187
|
* mutations after construction do not affect emitted logs.
|
|
17331
17188
|
*/
|
|
17332
17189
|
constructor(config2) {
|
|
17333
17190
|
this.config = {
|
|
17334
17191
|
...config2,
|
|
17335
|
-
|
|
17192
|
+
correlationContext: config2.correlationContext ? { ...config2.correlationContext } : void 0,
|
|
17336
17193
|
metadata: config2.metadata ? structuredClone(config2.metadata) : void 0
|
|
17337
17194
|
};
|
|
17338
17195
|
}
|
|
@@ -17369,9 +17226,7 @@ var LoggerContextImpl = class {
|
|
|
17369
17226
|
level,
|
|
17370
17227
|
message,
|
|
17371
17228
|
data,
|
|
17372
|
-
|
|
17373
|
-
spanId: this.config.spanId,
|
|
17374
|
-
tags: this.config.tags,
|
|
17229
|
+
correlationContext: this.config.correlationContext,
|
|
17375
17230
|
metadata: this.config.metadata
|
|
17376
17231
|
};
|
|
17377
17232
|
const event = { type: "log", log: exportedLog };
|
|
@@ -17381,20 +17236,38 @@ var LoggerContextImpl = class {
|
|
|
17381
17236
|
|
|
17382
17237
|
// src/context/metrics.ts
|
|
17383
17238
|
var MetricsContextImpl = class {
|
|
17384
|
-
|
|
17239
|
+
correlationContext;
|
|
17240
|
+
metadata;
|
|
17241
|
+
cardinalityFilter;
|
|
17385
17242
|
observabilityBus;
|
|
17386
17243
|
/**
|
|
17387
|
-
* Create a metrics context.
|
|
17388
|
-
* mutations after construction do not affect emitted metrics.
|
|
17244
|
+
* Create a metrics context. Correlation context and metadata are defensively
|
|
17245
|
+
* copied so mutations after construction do not affect emitted metrics.
|
|
17389
17246
|
*/
|
|
17390
17247
|
constructor(config2) {
|
|
17391
|
-
this.
|
|
17248
|
+
this.correlationContext = config2.correlationContext ? { ...config2.correlationContext } : void 0;
|
|
17249
|
+
this.metadata = config2.metadata ? structuredClone(config2.metadata) : void 0;
|
|
17250
|
+
this.cardinalityFilter = config2.cardinalityFilter;
|
|
17392
17251
|
this.observabilityBus = config2.observabilityBus;
|
|
17393
17252
|
}
|
|
17394
17253
|
/** Emit a metric observation. */
|
|
17395
|
-
emit(name, value, labels) {
|
|
17396
|
-
|
|
17397
|
-
|
|
17254
|
+
emit(name, value, labels, options) {
|
|
17255
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
17256
|
+
return;
|
|
17257
|
+
}
|
|
17258
|
+
const filteredLabels = labels ? this.cardinalityFilter.filterLabels(labels) : {};
|
|
17259
|
+
const costContext = options?.costContext ? cloneCostContext(options.costContext) : void 0;
|
|
17260
|
+
const exportedMetric = {
|
|
17261
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
17262
|
+
name,
|
|
17263
|
+
value,
|
|
17264
|
+
labels: filteredLabels,
|
|
17265
|
+
correlationContext: this.correlationContext,
|
|
17266
|
+
costContext,
|
|
17267
|
+
metadata: this.metadata
|
|
17268
|
+
};
|
|
17269
|
+
const event = { type: "metric", metric: exportedMetric };
|
|
17270
|
+
this.observabilityBus.emit(event);
|
|
17398
17271
|
}
|
|
17399
17272
|
/** @deprecated Use `emit()` instead. */
|
|
17400
17273
|
counter(name) {
|
|
@@ -17421,6 +17294,563 @@ var MetricsContextImpl = class {
|
|
|
17421
17294
|
};
|
|
17422
17295
|
}
|
|
17423
17296
|
};
|
|
17297
|
+
function cloneCostContext(costContext) {
|
|
17298
|
+
return {
|
|
17299
|
+
provider: costContext.provider,
|
|
17300
|
+
model: costContext.model,
|
|
17301
|
+
estimatedCost: costContext.estimatedCost,
|
|
17302
|
+
costUnit: costContext.costUnit,
|
|
17303
|
+
costMetadata: costContext.costMetadata ? structuredClone(costContext.costMetadata) : void 0
|
|
17304
|
+
};
|
|
17305
|
+
}
|
|
17306
|
+
|
|
17307
|
+
// src/metrics/pricing-model.ts
|
|
17308
|
+
var PricingTier = class {
|
|
17309
|
+
index;
|
|
17310
|
+
when;
|
|
17311
|
+
rates;
|
|
17312
|
+
constructor(args) {
|
|
17313
|
+
this.index = args.index;
|
|
17314
|
+
this.when = args.when;
|
|
17315
|
+
this.rates = args.rates;
|
|
17316
|
+
}
|
|
17317
|
+
matchesUsage(usage) {
|
|
17318
|
+
if (!this.when || this.when.length === 0) {
|
|
17319
|
+
return true;
|
|
17320
|
+
}
|
|
17321
|
+
return this.when.every((condition) => this.matchesCondition(condition, usage));
|
|
17322
|
+
}
|
|
17323
|
+
hasMatchingMeterForUsage(meter) {
|
|
17324
|
+
return Boolean(meter && typeof this.rates[meter] === "number");
|
|
17325
|
+
}
|
|
17326
|
+
matchesCondition(condition, usage) {
|
|
17327
|
+
const left = this.getConditionFieldValue(condition.field, usage);
|
|
17328
|
+
if (left == null) {
|
|
17329
|
+
return false;
|
|
17330
|
+
}
|
|
17331
|
+
switch (condition.op) {
|
|
17332
|
+
case "gt":
|
|
17333
|
+
return left > condition.value;
|
|
17334
|
+
case "gte":
|
|
17335
|
+
return left >= condition.value;
|
|
17336
|
+
case "lt":
|
|
17337
|
+
return left < condition.value;
|
|
17338
|
+
case "lte":
|
|
17339
|
+
return left <= condition.value;
|
|
17340
|
+
case "eq":
|
|
17341
|
+
return left === condition.value;
|
|
17342
|
+
case "neq":
|
|
17343
|
+
return left !== condition.value;
|
|
17344
|
+
default:
|
|
17345
|
+
return false;
|
|
17346
|
+
}
|
|
17347
|
+
}
|
|
17348
|
+
getConditionFieldValue(field, usage) {
|
|
17349
|
+
switch (field) {
|
|
17350
|
+
case "total_input_tokens":
|
|
17351
|
+
return typeof usage.inputTokens === "number" ? usage.inputTokens : null;
|
|
17352
|
+
default:
|
|
17353
|
+
return null;
|
|
17354
|
+
}
|
|
17355
|
+
}
|
|
17356
|
+
};
|
|
17357
|
+
var PricingModel = class {
|
|
17358
|
+
id;
|
|
17359
|
+
provider;
|
|
17360
|
+
model;
|
|
17361
|
+
schema;
|
|
17362
|
+
currency;
|
|
17363
|
+
tiers;
|
|
17364
|
+
constructor(args) {
|
|
17365
|
+
this.id = args.id;
|
|
17366
|
+
this.provider = args.provider;
|
|
17367
|
+
this.model = args.model;
|
|
17368
|
+
this.schema = args.schema;
|
|
17369
|
+
this.currency = args.currency;
|
|
17370
|
+
this.tiers = args.tiers;
|
|
17371
|
+
}
|
|
17372
|
+
getPricingTierForUsage(usage) {
|
|
17373
|
+
for (const tier of this.tiers) {
|
|
17374
|
+
if (tier.when && tier.when.length > 0 && tier.matchesUsage(usage)) {
|
|
17375
|
+
return tier;
|
|
17376
|
+
}
|
|
17377
|
+
}
|
|
17378
|
+
return this.getBasePricingTier();
|
|
17379
|
+
}
|
|
17380
|
+
getBasePricingTier() {
|
|
17381
|
+
return this.tiers[0] ?? null;
|
|
17382
|
+
}
|
|
17383
|
+
};
|
|
17384
|
+
|
|
17385
|
+
// src/metrics/pricing-registry.ts
|
|
17386
|
+
var DATA_FILE_NAME = "pricing-data.jsonl";
|
|
17387
|
+
var MINIFIED_METER_TO_CANONICAL = {
|
|
17388
|
+
it: "input_tokens",
|
|
17389
|
+
ot: "output_tokens",
|
|
17390
|
+
icrt: "input_cache_read_tokens",
|
|
17391
|
+
icwt: "input_cache_write_tokens",
|
|
17392
|
+
iat: "input_audio_tokens",
|
|
17393
|
+
oat: "output_audio_tokens",
|
|
17394
|
+
ort: "output_reasoning_tokens"
|
|
17395
|
+
};
|
|
17396
|
+
var MINIFIED_CONDITION_FIELD_TO_CANONICAL = {
|
|
17397
|
+
tit: "total_input_tokens"
|
|
17398
|
+
};
|
|
17399
|
+
var cachedLoadError = null;
|
|
17400
|
+
var PricingRegistry = class _PricingRegistry {
|
|
17401
|
+
constructor(pricingModels) {
|
|
17402
|
+
this.pricingModels = pricingModels;
|
|
17403
|
+
}
|
|
17404
|
+
static globalRegistry = null;
|
|
17405
|
+
static fromText(pricingModelText) {
|
|
17406
|
+
return new _PricingRegistry(parsePricingModelText(pricingModelText));
|
|
17407
|
+
}
|
|
17408
|
+
static getGlobal() {
|
|
17409
|
+
if (_PricingRegistry.globalRegistry) {
|
|
17410
|
+
return _PricingRegistry.globalRegistry;
|
|
17411
|
+
}
|
|
17412
|
+
const pricingModels = loadPricingModels();
|
|
17413
|
+
if (!pricingModels) {
|
|
17414
|
+
return null;
|
|
17415
|
+
}
|
|
17416
|
+
_PricingRegistry.globalRegistry = new _PricingRegistry(pricingModels);
|
|
17417
|
+
return _PricingRegistry.globalRegistry;
|
|
17418
|
+
}
|
|
17419
|
+
get(args) {
|
|
17420
|
+
return this.pricingModels.get(makePricingKey(args)) ?? null;
|
|
17421
|
+
}
|
|
17422
|
+
};
|
|
17423
|
+
function loadPricingModels() {
|
|
17424
|
+
if (cachedLoadError) {
|
|
17425
|
+
return null;
|
|
17426
|
+
}
|
|
17427
|
+
try {
|
|
17428
|
+
const content = fs.readFileSync(resolvePricingModelPath(), "utf-8");
|
|
17429
|
+
return parsePricingModelText(content);
|
|
17430
|
+
} catch (error48) {
|
|
17431
|
+
cachedLoadError = error48 instanceof Error ? error48.message : String(error48);
|
|
17432
|
+
return null;
|
|
17433
|
+
}
|
|
17434
|
+
}
|
|
17435
|
+
function parsePricingModelText(content) {
|
|
17436
|
+
const pricingModels = /* @__PURE__ */ new Map();
|
|
17437
|
+
for (const line of content.split("\n")) {
|
|
17438
|
+
const trimmed = line.trim();
|
|
17439
|
+
if (!trimmed) {
|
|
17440
|
+
continue;
|
|
17441
|
+
}
|
|
17442
|
+
const parsed = JSON.parse(trimmed);
|
|
17443
|
+
const pricingModel = expandPricingModelRow(parsed);
|
|
17444
|
+
pricingModels.set(makePricingKey(pricingModel), pricingModel);
|
|
17445
|
+
}
|
|
17446
|
+
return pricingModels;
|
|
17447
|
+
}
|
|
17448
|
+
function expandPricingModelRow(row) {
|
|
17449
|
+
return new PricingModel({
|
|
17450
|
+
id: row.i,
|
|
17451
|
+
provider: row.p,
|
|
17452
|
+
model: row.m,
|
|
17453
|
+
schema: row.s.v,
|
|
17454
|
+
currency: row.s.d.u,
|
|
17455
|
+
tiers: row.s.d.t.map(
|
|
17456
|
+
(tier, index) => new PricingTier({
|
|
17457
|
+
index,
|
|
17458
|
+
when: tier.w?.map((condition) => ({
|
|
17459
|
+
field: MINIFIED_CONDITION_FIELD_TO_CANONICAL[condition.f],
|
|
17460
|
+
op: condition.op,
|
|
17461
|
+
value: condition.value
|
|
17462
|
+
})),
|
|
17463
|
+
rates: Object.fromEntries(
|
|
17464
|
+
Object.entries(tier.r).map(([meter, value]) => [
|
|
17465
|
+
MINIFIED_METER_TO_CANONICAL[meter],
|
|
17466
|
+
value.c
|
|
17467
|
+
])
|
|
17468
|
+
)
|
|
17469
|
+
})
|
|
17470
|
+
)
|
|
17471
|
+
});
|
|
17472
|
+
}
|
|
17473
|
+
function resolvePricingModelPath() {
|
|
17474
|
+
const packageRoot = getPackageRoot();
|
|
17475
|
+
const candidates = [
|
|
17476
|
+
path.join(packageRoot, "dist", "metrics", DATA_FILE_NAME),
|
|
17477
|
+
path.join(packageRoot, "src", "metrics", DATA_FILE_NAME),
|
|
17478
|
+
path.join(process.cwd(), "observability", "mastra", "src", "metrics", DATA_FILE_NAME),
|
|
17479
|
+
path.join(process.cwd(), "src", "metrics", DATA_FILE_NAME)
|
|
17480
|
+
];
|
|
17481
|
+
for (const candidate of candidates) {
|
|
17482
|
+
if (fs.existsSync(candidate)) {
|
|
17483
|
+
return candidate;
|
|
17484
|
+
}
|
|
17485
|
+
}
|
|
17486
|
+
throw new Error(`Unable to locate pricing data JSONL at any known path: ${candidates.join(", ")}`);
|
|
17487
|
+
}
|
|
17488
|
+
function getPackageRoot() {
|
|
17489
|
+
try {
|
|
17490
|
+
const require2 = createRequire(import.meta.url || "file://");
|
|
17491
|
+
const packageJsonPath = require2.resolve("@mastra/observability/package.json");
|
|
17492
|
+
return path.dirname(packageJsonPath);
|
|
17493
|
+
} catch {
|
|
17494
|
+
return process.cwd();
|
|
17495
|
+
}
|
|
17496
|
+
}
|
|
17497
|
+
function makePricingKey(args) {
|
|
17498
|
+
return `${normalizeKeyPart(args.provider)}::${normalizeKeyPart(args.model)}`;
|
|
17499
|
+
}
|
|
17500
|
+
function normalizeKeyPart(value) {
|
|
17501
|
+
return value.trim().toLowerCase();
|
|
17502
|
+
}
|
|
17503
|
+
|
|
17504
|
+
// src/metrics/types.ts
|
|
17505
|
+
var PricingMeter = {
|
|
17506
|
+
INPUT_TOKENS: "input_tokens",
|
|
17507
|
+
INPUT_AUDIO_TOKENS: "input_audio_tokens",
|
|
17508
|
+
INPUT_CACHE_READ_TOKENS: "input_cache_read_tokens",
|
|
17509
|
+
INPUT_CACHE_WRITE_TOKENS: "input_cache_write_tokens",
|
|
17510
|
+
INPUT_IMAGE_TOKENS: "input_image_tokens",
|
|
17511
|
+
OUTPUT_TOKENS: "output_tokens",
|
|
17512
|
+
OUTPUT_AUDIO_TOKENS: "output_audio_tokens",
|
|
17513
|
+
OUTPUT_IMAGE_TOKENS: "output_image_tokens",
|
|
17514
|
+
OUTPUT_REASONING_TOKENS: "output_reasoning_tokens"
|
|
17515
|
+
};
|
|
17516
|
+
var TokenMetrics = {
|
|
17517
|
+
TOTAL_INPUT: "mastra_model_total_input_tokens",
|
|
17518
|
+
TOTAL_OUTPUT: "mastra_model_total_output_tokens",
|
|
17519
|
+
INPUT_TEXT: "mastra_model_input_text_tokens",
|
|
17520
|
+
INPUT_CACHE_READ: "mastra_model_input_cache_read_tokens",
|
|
17521
|
+
INPUT_CACHE_WRITE: "mastra_model_input_cache_write_tokens",
|
|
17522
|
+
INPUT_AUDIO: "mastra_model_input_audio_tokens",
|
|
17523
|
+
INPUT_IMAGE: "mastra_model_input_image_tokens",
|
|
17524
|
+
OUTPUT_TEXT: "mastra_model_output_text_tokens",
|
|
17525
|
+
OUTPUT_REASONING: "mastra_model_output_reasoning_tokens",
|
|
17526
|
+
OUTPUT_AUDIO: "mastra_model_output_audio_tokens",
|
|
17527
|
+
OUTPUT_IMAGE: "mastra_model_output_image_tokens"
|
|
17528
|
+
};
|
|
17529
|
+
|
|
17530
|
+
// src/metrics/usage-metrics.ts
|
|
17531
|
+
function getTokenMetricSamples(usage) {
|
|
17532
|
+
const samples = [];
|
|
17533
|
+
const pushIfDefined = (name, value) => {
|
|
17534
|
+
if (value != null) {
|
|
17535
|
+
samples.push({ name, value });
|
|
17536
|
+
}
|
|
17537
|
+
};
|
|
17538
|
+
const pushIfPositive = (name, value) => {
|
|
17539
|
+
if (value != null && value > 0) {
|
|
17540
|
+
samples.push({ name, value });
|
|
17541
|
+
}
|
|
17542
|
+
};
|
|
17543
|
+
pushIfDefined(TokenMetrics.TOTAL_INPUT, usage.inputTokens);
|
|
17544
|
+
pushIfDefined(TokenMetrics.TOTAL_OUTPUT, usage.outputTokens);
|
|
17545
|
+
if (usage.inputDetails) {
|
|
17546
|
+
pushIfPositive(TokenMetrics.INPUT_TEXT, usage.inputDetails.text);
|
|
17547
|
+
pushIfPositive(TokenMetrics.INPUT_CACHE_READ, usage.inputDetails.cacheRead);
|
|
17548
|
+
pushIfPositive(TokenMetrics.INPUT_CACHE_WRITE, usage.inputDetails.cacheWrite);
|
|
17549
|
+
pushIfPositive(TokenMetrics.INPUT_AUDIO, usage.inputDetails.audio);
|
|
17550
|
+
pushIfPositive(TokenMetrics.INPUT_IMAGE, usage.inputDetails.image);
|
|
17551
|
+
}
|
|
17552
|
+
if (usage.outputDetails) {
|
|
17553
|
+
pushIfPositive(TokenMetrics.OUTPUT_TEXT, usage.outputDetails.text);
|
|
17554
|
+
pushIfPositive(TokenMetrics.OUTPUT_REASONING, usage.outputDetails.reasoning);
|
|
17555
|
+
pushIfPositive(TokenMetrics.OUTPUT_AUDIO, usage.outputDetails.audio);
|
|
17556
|
+
pushIfPositive(TokenMetrics.OUTPUT_IMAGE, usage.outputDetails.image);
|
|
17557
|
+
}
|
|
17558
|
+
return samples;
|
|
17559
|
+
}
|
|
17560
|
+
|
|
17561
|
+
// src/metrics/estimator.ts
|
|
17562
|
+
function estimateCosts(args, pricingRegistry = PricingRegistry.getGlobal()) {
|
|
17563
|
+
const { provider, model, usage } = args;
|
|
17564
|
+
const results = /* @__PURE__ */ new Map();
|
|
17565
|
+
const pricingModel = pricingRegistry?.get({ provider, model });
|
|
17566
|
+
if (!pricingModel) {
|
|
17567
|
+
const errorContext = { costMetadata: { error: "no_matching_model" }, provider, model };
|
|
17568
|
+
applyErrorContextForUsage(results, usage, errorContext);
|
|
17569
|
+
return results;
|
|
17570
|
+
}
|
|
17571
|
+
const costMetadata = { pricing_id: pricingModel.id };
|
|
17572
|
+
const pricingTier = pricingModel.getPricingTierForUsage(usage);
|
|
17573
|
+
if (!pricingTier) {
|
|
17574
|
+
const errorContext = { costMetadata: { ...costMetadata, error: "no_matching_tier" }, provider, model };
|
|
17575
|
+
applyErrorContextForUsage(results, usage, errorContext);
|
|
17576
|
+
return results;
|
|
17577
|
+
}
|
|
17578
|
+
costMetadata["tier_index"] = pricingTier.index;
|
|
17579
|
+
const estimateFields = {
|
|
17580
|
+
pricingModel,
|
|
17581
|
+
pricingTier,
|
|
17582
|
+
costMetadata
|
|
17583
|
+
};
|
|
17584
|
+
const inputDetailResults = [];
|
|
17585
|
+
if (usage.inputDetails?.audio) {
|
|
17586
|
+
const result = estimateCostForMeter({
|
|
17587
|
+
meter: PricingMeter.INPUT_AUDIO_TOKENS,
|
|
17588
|
+
tokenCount: usage.inputDetails.audio,
|
|
17589
|
+
...estimateFields
|
|
17590
|
+
});
|
|
17591
|
+
results.set(TokenMetrics.INPUT_AUDIO, result.costContext);
|
|
17592
|
+
inputDetailResults.push(result);
|
|
17593
|
+
}
|
|
17594
|
+
if (usage.inputDetails?.cacheRead) {
|
|
17595
|
+
const result = estimateCostForMeter({
|
|
17596
|
+
meter: PricingMeter.INPUT_CACHE_READ_TOKENS,
|
|
17597
|
+
tokenCount: usage.inputDetails.cacheRead,
|
|
17598
|
+
...estimateFields
|
|
17599
|
+
});
|
|
17600
|
+
results.set(TokenMetrics.INPUT_CACHE_READ, result.costContext);
|
|
17601
|
+
inputDetailResults.push(result);
|
|
17602
|
+
}
|
|
17603
|
+
if (usage.inputDetails?.cacheWrite) {
|
|
17604
|
+
const result = estimateCostForMeter({
|
|
17605
|
+
meter: PricingMeter.INPUT_CACHE_WRITE_TOKENS,
|
|
17606
|
+
tokenCount: usage.inputDetails.cacheWrite,
|
|
17607
|
+
...estimateFields
|
|
17608
|
+
});
|
|
17609
|
+
results.set(TokenMetrics.INPUT_CACHE_WRITE, result.costContext);
|
|
17610
|
+
inputDetailResults.push(result);
|
|
17611
|
+
}
|
|
17612
|
+
if (usage.inputDetails?.image) {
|
|
17613
|
+
const result = estimateCostForMeter({
|
|
17614
|
+
meter: PricingMeter.INPUT_IMAGE_TOKENS,
|
|
17615
|
+
tokenCount: usage.inputDetails.image,
|
|
17616
|
+
...estimateFields
|
|
17617
|
+
});
|
|
17618
|
+
results.set(TokenMetrics.INPUT_IMAGE, result.costContext);
|
|
17619
|
+
inputDetailResults.push(result);
|
|
17620
|
+
}
|
|
17621
|
+
if (usage.inputDetails?.text) {
|
|
17622
|
+
const result = estimateCostForMeter({
|
|
17623
|
+
meter: PricingMeter.INPUT_TOKENS,
|
|
17624
|
+
tokenCount: usage.inputDetails.text,
|
|
17625
|
+
...estimateFields
|
|
17626
|
+
});
|
|
17627
|
+
results.set(TokenMetrics.INPUT_TEXT, result.costContext);
|
|
17628
|
+
inputDetailResults.push(result);
|
|
17629
|
+
}
|
|
17630
|
+
setAggregateCostContext({
|
|
17631
|
+
results,
|
|
17632
|
+
totalMetric: TokenMetrics.TOTAL_INPUT,
|
|
17633
|
+
fallbackMeter: PricingMeter.INPUT_TOKENS,
|
|
17634
|
+
totalTokenCount: usage.inputTokens,
|
|
17635
|
+
detailResults: inputDetailResults,
|
|
17636
|
+
...estimateFields
|
|
17637
|
+
});
|
|
17638
|
+
const outputDetailResults = [];
|
|
17639
|
+
if (usage.outputDetails?.audio) {
|
|
17640
|
+
const result = estimateCostForMeter({
|
|
17641
|
+
meter: PricingMeter.OUTPUT_AUDIO_TOKENS,
|
|
17642
|
+
tokenCount: usage.outputDetails.audio,
|
|
17643
|
+
...estimateFields
|
|
17644
|
+
});
|
|
17645
|
+
results.set(TokenMetrics.OUTPUT_AUDIO, result.costContext);
|
|
17646
|
+
outputDetailResults.push(result);
|
|
17647
|
+
}
|
|
17648
|
+
if (usage.outputDetails?.image) {
|
|
17649
|
+
const result = estimateCostForMeter({
|
|
17650
|
+
meter: PricingMeter.OUTPUT_IMAGE_TOKENS,
|
|
17651
|
+
tokenCount: usage.outputDetails.image,
|
|
17652
|
+
...estimateFields
|
|
17653
|
+
});
|
|
17654
|
+
results.set(TokenMetrics.OUTPUT_IMAGE, result.costContext);
|
|
17655
|
+
outputDetailResults.push(result);
|
|
17656
|
+
}
|
|
17657
|
+
if (usage.outputDetails?.reasoning) {
|
|
17658
|
+
const result = estimateCostForMeter({
|
|
17659
|
+
meter: PricingMeter.OUTPUT_REASONING_TOKENS,
|
|
17660
|
+
tokenCount: usage.outputDetails.reasoning,
|
|
17661
|
+
...estimateFields
|
|
17662
|
+
});
|
|
17663
|
+
results.set(TokenMetrics.OUTPUT_REASONING, result.costContext);
|
|
17664
|
+
outputDetailResults.push(result);
|
|
17665
|
+
}
|
|
17666
|
+
if (usage.outputDetails?.text) {
|
|
17667
|
+
const result = estimateCostForMeter({
|
|
17668
|
+
meter: PricingMeter.OUTPUT_TOKENS,
|
|
17669
|
+
tokenCount: usage.outputDetails.text,
|
|
17670
|
+
...estimateFields
|
|
17671
|
+
});
|
|
17672
|
+
results.set(TokenMetrics.OUTPUT_TEXT, result.costContext);
|
|
17673
|
+
outputDetailResults.push(result);
|
|
17674
|
+
}
|
|
17675
|
+
setAggregateCostContext({
|
|
17676
|
+
results,
|
|
17677
|
+
totalMetric: TokenMetrics.TOTAL_OUTPUT,
|
|
17678
|
+
fallbackMeter: PricingMeter.OUTPUT_TOKENS,
|
|
17679
|
+
totalTokenCount: usage.outputTokens,
|
|
17680
|
+
detailResults: outputDetailResults,
|
|
17681
|
+
...estimateFields
|
|
17682
|
+
});
|
|
17683
|
+
return results;
|
|
17684
|
+
}
|
|
17685
|
+
function applyErrorContextForUsage(results, usage, errorContext) {
|
|
17686
|
+
for (const sample of getTokenMetricSamples(usage)) {
|
|
17687
|
+
results.set(sample.name, errorContext);
|
|
17688
|
+
}
|
|
17689
|
+
}
|
|
17690
|
+
function setAggregateCostContext(args) {
|
|
17691
|
+
const {
|
|
17692
|
+
results,
|
|
17693
|
+
totalMetric,
|
|
17694
|
+
fallbackMeter,
|
|
17695
|
+
totalTokenCount,
|
|
17696
|
+
detailResults,
|
|
17697
|
+
pricingModel,
|
|
17698
|
+
pricingTier,
|
|
17699
|
+
costMetadata
|
|
17700
|
+
} = args;
|
|
17701
|
+
if (totalTokenCount == null) {
|
|
17702
|
+
return;
|
|
17703
|
+
}
|
|
17704
|
+
const successfulDetailCosts = detailResults.filter((result) => result.success).map((result) => result.costContext.estimatedCost).filter((value) => typeof value === "number");
|
|
17705
|
+
if (successfulDetailCosts.length > 0) {
|
|
17706
|
+
const hasFailedDetailCost = detailResults.some((result) => !result.success);
|
|
17707
|
+
results.set(totalMetric, {
|
|
17708
|
+
provider: pricingModel.provider,
|
|
17709
|
+
model: pricingModel.model,
|
|
17710
|
+
estimatedCost: successfulDetailCosts.reduce((sum, value) => sum + value, 0),
|
|
17711
|
+
costUnit: pricingModel.currency,
|
|
17712
|
+
costMetadata: hasFailedDetailCost ? { ...costMetadata, error: "partial_cost" } : { ...costMetadata }
|
|
17713
|
+
});
|
|
17714
|
+
return;
|
|
17715
|
+
}
|
|
17716
|
+
const fallbackResult = estimateCostForMeter({
|
|
17717
|
+
meter: fallbackMeter,
|
|
17718
|
+
tokenCount: totalTokenCount,
|
|
17719
|
+
pricingModel,
|
|
17720
|
+
pricingTier,
|
|
17721
|
+
costMetadata
|
|
17722
|
+
});
|
|
17723
|
+
results.set(totalMetric, fallbackResult.costContext);
|
|
17724
|
+
}
|
|
17725
|
+
function estimateCostForMeter(args) {
|
|
17726
|
+
const { pricingModel, pricingTier, meter, tokenCount, costMetadata } = args;
|
|
17727
|
+
const costContext = {
|
|
17728
|
+
provider: pricingModel.provider,
|
|
17729
|
+
model: pricingModel.model
|
|
17730
|
+
};
|
|
17731
|
+
const pricePerUnit = pricingTier.rates[meter];
|
|
17732
|
+
if (typeof pricePerUnit !== "number") {
|
|
17733
|
+
return {
|
|
17734
|
+
success: false,
|
|
17735
|
+
costContext: {
|
|
17736
|
+
...costContext,
|
|
17737
|
+
costMetadata: { ...costMetadata, error: "no_pricing_for_usage_type" }
|
|
17738
|
+
}
|
|
17739
|
+
};
|
|
17740
|
+
}
|
|
17741
|
+
return {
|
|
17742
|
+
success: true,
|
|
17743
|
+
costContext: {
|
|
17744
|
+
...costContext,
|
|
17745
|
+
estimatedCost: tokenCount * pricePerUnit,
|
|
17746
|
+
costUnit: pricingModel.currency,
|
|
17747
|
+
costMetadata: { ...costMetadata }
|
|
17748
|
+
}
|
|
17749
|
+
};
|
|
17750
|
+
}
|
|
17751
|
+
|
|
17752
|
+
// src/metrics/auto-extract.ts
|
|
17753
|
+
function emitDurationMetrics(span, metrics) {
|
|
17754
|
+
const durationMetricName = getDurationMetricName(span);
|
|
17755
|
+
if (!durationMetricName || !span.startTime || !span.endTime) {
|
|
17756
|
+
return;
|
|
17757
|
+
}
|
|
17758
|
+
const durationMs = span.endTime.getTime() - span.startTime.getTime();
|
|
17759
|
+
metrics.emit(durationMetricName, durationMs, {
|
|
17760
|
+
status: span.errorInfo ? "error" : "ok"
|
|
17761
|
+
});
|
|
17762
|
+
}
|
|
17763
|
+
function emitTokenMetrics(span, metrics) {
|
|
17764
|
+
if (span.type !== SpanType.MODEL_GENERATION) {
|
|
17765
|
+
return;
|
|
17766
|
+
}
|
|
17767
|
+
const attrs = span.attributes;
|
|
17768
|
+
if (!attrs?.usage) {
|
|
17769
|
+
return;
|
|
17770
|
+
}
|
|
17771
|
+
emitUsageMetrics(attrs, attrs.usage, metrics);
|
|
17772
|
+
}
|
|
17773
|
+
function emitAutoExtractedMetrics(span, metrics) {
|
|
17774
|
+
emitDurationMetrics(span, metrics);
|
|
17775
|
+
emitTokenMetrics(span, metrics);
|
|
17776
|
+
}
|
|
17777
|
+
function emitUsageMetrics(attrs, usage, metrics) {
|
|
17778
|
+
let metricCosts = /* @__PURE__ */ new Map();
|
|
17779
|
+
try {
|
|
17780
|
+
const provider = attrs.provider;
|
|
17781
|
+
const model = attrs.responseModel ?? attrs.model;
|
|
17782
|
+
if (provider && model) {
|
|
17783
|
+
metricCosts = estimateCosts({
|
|
17784
|
+
provider,
|
|
17785
|
+
model,
|
|
17786
|
+
usage
|
|
17787
|
+
});
|
|
17788
|
+
}
|
|
17789
|
+
} catch {
|
|
17790
|
+
metricCosts = /* @__PURE__ */ new Map();
|
|
17791
|
+
}
|
|
17792
|
+
const emit = (name, value) => {
|
|
17793
|
+
const costContext = metricCosts.get(name);
|
|
17794
|
+
if (!costContext) {
|
|
17795
|
+
metrics.emit(name, value);
|
|
17796
|
+
return;
|
|
17797
|
+
}
|
|
17798
|
+
metrics.emit(name, value, void 0, { costContext });
|
|
17799
|
+
};
|
|
17800
|
+
for (const sample of getTokenMetricSamples(usage)) {
|
|
17801
|
+
emit(sample.name, sample.value);
|
|
17802
|
+
}
|
|
17803
|
+
}
|
|
17804
|
+
function getDurationMetricName(span) {
|
|
17805
|
+
switch (span.type) {
|
|
17806
|
+
case SpanType.AGENT_RUN:
|
|
17807
|
+
return "mastra_agent_duration_ms";
|
|
17808
|
+
case SpanType.TOOL_CALL:
|
|
17809
|
+
case SpanType.MCP_TOOL_CALL:
|
|
17810
|
+
return "mastra_tool_duration_ms";
|
|
17811
|
+
case SpanType.WORKFLOW_RUN:
|
|
17812
|
+
return "mastra_workflow_duration_ms";
|
|
17813
|
+
case SpanType.MODEL_GENERATION:
|
|
17814
|
+
return "mastra_model_duration_ms";
|
|
17815
|
+
case SpanType.PROCESSOR_RUN:
|
|
17816
|
+
return "mastra_processor_duration_ms";
|
|
17817
|
+
default:
|
|
17818
|
+
return null;
|
|
17819
|
+
}
|
|
17820
|
+
}
|
|
17821
|
+
var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
17822
|
+
var CardinalityFilter = class {
|
|
17823
|
+
blockedLabels;
|
|
17824
|
+
blockUUIDs;
|
|
17825
|
+
/**
|
|
17826
|
+
* @param config - Optional configuration. When omitted, uses
|
|
17827
|
+
* {@link DEFAULT_BLOCKED_LABELS} and blocks UUID-valued labels.
|
|
17828
|
+
*/
|
|
17829
|
+
constructor(config2) {
|
|
17830
|
+
const blocked = config2?.blockedLabels ?? [...DEFAULT_BLOCKED_LABELS];
|
|
17831
|
+
this.blockedLabels = new Set(blocked.map((l) => l.toLowerCase()));
|
|
17832
|
+
this.blockUUIDs = config2?.blockUUIDs ?? true;
|
|
17833
|
+
}
|
|
17834
|
+
/**
|
|
17835
|
+
* Return a copy of `labels` with blocked keys and UUID values removed.
|
|
17836
|
+
*
|
|
17837
|
+
* @param labels - Raw metric labels to filter.
|
|
17838
|
+
* @returns A new object containing only the allowed labels.
|
|
17839
|
+
*/
|
|
17840
|
+
filterLabels(labels) {
|
|
17841
|
+
const filtered = {};
|
|
17842
|
+
for (const [key, value] of Object.entries(labels)) {
|
|
17843
|
+
if (this.blockedLabels.has(key.toLowerCase())) {
|
|
17844
|
+
continue;
|
|
17845
|
+
}
|
|
17846
|
+
if (this.blockUUIDs && UUID_REGEX.test(value)) {
|
|
17847
|
+
continue;
|
|
17848
|
+
}
|
|
17849
|
+
filtered[key] = value;
|
|
17850
|
+
}
|
|
17851
|
+
return filtered;
|
|
17852
|
+
}
|
|
17853
|
+
};
|
|
17424
17854
|
|
|
17425
17855
|
// src/usage.ts
|
|
17426
17856
|
function isDefined(value) {
|
|
@@ -17456,7 +17886,6 @@ function extractUsageMetrics(usage, providerMetadata) {
|
|
|
17456
17886
|
inputDetails.cacheWrite = anthropic.cacheCreationInputTokens;
|
|
17457
17887
|
}
|
|
17458
17888
|
if (isDefined(inputDetails.cacheRead) || isDefined(inputDetails.cacheWrite)) {
|
|
17459
|
-
inputDetails.text = usage.inputTokens;
|
|
17460
17889
|
inputTokens = (usage.inputTokens ?? 0) + (inputDetails.cacheRead ?? 0) + (inputDetails.cacheWrite ?? 0);
|
|
17461
17890
|
}
|
|
17462
17891
|
}
|
|
@@ -17469,6 +17898,15 @@ function extractUsageMetrics(usage, providerMetadata) {
|
|
|
17469
17898
|
outputDetails.reasoning = google.usageMetadata.thoughtsTokenCount;
|
|
17470
17899
|
}
|
|
17471
17900
|
}
|
|
17901
|
+
if (isDefined(inputTokens)) {
|
|
17902
|
+
inputDetails.text = Math.max(
|
|
17903
|
+
0,
|
|
17904
|
+
inputTokens - sumDefinedValues(inputDetails, ["cacheRead", "cacheWrite", "audio", "image"])
|
|
17905
|
+
);
|
|
17906
|
+
}
|
|
17907
|
+
if (isDefined(outputTokens)) {
|
|
17908
|
+
outputDetails.text = Math.max(0, outputTokens - sumDefinedValues(outputDetails, ["reasoning", "audio", "image"]));
|
|
17909
|
+
}
|
|
17472
17910
|
const result = {
|
|
17473
17911
|
inputTokens,
|
|
17474
17912
|
outputTokens
|
|
@@ -17481,6 +17919,9 @@ function extractUsageMetrics(usage, providerMetadata) {
|
|
|
17481
17919
|
}
|
|
17482
17920
|
return result;
|
|
17483
17921
|
}
|
|
17922
|
+
function sumDefinedValues(obj, keys) {
|
|
17923
|
+
return keys.reduce((sum, key) => sum + (obj[key] ?? 0), 0);
|
|
17924
|
+
}
|
|
17484
17925
|
|
|
17485
17926
|
// src/model-tracing.ts
|
|
17486
17927
|
var ModelSpanTracker = class {
|
|
@@ -18187,6 +18628,8 @@ var BaseSpan = class {
|
|
|
18187
18628
|
parentSpanId;
|
|
18188
18629
|
/** Deep clean options for serialization */
|
|
18189
18630
|
deepCleanOptions;
|
|
18631
|
+
/** Cached canonical correlation context for this live span */
|
|
18632
|
+
correlationContext;
|
|
18190
18633
|
constructor(options, observabilityInstance) {
|
|
18191
18634
|
const serializationOptions = observabilityInstance.getConfig().serializationOptions;
|
|
18192
18635
|
this.deepCleanOptions = mergeSerializationOptions(serializationOptions);
|
|
@@ -18268,6 +18711,46 @@ var BaseSpan = class {
|
|
|
18268
18711
|
}
|
|
18269
18712
|
return void 0;
|
|
18270
18713
|
}
|
|
18714
|
+
/** Build and cache the canonical correlation context for this live span. */
|
|
18715
|
+
getCorrelationContext() {
|
|
18716
|
+
if (this.correlationContext) {
|
|
18717
|
+
return this.correlationContext;
|
|
18718
|
+
}
|
|
18719
|
+
const metadata = this.metadata ?? {};
|
|
18720
|
+
const getMetadataString = (key) => typeof metadata[key] === "string" ? metadata[key] : void 0;
|
|
18721
|
+
const parentSpan = this.getParentSpan(false);
|
|
18722
|
+
let rootSpan = this;
|
|
18723
|
+
while (rootSpan.parent) {
|
|
18724
|
+
rootSpan = rootSpan.parent;
|
|
18725
|
+
}
|
|
18726
|
+
const rootTags = rootSpan.tags?.length ? [...rootSpan.tags] : void 0;
|
|
18727
|
+
this.correlationContext = {
|
|
18728
|
+
traceId: this.traceId,
|
|
18729
|
+
spanId: this.id,
|
|
18730
|
+
tags: rootTags,
|
|
18731
|
+
entityType: this.entityType,
|
|
18732
|
+
entityId: this.entityId,
|
|
18733
|
+
entityName: this.entityName,
|
|
18734
|
+
parentEntityType: parentSpan?.entityType,
|
|
18735
|
+
parentEntityId: parentSpan?.entityId,
|
|
18736
|
+
parentEntityName: parentSpan?.entityName,
|
|
18737
|
+
rootEntityType: rootSpan.entityType,
|
|
18738
|
+
rootEntityId: rootSpan.entityId,
|
|
18739
|
+
rootEntityName: rootSpan.entityName,
|
|
18740
|
+
userId: getMetadataString("userId"),
|
|
18741
|
+
organizationId: getMetadataString("organizationId"),
|
|
18742
|
+
resourceId: getMetadataString("resourceId"),
|
|
18743
|
+
runId: getMetadataString("runId"),
|
|
18744
|
+
sessionId: getMetadataString("sessionId"),
|
|
18745
|
+
threadId: getMetadataString("threadId"),
|
|
18746
|
+
requestId: getMetadataString("requestId"),
|
|
18747
|
+
environment: getMetadataString("environment"),
|
|
18748
|
+
source: getMetadataString("source"),
|
|
18749
|
+
serviceName: getMetadataString("serviceName") ?? this.observabilityInstance.getConfig().serviceName,
|
|
18750
|
+
experimentId: getMetadataString("experimentId")
|
|
18751
|
+
};
|
|
18752
|
+
return this.correlationContext;
|
|
18753
|
+
}
|
|
18271
18754
|
/** Returns a lightweight span ready for export */
|
|
18272
18755
|
exportSpan(includeInternalSpans) {
|
|
18273
18756
|
const hideInput = this.traceState?.hideInput ?? false;
|
|
@@ -18522,9 +19005,7 @@ var BaseObservabilityInstance = class extends MastraBase {
|
|
|
18522
19005
|
serializationOptions: config2.serializationOptions
|
|
18523
19006
|
};
|
|
18524
19007
|
this.cardinalityFilter = new CardinalityFilter(config2.cardinality);
|
|
18525
|
-
this.observabilityBus = new ObservabilityBus(
|
|
18526
|
-
cardinalityFilter: this.cardinalityFilter
|
|
18527
|
-
});
|
|
19008
|
+
this.observabilityBus = new ObservabilityBus();
|
|
18528
19009
|
for (const exporter of this.exporters) {
|
|
18529
19010
|
this.observabilityBus.registerExporter(exporter);
|
|
18530
19011
|
}
|
|
@@ -18695,85 +19176,32 @@ var BaseObservabilityInstance = class extends MastraBase {
|
|
|
18695
19176
|
// ============================================================================
|
|
18696
19177
|
// Context-factory bridge methods
|
|
18697
19178
|
// ============================================================================
|
|
18698
|
-
/**
|
|
18699
|
-
* Extract entity context labels from a span's entity hierarchy by
|
|
18700
|
-
* walking the parent chain.
|
|
18701
|
-
*
|
|
18702
|
-
* Returns labels for: entity_type/name, parent_type/name, root_type/name.
|
|
18703
|
-
* Internal spans are skipped when resolving parent and root entities.
|
|
18704
|
-
*/
|
|
18705
|
-
extractEntityLabels(span) {
|
|
18706
|
-
const labels = {};
|
|
18707
|
-
if (span.entityType) labels.entity_type = span.entityType;
|
|
18708
|
-
if (span.entityName) labels.entity_name = span.entityName;
|
|
18709
|
-
let parentSpan = span.parent;
|
|
18710
|
-
while (parentSpan && parentSpan.isInternal) {
|
|
18711
|
-
parentSpan = parentSpan.parent;
|
|
18712
|
-
}
|
|
18713
|
-
if (parentSpan?.entityType && parentSpan.entityName) {
|
|
18714
|
-
labels.parent_type = parentSpan.entityType;
|
|
18715
|
-
labels.parent_name = parentSpan.entityName;
|
|
18716
|
-
let rootEntity = parentSpan;
|
|
18717
|
-
let current = parentSpan.parent;
|
|
18718
|
-
while (current) {
|
|
18719
|
-
if (!current.isInternal && current.entityType && current.entityName) {
|
|
18720
|
-
rootEntity = current;
|
|
18721
|
-
}
|
|
18722
|
-
current = current.parent;
|
|
18723
|
-
}
|
|
18724
|
-
if (rootEntity !== parentSpan) {
|
|
18725
|
-
labels.root_type = rootEntity.entityType;
|
|
18726
|
-
labels.root_name = rootEntity.entityName;
|
|
18727
|
-
}
|
|
18728
|
-
}
|
|
18729
|
-
return labels;
|
|
18730
|
-
}
|
|
18731
|
-
/**
|
|
18732
|
-
* Resolve tags for a span. Uses the span's own tags if present,
|
|
18733
|
-
* otherwise walks to the root span to inherit its tags.
|
|
18734
|
-
*/
|
|
18735
|
-
resolveSpanTags(span) {
|
|
18736
|
-
if (span.tags) return span.tags;
|
|
18737
|
-
let root = span;
|
|
18738
|
-
while (root.parent) {
|
|
18739
|
-
root = root.parent;
|
|
18740
|
-
}
|
|
18741
|
-
return root.tags;
|
|
18742
|
-
}
|
|
18743
19179
|
/**
|
|
18744
19180
|
* Get a LoggerContext correlated to a span.
|
|
18745
19181
|
* Called by the context-factory in core (deriveLoggerContext) so that
|
|
18746
19182
|
* `observabilityContext.loggerVNext` is a real logger instead of no-op.
|
|
18747
19183
|
*/
|
|
18748
19184
|
getLoggerContext(span) {
|
|
18749
|
-
const
|
|
18750
|
-
const
|
|
18751
|
-
const metadata = hasEntityLabels || span?.metadata || this.config.serviceName ? {
|
|
18752
|
-
...hasEntityLabels ? entityLabels : void 0,
|
|
18753
|
-
...span?.metadata,
|
|
18754
|
-
...this.config.serviceName ? { serviceName: this.config.serviceName } : void 0
|
|
18755
|
-
} : void 0;
|
|
19185
|
+
const correlationContext = span?.getCorrelationContext?.();
|
|
19186
|
+
const metadata = span?.metadata ? structuredClone(span.metadata) : void 0;
|
|
18756
19187
|
return new LoggerContextImpl({
|
|
18757
|
-
|
|
18758
|
-
spanId: span?.id,
|
|
18759
|
-
tags: span ? this.resolveSpanTags(span) : void 0,
|
|
19188
|
+
correlationContext,
|
|
18760
19189
|
metadata,
|
|
18761
19190
|
observabilityBus: this.observabilityBus
|
|
18762
19191
|
});
|
|
18763
19192
|
}
|
|
18764
19193
|
/**
|
|
18765
|
-
* Get a MetricsContext
|
|
19194
|
+
* Get a MetricsContext correlated to a span.
|
|
18766
19195
|
* Called by the context-factory in core (deriveMetricsContext) so that
|
|
18767
19196
|
* `observabilityContext.metrics` is a real metrics context instead of no-op.
|
|
18768
19197
|
*/
|
|
18769
19198
|
getMetricsContext(span) {
|
|
18770
|
-
const
|
|
18771
|
-
const
|
|
18772
|
-
if (attrs?.model && typeof attrs.model === "string") labels.model = attrs.model;
|
|
18773
|
-
if (attrs?.provider && typeof attrs.provider === "string") labels.provider = attrs.provider;
|
|
18774
|
-
if (this.config.serviceName) labels.service_name = this.config.serviceName;
|
|
19199
|
+
const correlationContext = span?.getCorrelationContext?.();
|
|
19200
|
+
const metadata = span?.metadata ? structuredClone(span.metadata) : void 0;
|
|
18775
19201
|
return new MetricsContextImpl({
|
|
18776
|
-
|
|
19202
|
+
correlationContext,
|
|
19203
|
+
metadata,
|
|
19204
|
+
cardinalityFilter: this.cardinalityFilter,
|
|
18777
19205
|
observabilityBus: this.observabilityBus
|
|
18778
19206
|
});
|
|
18779
19207
|
}
|
|
@@ -18930,8 +19358,7 @@ var BaseObservabilityInstance = class extends MastraBase {
|
|
|
18930
19358
|
}
|
|
18931
19359
|
/**
|
|
18932
19360
|
* Emit a span started event.
|
|
18933
|
-
* Routes through the ObservabilityBus so exporters receive it via onTracingEvent
|
|
18934
|
-
* and auto-extracted metrics are generated.
|
|
19361
|
+
* Routes through the ObservabilityBus so exporters receive it via onTracingEvent.
|
|
18935
19362
|
*/
|
|
18936
19363
|
emitSpanStarted(span) {
|
|
18937
19364
|
const exportedSpan = this.getSpanForExport(span);
|
|
@@ -18942,20 +19369,24 @@ var BaseObservabilityInstance = class extends MastraBase {
|
|
|
18942
19369
|
}
|
|
18943
19370
|
/**
|
|
18944
19371
|
* Emit a span ended event (called automatically when spans end).
|
|
18945
|
-
*
|
|
18946
|
-
*
|
|
19372
|
+
* Emits any auto-extracted metrics while the live span tree is still available,
|
|
19373
|
+
* then routes the exported tracing event through the ObservabilityBus.
|
|
18947
19374
|
*/
|
|
18948
19375
|
emitSpanEnded(span) {
|
|
18949
19376
|
const exportedSpan = this.getSpanForExport(span);
|
|
18950
19377
|
if (exportedSpan) {
|
|
19378
|
+
try {
|
|
19379
|
+
emitAutoExtractedMetrics(span, this.getMetricsContext(span));
|
|
19380
|
+
} catch (err) {
|
|
19381
|
+
this.logger.error("[Observability] Auto-extraction error:", err);
|
|
19382
|
+
}
|
|
18951
19383
|
const event = { type: TracingEventType.SPAN_ENDED, exportedSpan };
|
|
18952
19384
|
this.emitTracingEvent(event);
|
|
18953
19385
|
}
|
|
18954
19386
|
}
|
|
18955
19387
|
/**
|
|
18956
19388
|
* Emit a span updated event.
|
|
18957
|
-
* Routes through the ObservabilityBus so exporters receive it via onTracingEvent
|
|
18958
|
-
* and auto-extracted metrics are generated.
|
|
19389
|
+
* Routes through the ObservabilityBus so exporters receive it via onTracingEvent.
|
|
18959
19390
|
*/
|
|
18960
19391
|
emitSpanUpdated(span) {
|
|
18961
19392
|
const exportedSpan = this.getSpanForExport(span);
|
|
@@ -18968,8 +19399,7 @@ var BaseObservabilityInstance = class extends MastraBase {
|
|
|
18968
19399
|
* Emit a tracing event through the bus.
|
|
18969
19400
|
*
|
|
18970
19401
|
* The bus routes the event to each registered exporter's and bridge's
|
|
18971
|
-
* onTracingEvent handler
|
|
18972
|
-
* mastra_agent_duration_ms, mastra_model_duration_ms).
|
|
19402
|
+
* onTracingEvent handler.
|
|
18973
19403
|
*/
|
|
18974
19404
|
emitTracingEvent(event) {
|
|
18975
19405
|
this.observabilityBus.emit(event);
|
|
@@ -19442,6 +19872,6 @@ function buildTracingOptions(...updaters) {
|
|
|
19442
19872
|
return updaters.reduce((opts, updater) => updater(opts), {});
|
|
19443
19873
|
}
|
|
19444
19874
|
|
|
19445
|
-
export {
|
|
19875
|
+
export { BaseExporter, BaseObservabilityEventBus, BaseObservabilityInstance, BaseSpan, CardinalityFilter, CloudExporter, ConsoleExporter, DEFAULT_DEEP_CLEAN_OPTIONS, DEFAULT_KEYS_TO_STRIP, DefaultExporter, DefaultObservabilityInstance, DefaultSpan, JsonExporter, LoggerContextImpl, MetricsContextImpl, ModelSpanTracker, NoOpSpan, Observability, ObservabilityBus, SamplingStrategyType, SensitiveDataFilter, TestExporter, TraceData, TrackingExporter, buildTracingOptions, chainFormatters, deepClean, getExternalParentId, mergeSerializationOptions, observabilityConfigValueSchema, observabilityInstanceConfigSchema, observabilityRegistryConfigSchema, routeToHandler, samplingStrategySchema, serializationOptionsSchema, truncateString };
|
|
19446
19876
|
//# sourceMappingURL=index.js.map
|
|
19447
19877
|
//# sourceMappingURL=index.js.map
|