@mastra/observability 1.17.0 → 1.17.1-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/README.md +3 -1
- package/dist/exporters/mastra-platform.d.ts +2 -0
- package/dist/exporters/mastra-platform.d.ts.map +1 -1
- package/dist/index.cjs +241 -49
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +240 -49
- package/dist/index.js.map +1 -1
- package/dist/instances/base.d.ts.map +1 -1
- package/dist/metrics/estimator.d.ts.map +1 -1
- package/dist/metrics/pricing-registry.d.ts.map +1 -1
- package/dist/metrics/types.d.ts +4 -0
- package/dist/metrics/types.d.ts.map +1 -1
- package/dist/metrics/usage-metrics.d.ts.map +1 -1
- package/dist/spans/base.d.ts +2 -0
- package/dist/spans/base.d.ts.map +1 -1
- package/dist/spans/default.d.ts.map +1 -1
- package/dist/spans/metadata.d.ts +22 -0
- package/dist/spans/metadata.d.ts.map +1 -0
- package/dist/spans/serialization.d.ts +0 -5
- package/dist/spans/serialization.d.ts.map +1 -1
- package/dist/usage.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -185,21 +185,15 @@ var BaseObservabilityEventBus = class BaseObservabilityEventBus extends MastraBa
|
|
|
185
185
|
* }
|
|
186
186
|
* ```
|
|
187
187
|
*/
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
"
|
|
194
|
-
|
|
195
|
-
"providerMetadata",
|
|
196
|
-
"steps",
|
|
197
|
-
"tracingContext",
|
|
198
|
-
"execute",
|
|
199
|
-
"validate"
|
|
200
|
-
]);
|
|
188
|
+
const FUNCTION_KEYS_TO_STRIP = /* @__PURE__ */ new Set(["execute", "validate"]);
|
|
189
|
+
const LOGGER_METHODS = [
|
|
190
|
+
"debug",
|
|
191
|
+
"info",
|
|
192
|
+
"warn",
|
|
193
|
+
"error"
|
|
194
|
+
];
|
|
201
195
|
const DEFAULT_DEEP_CLEAN_OPTIONS = Object.freeze({
|
|
202
|
-
keysToStrip:
|
|
196
|
+
keysToStrip: [],
|
|
203
197
|
maxDepth: 8,
|
|
204
198
|
maxStringLength: 128 * 1024,
|
|
205
199
|
maxArrayLength: 50,
|
|
@@ -212,7 +206,7 @@ const DEFAULT_DEEP_CLEAN_OPTIONS = Object.freeze({
|
|
|
212
206
|
function mergeSerializationOptions(userOptions) {
|
|
213
207
|
if (!userOptions) return DEFAULT_DEEP_CLEAN_OPTIONS;
|
|
214
208
|
return {
|
|
215
|
-
keysToStrip:
|
|
209
|
+
keysToStrip: DEFAULT_DEEP_CLEAN_OPTIONS.keysToStrip,
|
|
216
210
|
maxDepth: userOptions.maxDepth ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxDepth,
|
|
217
211
|
maxStringLength: userOptions.maxStringLength ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxStringLength,
|
|
218
212
|
maxArrayLength: userOptions.maxArrayLength ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxArrayLength,
|
|
@@ -238,6 +232,47 @@ function getMapKeyType(key) {
|
|
|
238
232
|
if (key instanceof Error) return "error";
|
|
239
233
|
return typeof key;
|
|
240
234
|
}
|
|
235
|
+
function hasOnlyKnownKeys(value, keys) {
|
|
236
|
+
try {
|
|
237
|
+
return Object.keys(value).every((key) => keys.includes(key));
|
|
238
|
+
} catch {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
function isSpanLike(value) {
|
|
243
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
244
|
+
const span = value;
|
|
245
|
+
try {
|
|
246
|
+
return typeof span.id === "string" && typeof span.traceId === "string" && typeof span.type === "string" && typeof span.name === "string";
|
|
247
|
+
} catch {
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function isTracingContextLike(value) {
|
|
252
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
253
|
+
const context = value;
|
|
254
|
+
if (!hasOnlyKnownKeys(context, ["currentSpan"])) return false;
|
|
255
|
+
try {
|
|
256
|
+
return context.currentSpan === void 0 || isSpanLike(context.currentSpan);
|
|
257
|
+
} catch {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
function isLoggerLike(value) {
|
|
262
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
263
|
+
const logger = value;
|
|
264
|
+
try {
|
|
265
|
+
return LOGGER_METHODS.some((method) => typeof logger[method] === "function");
|
|
266
|
+
} catch {
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function shouldStripEntry(key, value, stripSet) {
|
|
271
|
+
if (stripSet.has(key)) return true;
|
|
272
|
+
if (key === "tracingContext" && isTracingContextLike(value)) return true;
|
|
273
|
+
if (key === "logger") return typeof value === "function" || isLoggerLike(value);
|
|
274
|
+
return FUNCTION_KEYS_TO_STRIP.has(key) && typeof value === "function";
|
|
275
|
+
}
|
|
241
276
|
function restoreSerializedMapKey(keyType, key) {
|
|
242
277
|
switch (keyType) {
|
|
243
278
|
case "undefined": return;
|
|
@@ -340,7 +375,7 @@ function deepClean(value, options = DEFAULT_DEEP_CLEAN_OPTIONS) {
|
|
|
340
375
|
let mapKeyCount = 0;
|
|
341
376
|
let omittedMapEntries = 0;
|
|
342
377
|
for (const [mapKey, mapVal] of val) {
|
|
343
|
-
if (typeof mapKey === "string" &&
|
|
378
|
+
if (typeof mapKey === "string" && shouldStripEntry(mapKey, mapVal, stripSet)) continue;
|
|
344
379
|
if (mapKeyCount >= maxObjectKeys) {
|
|
345
380
|
omittedMapEntries++;
|
|
346
381
|
continue;
|
|
@@ -416,15 +451,34 @@ function deepClean(value, options = DEFAULT_DEEP_CLEAN_OPTIONS) {
|
|
|
416
451
|
}
|
|
417
452
|
if (looksLikeJsonSchema) return val;
|
|
418
453
|
const cleaned = {};
|
|
419
|
-
|
|
454
|
+
let keys;
|
|
455
|
+
try {
|
|
456
|
+
keys = Object.keys(val);
|
|
457
|
+
} catch (error) {
|
|
458
|
+
return formatSerializationError(error);
|
|
459
|
+
}
|
|
420
460
|
let keyCount = 0;
|
|
421
461
|
for (const key of keys) {
|
|
462
|
+
if (stripSet.has(key)) continue;
|
|
463
|
+
let rawValue;
|
|
464
|
+
try {
|
|
465
|
+
rawValue = val[key];
|
|
466
|
+
} catch (error) {
|
|
467
|
+
if (keyCount >= maxObjectKeys) {
|
|
468
|
+
cleaned["__truncated"] = `${keys.length - keyCount} more keys omitted`;
|
|
469
|
+
break;
|
|
470
|
+
}
|
|
471
|
+
cleaned[key] = formatSerializationError(error);
|
|
472
|
+
keyCount++;
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
if (shouldStripEntry(key, rawValue, stripSet)) continue;
|
|
422
476
|
if (keyCount >= maxObjectKeys) {
|
|
423
477
|
cleaned["__truncated"] = `${keys.length - keyCount} more keys omitted`;
|
|
424
478
|
break;
|
|
425
479
|
}
|
|
426
480
|
try {
|
|
427
|
-
cleaned[key] = helper(
|
|
481
|
+
cleaned[key] = helper(rawValue, depth + 1);
|
|
428
482
|
keyCount++;
|
|
429
483
|
} catch (error) {
|
|
430
484
|
cleaned[key] = formatSerializationError(error);
|
|
@@ -1023,6 +1077,8 @@ const MINIFIED_METER_TO_CANONICAL = {
|
|
|
1023
1077
|
ot: "output_tokens",
|
|
1024
1078
|
icrt: "input_cache_read_tokens",
|
|
1025
1079
|
icwt: "input_cache_write_tokens",
|
|
1080
|
+
icwt5m: "input_cache_write_5m_tokens",
|
|
1081
|
+
icwt1h: "input_cache_write_1h_tokens",
|
|
1026
1082
|
iat: "input_audio_tokens",
|
|
1027
1083
|
oat: "output_audio_tokens",
|
|
1028
1084
|
ort: "output_reasoning_tokens"
|
|
@@ -1079,6 +1135,15 @@ function parsePricingModelText(content) {
|
|
|
1079
1135
|
}
|
|
1080
1136
|
return pricingModels;
|
|
1081
1137
|
}
|
|
1138
|
+
function expandRates(row, tier) {
|
|
1139
|
+
const rates = Object.fromEntries(Object.entries(tier.r).map(([meter, value]) => [MINIFIED_METER_TO_CANONICAL[meter], value.c]));
|
|
1140
|
+
const cacheWriteRate = rates.input_cache_write_tokens;
|
|
1141
|
+
if (row.m.includes("claude") && typeof cacheWriteRate === "number") {
|
|
1142
|
+
rates.input_cache_write_5m_tokens ??= cacheWriteRate;
|
|
1143
|
+
rates.input_cache_write_1h_tokens ??= cacheWriteRate * 1.6;
|
|
1144
|
+
}
|
|
1145
|
+
return rates;
|
|
1146
|
+
}
|
|
1082
1147
|
function expandPricingModelRow(row) {
|
|
1083
1148
|
return new PricingModel({
|
|
1084
1149
|
id: row.i,
|
|
@@ -1093,7 +1158,7 @@ function expandPricingModelRow(row) {
|
|
|
1093
1158
|
op: condition.op,
|
|
1094
1159
|
value: condition.value
|
|
1095
1160
|
})),
|
|
1096
|
-
rates:
|
|
1161
|
+
rates: expandRates(row, tier)
|
|
1097
1162
|
}))
|
|
1098
1163
|
});
|
|
1099
1164
|
}
|
|
@@ -1224,6 +1289,8 @@ const PricingMeter = {
|
|
|
1224
1289
|
INPUT_AUDIO_TOKENS: "input_audio_tokens",
|
|
1225
1290
|
INPUT_CACHE_READ_TOKENS: "input_cache_read_tokens",
|
|
1226
1291
|
INPUT_CACHE_WRITE_TOKENS: "input_cache_write_tokens",
|
|
1292
|
+
INPUT_CACHE_WRITE_5M_TOKENS: "input_cache_write_5m_tokens",
|
|
1293
|
+
INPUT_CACHE_WRITE_1H_TOKENS: "input_cache_write_1h_tokens",
|
|
1227
1294
|
INPUT_IMAGE_TOKENS: "input_image_tokens",
|
|
1228
1295
|
OUTPUT_TOKENS: "output_tokens",
|
|
1229
1296
|
OUTPUT_AUDIO_TOKENS: "output_audio_tokens",
|
|
@@ -1236,6 +1303,8 @@ const TokenMetrics = {
|
|
|
1236
1303
|
INPUT_TEXT: "mastra_model_input_text_tokens",
|
|
1237
1304
|
INPUT_CACHE_READ: "mastra_model_input_cache_read_tokens",
|
|
1238
1305
|
INPUT_CACHE_WRITE: "mastra_model_input_cache_write_tokens",
|
|
1306
|
+
INPUT_CACHE_WRITE_5M: "mastra_model_input_cache_write_5m_tokens",
|
|
1307
|
+
INPUT_CACHE_WRITE_1H: "mastra_model_input_cache_write_1h_tokens",
|
|
1239
1308
|
INPUT_AUDIO: "mastra_model_input_audio_tokens",
|
|
1240
1309
|
INPUT_IMAGE: "mastra_model_input_image_tokens",
|
|
1241
1310
|
OUTPUT_TEXT: "mastra_model_output_text_tokens",
|
|
@@ -1265,6 +1334,8 @@ function getTokenMetricSamples(usage) {
|
|
|
1265
1334
|
pushIfPositive(TokenMetrics.INPUT_TEXT, usage.inputDetails.text);
|
|
1266
1335
|
pushIfPositive(TokenMetrics.INPUT_CACHE_READ, usage.inputDetails.cacheRead);
|
|
1267
1336
|
pushIfPositive(TokenMetrics.INPUT_CACHE_WRITE, usage.inputDetails.cacheWrite);
|
|
1337
|
+
pushIfPositive(TokenMetrics.INPUT_CACHE_WRITE_5M, usage.inputDetails.cacheWrite5m);
|
|
1338
|
+
pushIfPositive(TokenMetrics.INPUT_CACHE_WRITE_1H, usage.inputDetails.cacheWrite1h);
|
|
1268
1339
|
pushIfPositive(TokenMetrics.INPUT_AUDIO, usage.inputDetails.audio);
|
|
1269
1340
|
pushIfPositive(TokenMetrics.INPUT_IMAGE, usage.inputDetails.image);
|
|
1270
1341
|
}
|
|
@@ -1331,15 +1402,40 @@ function estimateCosts(args, pricingRegistry = PricingRegistry.getGlobal()) {
|
|
|
1331
1402
|
results.set(TokenMetrics.INPUT_CACHE_READ, result.costContext);
|
|
1332
1403
|
inputDetailResults.push(result);
|
|
1333
1404
|
}
|
|
1334
|
-
|
|
1405
|
+
const cacheWriteDetailResults = [];
|
|
1406
|
+
const cacheWrite5m = usage.inputDetails?.cacheWrite5m ?? 0;
|
|
1407
|
+
const cacheWrite1h = usage.inputDetails?.cacheWrite1h ?? 0;
|
|
1408
|
+
if (cacheWrite5m > 0) {
|
|
1409
|
+
const result = estimateCostForMeter({
|
|
1410
|
+
meter: PricingMeter.INPUT_CACHE_WRITE_5M_TOKENS,
|
|
1411
|
+
tokenCount: cacheWrite5m,
|
|
1412
|
+
...estimateFields
|
|
1413
|
+
});
|
|
1414
|
+
results.set(TokenMetrics.INPUT_CACHE_WRITE_5M, result.costContext);
|
|
1415
|
+
cacheWriteDetailResults.push(result);
|
|
1416
|
+
inputDetailResults.push(result);
|
|
1417
|
+
}
|
|
1418
|
+
if (cacheWrite1h > 0) {
|
|
1419
|
+
const result = estimateCostForMeter({
|
|
1420
|
+
meter: PricingMeter.INPUT_CACHE_WRITE_1H_TOKENS,
|
|
1421
|
+
tokenCount: cacheWrite1h,
|
|
1422
|
+
...estimateFields
|
|
1423
|
+
});
|
|
1424
|
+
results.set(TokenMetrics.INPUT_CACHE_WRITE_1H, result.costContext);
|
|
1425
|
+
cacheWriteDetailResults.push(result);
|
|
1426
|
+
inputDetailResults.push(result);
|
|
1427
|
+
}
|
|
1428
|
+
const unclassifiedCacheWrite = Math.max(0, (usage.inputDetails?.cacheWrite ?? 0) - cacheWrite5m - cacheWrite1h);
|
|
1429
|
+
if (unclassifiedCacheWrite > 0) {
|
|
1335
1430
|
const result = estimateCostForMeter({
|
|
1336
1431
|
meter: PricingMeter.INPUT_CACHE_WRITE_TOKENS,
|
|
1337
|
-
tokenCount:
|
|
1432
|
+
tokenCount: unclassifiedCacheWrite,
|
|
1338
1433
|
...estimateFields
|
|
1339
1434
|
});
|
|
1340
|
-
|
|
1435
|
+
cacheWriteDetailResults.push(result);
|
|
1341
1436
|
inputDetailResults.push(result);
|
|
1342
1437
|
}
|
|
1438
|
+
if (cacheWriteDetailResults.length > 0) setCombinedCostContext(results, TokenMetrics.INPUT_CACHE_WRITE, cacheWriteDetailResults, pricingModel, costMetadata);
|
|
1343
1439
|
if (usage.inputDetails?.image) {
|
|
1344
1440
|
const result = estimateCostForMeter({
|
|
1345
1441
|
meter: PricingMeter.INPUT_IMAGE_TOKENS,
|
|
@@ -1416,6 +1512,20 @@ function estimateCosts(args, pricingRegistry = PricingRegistry.getGlobal()) {
|
|
|
1416
1512
|
function applyErrorContextForUsage(results, usage, errorContext) {
|
|
1417
1513
|
for (const sample of getTokenMetricSamples(usage)) results.set(sample.name, errorContext);
|
|
1418
1514
|
}
|
|
1515
|
+
function setCombinedCostContext(results, metric, detailResults, pricingModel, costMetadata) {
|
|
1516
|
+
const estimatedCosts = detailResults.map((result) => result.costContext.estimatedCost).filter((value) => typeof value === "number");
|
|
1517
|
+
const hasFailedCost = detailResults.some((result) => !result.success);
|
|
1518
|
+
results.set(metric, {
|
|
1519
|
+
provider: pricingModel.provider,
|
|
1520
|
+
model: pricingModel.model,
|
|
1521
|
+
...estimatedCosts.length > 0 && { estimatedCost: estimatedCosts.reduce((sum, value) => sum + value, 0) },
|
|
1522
|
+
...estimatedCosts.length > 0 && { costUnit: pricingModel.currency },
|
|
1523
|
+
costMetadata: hasFailedCost ? {
|
|
1524
|
+
...costMetadata,
|
|
1525
|
+
error: "partial_cost"
|
|
1526
|
+
} : { ...costMetadata }
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1419
1529
|
function setAggregateCostContext(args) {
|
|
1420
1530
|
const { results, totalMetric, fallbackMeter, totalTokenCount, detailResults, pricingModel, pricingTier, costMetadata } = args;
|
|
1421
1531
|
if (totalTokenCount == null) return;
|
|
@@ -1656,14 +1766,24 @@ function extractUsageMetrics(usage, providerMetadata) {
|
|
|
1656
1766
|
if (isDefined(aiSdkDetails?.cacheReadTokens)) inputDetails.cacheRead = aiSdkDetails.cacheReadTokens;
|
|
1657
1767
|
if (isDefined(aiSdkDetails?.cacheWriteTokens)) inputDetails.cacheWrite = aiSdkDetails.cacheWriteTokens;
|
|
1658
1768
|
if (!isDefined(inputDetails.cacheRead) && isDefined(usage.cachedInputTokens)) inputDetails.cacheRead = usage.cachedInputTokens;
|
|
1769
|
+
if (isDefined(usage.cacheCreationInputTokens5m)) inputDetails.cacheWrite5m = usage.cacheCreationInputTokens5m;
|
|
1770
|
+
if (isDefined(usage.cacheCreationInputTokens1h)) inputDetails.cacheWrite1h = usage.cacheCreationInputTokens1h;
|
|
1659
1771
|
if (!isDefined(inputDetails.cacheWrite) && isDefined(usage.cacheCreationInputTokens)) inputDetails.cacheWrite = usage.cacheCreationInputTokens;
|
|
1772
|
+
if (!isDefined(inputDetails.cacheWrite) && (isDefined(inputDetails.cacheWrite5m) || isDefined(inputDetails.cacheWrite1h))) inputDetails.cacheWrite = (inputDetails.cacheWrite5m ?? 0) + (inputDetails.cacheWrite1h ?? 0);
|
|
1660
1773
|
if (isDefined(usage.reasoningTokens)) outputDetails.reasoning = usage.reasoningTokens;
|
|
1661
1774
|
const anthropic = providerMetadata?.anthropic;
|
|
1662
1775
|
if (anthropic) {
|
|
1663
1776
|
const rawV3InputUsage = isV3RawUsage(usage.raw) ? usage.raw.inputTokens : void 0;
|
|
1664
1777
|
const hasV3CachedTotals = rawV3InputUsage?.total !== void 0 && (rawV3InputUsage.cacheRead !== void 0 || rawV3InputUsage.cacheWrite !== void 0);
|
|
1665
1778
|
if (!isDefined(inputDetails.cacheRead) && isDefined(anthropic.cacheReadInputTokens)) inputDetails.cacheRead = anthropic.cacheReadInputTokens;
|
|
1666
|
-
|
|
1779
|
+
const cacheWrite5m = anthropic.cacheCreation?.ephemeral_5m_input_tokens ?? anthropic.cacheCreation?.ephemeral5mInputTokens;
|
|
1780
|
+
const cacheWrite1h = anthropic.cacheCreation?.ephemeral_1h_input_tokens ?? anthropic.cacheCreation?.ephemeral1hInputTokens;
|
|
1781
|
+
if (!isDefined(inputDetails.cacheWrite5m) && isDefined(cacheWrite5m)) inputDetails.cacheWrite5m = cacheWrite5m;
|
|
1782
|
+
if (!isDefined(inputDetails.cacheWrite1h) && isDefined(cacheWrite1h)) inputDetails.cacheWrite1h = cacheWrite1h;
|
|
1783
|
+
if (!isDefined(inputDetails.cacheWrite)) {
|
|
1784
|
+
if (isDefined(anthropic.cacheCreationInputTokens)) inputDetails.cacheWrite = anthropic.cacheCreationInputTokens;
|
|
1785
|
+
else if (isDefined(cacheWrite5m) || isDefined(cacheWrite1h)) inputDetails.cacheWrite = (cacheWrite5m ?? 0) + (cacheWrite1h ?? 0);
|
|
1786
|
+
}
|
|
1667
1787
|
if (!(hasV3CachedTotals || isDefined(usage.cachedInputTokens) && usage.cachedInputTokens > 0 || isDefined(usage.cacheCreationInputTokens) && usage.cacheCreationInputTokens > 0) && (isDefined(inputDetails.cacheRead) || isDefined(inputDetails.cacheWrite))) inputTokens = (usage.inputTokens ?? 0) + (inputDetails.cacheRead ?? 0) + (inputDetails.cacheWrite ?? 0);
|
|
1668
1788
|
}
|
|
1669
1789
|
const google = providerMetadata?.google;
|
|
@@ -1704,6 +1824,8 @@ function mergeInputDetails(a, b) {
|
|
|
1704
1824
|
text: addOptional(a.text, b.text),
|
|
1705
1825
|
cacheRead: addOptional(a.cacheRead, b.cacheRead),
|
|
1706
1826
|
cacheWrite: addOptional(a.cacheWrite, b.cacheWrite),
|
|
1827
|
+
cacheWrite5m: addOptional(a.cacheWrite5m, b.cacheWrite5m),
|
|
1828
|
+
cacheWrite1h: addOptional(a.cacheWrite1h, b.cacheWrite1h),
|
|
1707
1829
|
audio: addOptional(a.audio, b.audio),
|
|
1708
1830
|
image: addOptional(a.image, b.image)
|
|
1709
1831
|
};
|
|
@@ -2437,6 +2559,49 @@ var ModelSpanTracker = class {
|
|
|
2437
2559
|
}
|
|
2438
2560
|
};
|
|
2439
2561
|
//#endregion
|
|
2562
|
+
//#region src/spans/metadata.ts
|
|
2563
|
+
/**
|
|
2564
|
+
* Shared span-metadata helpers.
|
|
2565
|
+
*
|
|
2566
|
+
* Used by both the observability instance (`instances/base.ts`) and the span
|
|
2567
|
+
* base class (`spans/base.ts`) so the plain-record check and the
|
|
2568
|
+
* descriptor-preserving merge stay in a single place. Both feed the same span
|
|
2569
|
+
* metadata pipeline, so keeping one implementation avoids divergence.
|
|
2570
|
+
*/
|
|
2571
|
+
/**
|
|
2572
|
+
* Returns true only for plain object records (prototype is `Object.prototype`
|
|
2573
|
+
* or `null`). Maps, Dates, class instances, and arrays return false so callers
|
|
2574
|
+
* can preserve their original shape instead of shallow-copying them into `{}`.
|
|
2575
|
+
*/
|
|
2576
|
+
function isPlainRecord(value) {
|
|
2577
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
2578
|
+
try {
|
|
2579
|
+
const prototype = Object.getPrototypeOf(value);
|
|
2580
|
+
return prototype === Object.prototype || prototype === null;
|
|
2581
|
+
} catch {
|
|
2582
|
+
return false;
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
/**
|
|
2586
|
+
* Merges two metadata values while preserving property descriptors (so getters
|
|
2587
|
+
* are copied as accessors rather than eagerly invoked). Only plain records are
|
|
2588
|
+
* merged; if either side is non-plain the second argument is returned as-is,
|
|
2589
|
+
* matching the previous per-module behavior.
|
|
2590
|
+
*/
|
|
2591
|
+
function mergeMetadata$1(parentMetadata, metadata) {
|
|
2592
|
+
if (!parentMetadata) return metadata;
|
|
2593
|
+
if (!metadata) return parentMetadata;
|
|
2594
|
+
if (!isPlainRecord(parentMetadata) || !isPlainRecord(metadata)) return metadata;
|
|
2595
|
+
try {
|
|
2596
|
+
const merged = {};
|
|
2597
|
+
Object.defineProperties(merged, Object.getOwnPropertyDescriptors(parentMetadata));
|
|
2598
|
+
Object.defineProperties(merged, Object.getOwnPropertyDescriptors(metadata));
|
|
2599
|
+
return merged;
|
|
2600
|
+
} catch {
|
|
2601
|
+
return metadata;
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
//#endregion
|
|
2440
2605
|
//#region src/spans/base.ts
|
|
2441
2606
|
/**
|
|
2442
2607
|
* Determines if a span type should be considered internal based on flags.
|
|
@@ -2561,10 +2726,7 @@ var BaseSpan = class {
|
|
|
2561
2726
|
this.type = options.type;
|
|
2562
2727
|
this.isInternal = isSpanInternal(this.type, options.tracingPolicy?.internal);
|
|
2563
2728
|
this.isExcluded = this.alwaysExcluded || observabilityConfig.excludeSpanTypes?.includes(this.type) === true || this.isInternal && !observabilityConfig.includeInternalSpans;
|
|
2564
|
-
this.metadata = deepClean(options.parent?.metadata
|
|
2565
|
-
...options.parent?.metadata,
|
|
2566
|
-
...options.metadata
|
|
2567
|
-
} : void 0, this.deepCleanOptions);
|
|
2729
|
+
this.metadata = deepClean(this.prepareSpanMetadata(mergeMetadata$1(options.parent?.metadata, options.metadata)), this.deepCleanOptions);
|
|
2568
2730
|
this.parent = options.parent;
|
|
2569
2731
|
this.startTime = options.startTime ?? /* @__PURE__ */ new Date();
|
|
2570
2732
|
this.observabilityInstance = observabilityInstance;
|
|
@@ -2582,9 +2744,32 @@ var BaseSpan = class {
|
|
|
2582
2744
|
}
|
|
2583
2745
|
this.attributes = deepClean(options.attributes, this.deepCleanOptions) || {};
|
|
2584
2746
|
if (options.requestContext && options.requestContext.size() > 0) this.requestContext = deepClean(options.requestContext, this.deepCleanOptions);
|
|
2585
|
-
if (this.isEvent) this.output = deepClean(options.output, this.deepCleanOptions);
|
|
2747
|
+
if (this.isEvent) this.output = deepClean(this.prepareSpanOutput(options.output), this.deepCleanOptions);
|
|
2586
2748
|
else this.input = deepClean(options.input, this.deepCleanOptions);
|
|
2587
2749
|
}
|
|
2750
|
+
prepareSpanOutput(value) {
|
|
2751
|
+
if (!isPlainRecord(value)) return value;
|
|
2752
|
+
if (this.type !== SpanType.MODEL_STEP && this.type !== SpanType.MODEL_INFERENCE) return value;
|
|
2753
|
+
try {
|
|
2754
|
+
const prepared = { ...value };
|
|
2755
|
+
delete prepared.steps;
|
|
2756
|
+
return prepared;
|
|
2757
|
+
} catch {
|
|
2758
|
+
return value;
|
|
2759
|
+
}
|
|
2760
|
+
}
|
|
2761
|
+
prepareSpanMetadata(value) {
|
|
2762
|
+
if (!isPlainRecord(value)) return value;
|
|
2763
|
+
if (this.type !== SpanType.MODEL_STEP) return value;
|
|
2764
|
+
try {
|
|
2765
|
+
const prepared = { ...value };
|
|
2766
|
+
delete prepared.providerMetadata;
|
|
2767
|
+
delete prepared.experimental_providerMetadata;
|
|
2768
|
+
return prepared;
|
|
2769
|
+
} catch {
|
|
2770
|
+
return value;
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
2588
2773
|
createChildSpan(options) {
|
|
2589
2774
|
return this.observabilityInstance.startSpan({
|
|
2590
2775
|
...options,
|
|
@@ -2791,10 +2976,10 @@ var DefaultSpan = class extends BaseSpan {
|
|
|
2791
2976
|
this.endTime = /* @__PURE__ */ new Date();
|
|
2792
2977
|
if (options?.metadata) this.metadata = {
|
|
2793
2978
|
...this.metadata,
|
|
2794
|
-
...deepClean(options.metadata, this.deepCleanOptions)
|
|
2979
|
+
...deepClean(this.prepareSpanMetadata(options.metadata), this.deepCleanOptions)
|
|
2795
2980
|
};
|
|
2796
2981
|
if (this.isExcluded) return;
|
|
2797
|
-
if (options?.output !== void 0) this.output = deepClean(options.output, this.deepCleanOptions);
|
|
2982
|
+
if (options?.output !== void 0) this.output = deepClean(this.prepareSpanOutput(options.output), this.deepCleanOptions);
|
|
2798
2983
|
if (options?.attributes) this.attributes = {
|
|
2799
2984
|
...this.attributes,
|
|
2800
2985
|
...deepClean(options.attributes, this.deepCleanOptions)
|
|
@@ -2805,7 +2990,7 @@ var DefaultSpan = class extends BaseSpan {
|
|
|
2805
2990
|
const { error, endSpan = true, attributes, metadata } = options;
|
|
2806
2991
|
if (metadata) this.metadata = {
|
|
2807
2992
|
...this.metadata,
|
|
2808
|
-
...deepClean(metadata, this.deepCleanOptions)
|
|
2993
|
+
...deepClean(this.prepareSpanMetadata(metadata), this.deepCleanOptions)
|
|
2809
2994
|
};
|
|
2810
2995
|
if (!this.isExcluded) {
|
|
2811
2996
|
this.errorInfo = deepClean(error instanceof MastraError ? {
|
|
@@ -2834,11 +3019,11 @@ var DefaultSpan = class extends BaseSpan {
|
|
|
2834
3019
|
if (options.name !== void 0) this.name = options.name;
|
|
2835
3020
|
if (options.metadata) this.metadata = {
|
|
2836
3021
|
...this.metadata,
|
|
2837
|
-
...deepClean(options.metadata, this.deepCleanOptions)
|
|
3022
|
+
...deepClean(this.prepareSpanMetadata(options.metadata), this.deepCleanOptions)
|
|
2838
3023
|
};
|
|
2839
3024
|
if (this.isExcluded) return;
|
|
2840
3025
|
if (options.input !== void 0) this.input = deepClean(options.input, this.deepCleanOptions);
|
|
2841
|
-
if (options.output !== void 0) this.output = deepClean(options.output, this.deepCleanOptions);
|
|
3026
|
+
if (options.output !== void 0) this.output = deepClean(this.prepareSpanOutput(options.output), this.deepCleanOptions);
|
|
2842
3027
|
if (options.attributes) this.attributes = {
|
|
2843
3028
|
...this.attributes,
|
|
2844
3029
|
...deepClean(options.attributes, this.deepCleanOptions)
|
|
@@ -2926,6 +3111,19 @@ var NoOpSpan = class extends BaseSpan {
|
|
|
2926
3111
|
/**
|
|
2927
3112
|
* BaseObservability - Abstract base class for Observability implementations
|
|
2928
3113
|
*/
|
|
3114
|
+
function hasMetadataKey(metadata, key) {
|
|
3115
|
+
if (!metadata || typeof metadata !== "object") return false;
|
|
3116
|
+
try {
|
|
3117
|
+
return Object.prototype.hasOwnProperty.call(Object.getOwnPropertyDescriptors(metadata), key);
|
|
3118
|
+
} catch {
|
|
3119
|
+
return true;
|
|
3120
|
+
}
|
|
3121
|
+
}
|
|
3122
|
+
function injectEnvironmentMetadata(metadata, environment) {
|
|
3123
|
+
if (environment === void 0 || hasMetadataKey(metadata, "environment")) return metadata;
|
|
3124
|
+
if (metadata && !isPlainRecord(metadata)) return metadata;
|
|
3125
|
+
return mergeMetadata$1(metadata, { environment });
|
|
3126
|
+
}
|
|
2929
3127
|
/**
|
|
2930
3128
|
* Abstract base class for all Observability implementations in Mastra.
|
|
2931
3129
|
*/
|
|
@@ -3021,16 +3219,9 @@ var BaseObservabilityInstance = class extends MastraBase {
|
|
|
3021
3219
|
let traceState;
|
|
3022
3220
|
if (options.parent) traceState = options.parent.traceState;
|
|
3023
3221
|
else traceState = this.computeTraceState(tracingOptions);
|
|
3024
|
-
const
|
|
3025
|
-
const mergedMetadata = metadata || tracingMetadata ? {
|
|
3026
|
-
...metadata,
|
|
3027
|
-
...tracingMetadata
|
|
3028
|
-
} : void 0;
|
|
3222
|
+
const mergedMetadata = mergeMetadata$1(metadata, !options.parent ? tracingOptions?.metadata : void 0);
|
|
3029
3223
|
const enrichedMetadata = this.extractMetadataFromRequestContext(requestContext, mergedMetadata, traceState);
|
|
3030
|
-
const finalMetadata = !options.parent
|
|
3031
|
-
...enrichedMetadata ?? {},
|
|
3032
|
-
environment: this.#mastraEnvironment
|
|
3033
|
-
} : enrichedMetadata;
|
|
3224
|
+
const finalMetadata = !options.parent ? injectEnvironmentMetadata(enrichedMetadata, this.#mastraEnvironment) : enrichedMetadata;
|
|
3034
3225
|
const tags = !options.parent ? tracingOptions?.tags : void 0;
|
|
3035
3226
|
const traceId = !options.parent ? options.traceId ?? tracingOptions?.traceId : options.traceId;
|
|
3036
3227
|
const parentSpanId = options.parentSpanId;
|
|
@@ -3295,10 +3486,7 @@ var BaseObservabilityInstance = class extends MastraBase {
|
|
|
3295
3486
|
if (!requestContext || !traceState || traceState.requestContextKeys.length === 0) return explicitMetadata;
|
|
3296
3487
|
const extracted = this.extractKeys(requestContext, traceState.requestContextKeys);
|
|
3297
3488
|
if (Object.keys(extracted).length === 0 && !explicitMetadata) return;
|
|
3298
|
-
return
|
|
3299
|
-
...extracted,
|
|
3300
|
-
...explicitMetadata
|
|
3301
|
-
};
|
|
3489
|
+
return mergeMetadata$1(extracted, explicitMetadata);
|
|
3302
3490
|
}
|
|
3303
3491
|
/**
|
|
3304
3492
|
* Extract specific keys from RequestContext
|
|
@@ -6345,6 +6533,8 @@ const QUOTA_EXCEEDED_STATUS = 402;
|
|
|
6345
6533
|
const OBSERVABILITY_STATUS_HEADER = "x-mastra-observability";
|
|
6346
6534
|
const OBSERVABILITY_DISABLED_VALUE = "disabled";
|
|
6347
6535
|
const OBSERVABILITY_RETRY_AFTER_HEADER = "x-mastra-observability-retry-after";
|
|
6536
|
+
const OBSERVABILITY_CAPABILITIES_HEADER = "x-mastra-observability-capabilities";
|
|
6537
|
+
const QUOTA_PAUSE_CAPABILITY = "quota-pause-v1";
|
|
6348
6538
|
const DEFAULT_QUOTA_PROBE_INTERVAL_SECONDS = 300;
|
|
6349
6539
|
const MAX_QUOTA_PROBE_INTERVAL_SECONDS = Math.floor(2147483647 / 1e3);
|
|
6350
6540
|
function isObservabilityDisabled(response) {
|
|
@@ -6671,7 +6861,8 @@ var MastraPlatformExporter = class extends BaseExporter {
|
|
|
6671
6861
|
buildPublishHeaders() {
|
|
6672
6862
|
return {
|
|
6673
6863
|
Authorization: `Bearer ${this.platformConfig.accessToken}`,
|
|
6674
|
-
"Content-Type": "application/json"
|
|
6864
|
+
"Content-Type": "application/json",
|
|
6865
|
+
[OBSERVABILITY_CAPABILITIES_HEADER]: QUOTA_PAUSE_CAPABILITY
|
|
6675
6866
|
};
|
|
6676
6867
|
}
|
|
6677
6868
|
buildPublishBody(signal, records) {
|
|
@@ -6724,7 +6915,7 @@ var MastraPlatformExporter = class extends BaseExporter {
|
|
|
6724
6915
|
this.flushTimer = null;
|
|
6725
6916
|
}
|
|
6726
6917
|
this.resetBuffer();
|
|
6727
|
-
this.logger.warn(`Mastra observability paused: quota exhausted
|
|
6918
|
+
this.logger.warn(`Mastra observability export paused: platform quota exhausted (OBSERVABILITY_QUOTA_EXCEEDED). Dropping telemetry and retrying in ${retryAfterSeconds} seconds. Check Platform billing/usage to restore telemetry.`);
|
|
6728
6919
|
this.scheduleQuotaProbe();
|
|
6729
6920
|
}
|
|
6730
6921
|
scheduleQuotaProbe() {
|
|
@@ -9299,6 +9490,6 @@ function buildTracingOptions(...updaters) {
|
|
|
9299
9490
|
return updaters.reduce((opts, updater) => updater(opts), {});
|
|
9300
9491
|
}
|
|
9301
9492
|
//#endregion
|
|
9302
|
-
export { BaseExporter, BaseObservabilityEventBus, BaseObservabilityInstance, BaseSpan, CardinalityFilter, CloudExporter, ConsoleExporter, DEFAULT_DEEP_CLEAN_OPTIONS,
|
|
9493
|
+
export { BaseExporter, BaseObservabilityEventBus, BaseObservabilityInstance, BaseSpan, CardinalityFilter, CloudExporter, ConsoleExporter, DEFAULT_DEEP_CLEAN_OPTIONS, DEFAULT_LIMITS, DefaultExporter, DefaultObservabilityInstance, DefaultSpan, JsonExporter, LoggerContextImpl, MastraPlatformExporter, MastraStorageExporter, MetricsContextImpl, ModelSpanTracker, NoOpSpan, OBSERVABILITY_CAPABILITIES_HEADER, Observability, ObservabilityBus, QUOTA_PAUSE_CAPABILITY, SamplingStrategyType, SensitiveDataFilter, TestExporter, TraceData, TrackingExporter, buildExportedLog, buildExportedSpan, buildTracingOptions, chainFormatters, createClientObservabilityProxy, decodeResourceLogs, decodeResourceSpans, deepClean, formatBaggage, formatTraceparent, getExternalParentId, isSerializedMap, mergeSerializationOptions, observabilityConfigValueSchema, observabilityFeatures, observabilityInstanceConfigSchema, observabilityRegistryConfigSchema, otlpSeverityToLogLevel, parseBaggage, parseTraceparent, reconstructSerializedMap, routeToHandler, samplingStrategySchema, serializationOptionsSchema, truncateString };
|
|
9303
9494
|
|
|
9304
9495
|
//# sourceMappingURL=index.js.map
|