@mastra/observability 1.21.1-alpha.1 → 1.22.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/exporters/event-buffer.d.ts +5 -0
- package/dist/exporters/event-buffer.d.ts.map +1 -1
- package/dist/exporters/mastra-platform.d.ts.map +1 -1
- package/dist/exporters/mastra-storage.d.ts +14 -1
- package/dist/exporters/mastra-storage.d.ts.map +1 -1
- package/dist/exporters/span-previews.d.ts +4 -0
- package/dist/exporters/span-previews.d.ts.map +1 -0
- package/dist/exporters/test.d.ts.map +1 -1
- package/dist/index.cjs +169 -113
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +168 -111
- package/dist/index.js.map +1 -1
- package/dist/instances/base.d.ts.map +1 -1
- package/dist/metrics/pricing-data.json +1529 -598
- package/dist/model-tracing.d.ts +5 -0
- package/dist/model-tracing.d.ts.map +1 -1
- package/dist/spans/base.d.ts.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { createRequire } from "module";
|
|
|
2
2
|
import { MastraBase } from "@mastra/core/base";
|
|
3
3
|
import { ErrorCategory, ErrorDomain, MastraError } from "@mastra/core/error";
|
|
4
4
|
import { ConsoleLogger, LogLevel, RegisteredLogger } from "@mastra/core/logger";
|
|
5
|
+
import * as coreObservability from "@mastra/core/observability";
|
|
5
6
|
import { DEFAULT_BLOCKED_LABELS, EntityType, InternalSpans, SpanType, TracingEventType, noOpLoggerContext } from "@mastra/core/observability";
|
|
6
7
|
import { fetchWithRetry, getNestedValue, setNestedValue } from "@mastra/core/utils";
|
|
7
8
|
import { z } from "zod/v4";
|
|
@@ -12,7 +13,7 @@ import { TransformStream } from "stream/web";
|
|
|
12
13
|
import { coreFeatures } from "@mastra/core/features";
|
|
13
14
|
import { buildCreateSpanRecord, buildFeedbackRecord, buildLogRecord, buildMetricRecord, buildScoreRecord, buildUpdateSpanRecord } from "@mastra/core/storage";
|
|
14
15
|
import { createHash } from "crypto";
|
|
15
|
-
|
|
16
|
+
// src/bus/route-event.ts
|
|
16
17
|
/**
|
|
17
18
|
* Route a single event to the appropriate method on a handler.
|
|
18
19
|
*
|
|
@@ -79,8 +80,7 @@ function catchAsyncResult(result, handlerName, signal, logger) {
|
|
|
79
80
|
logger.error(`[Observability] ${signal} handler error [handler=${handlerName}]:`, err);
|
|
80
81
|
});
|
|
81
82
|
}
|
|
82
|
-
|
|
83
|
-
//#region src/bus/base.ts
|
|
83
|
+
// src/bus/base.ts
|
|
84
84
|
/**
|
|
85
85
|
* BaseObservabilityEventBus - Generic event bus for observability events.
|
|
86
86
|
*
|
|
@@ -155,8 +155,7 @@ var BaseObservabilityEventBus = class BaseObservabilityEventBus extends MastraBa
|
|
|
155
155
|
this.subscribers.clear();
|
|
156
156
|
}
|
|
157
157
|
};
|
|
158
|
-
|
|
159
|
-
//#region src/spans/serialization.ts
|
|
158
|
+
// src/spans/serialization.ts
|
|
160
159
|
/**
|
|
161
160
|
* Bounded serialization utilities for AI tracing.
|
|
162
161
|
*
|
|
@@ -522,8 +521,7 @@ function deepClean(value, options = DEFAULT_DEEP_CLEAN_OPTIONS) {
|
|
|
522
521
|
}
|
|
523
522
|
return helper(value, 0);
|
|
524
523
|
}
|
|
525
|
-
|
|
526
|
-
//#region src/bus/observability-bus.ts
|
|
524
|
+
// src/bus/observability-bus.ts
|
|
527
525
|
/**
|
|
528
526
|
* Apply deepClean() to non-tracing observability events. Tracing events are
|
|
529
527
|
* already deep-cleaned at span construction time (see spans/base.ts and
|
|
@@ -732,8 +730,7 @@ var ObservabilityBus = class extends BaseObservabilityEventBus {
|
|
|
732
730
|
await super.shutdown();
|
|
733
731
|
}
|
|
734
732
|
};
|
|
735
|
-
|
|
736
|
-
//#region src/config.ts
|
|
733
|
+
// src/config.ts
|
|
737
734
|
/**
|
|
738
735
|
* Sampling strategy types
|
|
739
736
|
*/
|
|
@@ -860,8 +857,7 @@ const observabilityRegistryConfigSchema = z.object({
|
|
|
860
857
|
}
|
|
861
858
|
return true;
|
|
862
859
|
}, { message: "A \"configSelector\" requires at least one config or default observability to be configured." });
|
|
863
|
-
|
|
864
|
-
//#region src/ids.ts
|
|
860
|
+
// src/ids.ts
|
|
865
861
|
/**
|
|
866
862
|
* Signal and span id helpers.
|
|
867
863
|
*
|
|
@@ -929,8 +925,7 @@ function resolveExportedSpanId(span) {
|
|
|
929
925
|
if (!span) return void 0;
|
|
930
926
|
return typeof span.getExportedSpanId === "function" ? span.getExportedSpanId() : span.id;
|
|
931
927
|
}
|
|
932
|
-
|
|
933
|
-
//#region src/context/logger.ts
|
|
928
|
+
// src/context/logger.ts
|
|
934
929
|
/** Numeric priority used to compare log levels against the configured minimum. */
|
|
935
930
|
const LOG_LEVEL_PRIORITY = {
|
|
936
931
|
debug: 0,
|
|
@@ -998,8 +993,7 @@ var LoggerContextImpl = class {
|
|
|
998
993
|
this.config.observabilityBus.emit(event);
|
|
999
994
|
}
|
|
1000
995
|
};
|
|
1001
|
-
|
|
1002
|
-
//#region src/context/metrics.ts
|
|
996
|
+
// src/context/metrics.ts
|
|
1003
997
|
/**
|
|
1004
998
|
* User-facing metric emission API. All metrics are routed through
|
|
1005
999
|
* ObservabilityBus.emit() after validation and cardinality filtering.
|
|
@@ -1074,14 +1068,12 @@ function cloneCostContext(costContext) {
|
|
|
1074
1068
|
costMetadata: costContext.costMetadata ? structuredClone(costContext.costMetadata) : void 0
|
|
1075
1069
|
};
|
|
1076
1070
|
}
|
|
1077
|
-
|
|
1078
|
-
//#region src/model-id.ts
|
|
1071
|
+
// src/model-id.ts
|
|
1079
1072
|
/** Return the first model id that contains non-whitespace characters. */
|
|
1080
1073
|
function resolveModelId(...candidates) {
|
|
1081
1074
|
return candidates.find((candidate) => candidate?.trim());
|
|
1082
1075
|
}
|
|
1083
|
-
|
|
1084
|
-
//#region src/metrics/pricing-model.ts
|
|
1076
|
+
// src/metrics/pricing-model.ts
|
|
1085
1077
|
var PricingTier = class {
|
|
1086
1078
|
index;
|
|
1087
1079
|
when;
|
|
@@ -1139,8 +1131,7 @@ var PricingModel = class {
|
|
|
1139
1131
|
return this.tiers[0] ?? null;
|
|
1140
1132
|
}
|
|
1141
1133
|
};
|
|
1142
|
-
|
|
1143
|
-
//#region src/metrics/models-dev.ts
|
|
1134
|
+
// src/metrics/models-dev.ts
|
|
1144
1135
|
/** Same catalog the model router reads in `@mastra/core` (`gateways/models-dev.ts`). */
|
|
1145
1136
|
const MODELS_DEV_API_URL = "https://models.dev/api.json";
|
|
1146
1137
|
/**
|
|
@@ -1271,8 +1262,7 @@ function sortedEntries(value) {
|
|
|
1271
1262
|
function isRecord(value) {
|
|
1272
1263
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1273
1264
|
}
|
|
1274
|
-
|
|
1275
|
-
//#region src/metrics/pricing-registry.ts
|
|
1265
|
+
// src/metrics/pricing-registry.ts
|
|
1276
1266
|
const DATA_FILE_NAME = "pricing-data.json";
|
|
1277
1267
|
const REFRESH_INTERVAL_MS = 864e5;
|
|
1278
1268
|
const MIN_REFRESH_ATTEMPT_INTERVAL_MS = 36e5;
|
|
@@ -1623,8 +1613,7 @@ function stripDateSuffix(model) {
|
|
|
1623
1613
|
stripped = model.replace(/-\d{2}-20\d{2}$/, "");
|
|
1624
1614
|
return stripped;
|
|
1625
1615
|
}
|
|
1626
|
-
|
|
1627
|
-
//#region src/metrics/types.ts
|
|
1616
|
+
// src/metrics/types.ts
|
|
1628
1617
|
const PricingMeter = {
|
|
1629
1618
|
INPUT_TOKENS: "input_tokens",
|
|
1630
1619
|
INPUT_AUDIO_TOKENS: "input_audio_tokens",
|
|
@@ -1660,8 +1649,7 @@ const TokenMetrics = {
|
|
|
1660
1649
|
OUTPUT_AUDIO: "mastra_model_output_audio_tokens",
|
|
1661
1650
|
OUTPUT_IMAGE: "mastra_model_output_image_tokens"
|
|
1662
1651
|
};
|
|
1663
|
-
|
|
1664
|
-
//#region src/metrics/usage-metrics.ts
|
|
1652
|
+
// src/metrics/usage-metrics.ts
|
|
1665
1653
|
function getTokenMetricSamples(usage) {
|
|
1666
1654
|
const samples = [];
|
|
1667
1655
|
const pushIfDefined = (name, value) => {
|
|
@@ -1695,8 +1683,7 @@ function getTokenMetricSamples(usage) {
|
|
|
1695
1683
|
}
|
|
1696
1684
|
return samples;
|
|
1697
1685
|
}
|
|
1698
|
-
|
|
1699
|
-
//#region src/metrics/estimator.ts
|
|
1686
|
+
// src/metrics/estimator.ts
|
|
1700
1687
|
function estimateCosts(args, pricingRegistry = PricingRegistry.getGlobal()) {
|
|
1701
1688
|
const { provider, model, usage } = args;
|
|
1702
1689
|
const results = /* @__PURE__ */ new Map();
|
|
@@ -1928,8 +1915,7 @@ function estimateCostForMeter(args) {
|
|
|
1928
1915
|
}
|
|
1929
1916
|
};
|
|
1930
1917
|
}
|
|
1931
|
-
|
|
1932
|
-
//#region src/metrics/auto-extract.ts
|
|
1918
|
+
// src/metrics/auto-extract.ts
|
|
1933
1919
|
/**
|
|
1934
1920
|
* Emits metrics derived from live spans.
|
|
1935
1921
|
*/
|
|
@@ -2083,8 +2069,7 @@ function getDurationMetricName(span) {
|
|
|
2083
2069
|
default: return null;
|
|
2084
2070
|
}
|
|
2085
2071
|
}
|
|
2086
|
-
|
|
2087
|
-
//#region src/metrics/cardinality.ts
|
|
2072
|
+
// src/metrics/cardinality.ts
|
|
2088
2073
|
/** Matches standard UUID v4 strings (case-insensitive). */
|
|
2089
2074
|
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
2090
2075
|
var CardinalityFilter = class {
|
|
@@ -2115,8 +2100,7 @@ var CardinalityFilter = class {
|
|
|
2115
2100
|
return filtered;
|
|
2116
2101
|
}
|
|
2117
2102
|
};
|
|
2118
|
-
|
|
2119
|
-
//#region src/usage.ts
|
|
2103
|
+
// src/usage.ts
|
|
2120
2104
|
/**
|
|
2121
2105
|
* For non-BYOK requests, `usage.cost` is the complete OpenRouter charge and
|
|
2122
2106
|
* `usage.costDetails.upstreamInferenceCost` is only its upstream breakdown. For BYOK requests,
|
|
@@ -2301,8 +2285,7 @@ function addUsageStats(a, b) {
|
|
|
2301
2285
|
outputDetails: mergeOutputDetails(a.outputDetails, b.outputDetails)
|
|
2302
2286
|
};
|
|
2303
2287
|
}
|
|
2304
|
-
|
|
2305
|
-
//#region src/model-tracing.ts
|
|
2288
|
+
// src/model-tracing.ts
|
|
2306
2289
|
/**
|
|
2307
2290
|
* Model Span Tracing
|
|
2308
2291
|
*
|
|
@@ -2730,8 +2713,20 @@ var ModelSpanTracker = class {
|
|
|
2730
2713
|
* feature flag, or when called without an active step span. Auto-invoked from
|
|
2731
2714
|
* chunk handlers as a safety net; explicit callers get the most accurate
|
|
2732
2715
|
* start time.
|
|
2716
|
+
*
|
|
2717
|
+
* `payload.modelId` / `payload.provider` name the model the caller is about
|
|
2718
|
+
* to invoke and are recorded on MODEL_STEP, also when a fallback attempt
|
|
2719
|
+
* reuses the step's open inference span. The safety net never records them:
|
|
2720
|
+
* a replayed step-start chunk names the model of the original call.
|
|
2733
2721
|
*/
|
|
2734
2722
|
startInference(payload) {
|
|
2723
|
+
if (payload?.modelId && payload.provider) this.#currentStepSpan?.update({ attributes: {
|
|
2724
|
+
model: payload.modelId,
|
|
2725
|
+
provider: payload.provider
|
|
2726
|
+
} });
|
|
2727
|
+
this.#openInference(payload);
|
|
2728
|
+
}
|
|
2729
|
+
#openInference(payload) {
|
|
2735
2730
|
if (!supportsModelInference()) return;
|
|
2736
2731
|
if (!this.#currentStepSpan || this.#currentInferenceSpan) return;
|
|
2737
2732
|
this.#inferenceCompletionStartTime = void 0;
|
|
@@ -2856,7 +2851,7 @@ var ModelSpanTracker = class {
|
|
|
2856
2851
|
*/
|
|
2857
2852
|
#ensureStepAndInference() {
|
|
2858
2853
|
if (!this.#currentStepSpan) this.startStep();
|
|
2859
|
-
if (!this.#currentInferenceSpan) this
|
|
2854
|
+
if (!this.#currentInferenceSpan) this.#openInference();
|
|
2860
2855
|
}
|
|
2861
2856
|
/**
|
|
2862
2857
|
* Create a new chunk span (for multi-part chunks like text-start/delta/end)
|
|
@@ -3056,7 +3051,7 @@ var ModelSpanTracker = class {
|
|
|
3056
3051
|
this.#inModelResponse = true;
|
|
3057
3052
|
if (this.#currentStepSpan) this.updateStep(chunk.payload);
|
|
3058
3053
|
else this.startStep(chunk.payload);
|
|
3059
|
-
if (!this.#currentInferenceSpan) this
|
|
3054
|
+
if (!this.#currentInferenceSpan) this.#openInference(chunk.payload);
|
|
3060
3055
|
break;
|
|
3061
3056
|
case "step-finish":
|
|
3062
3057
|
this.#inModelResponse = false;
|
|
@@ -3102,8 +3097,7 @@ var ModelSpanTracker = class {
|
|
|
3102
3097
|
} }));
|
|
3103
3098
|
}
|
|
3104
3099
|
};
|
|
3105
|
-
|
|
3106
|
-
//#region src/spans/metadata.ts
|
|
3100
|
+
// src/spans/metadata.ts
|
|
3107
3101
|
/**
|
|
3108
3102
|
* Shared span-metadata helpers.
|
|
3109
3103
|
*
|
|
@@ -3170,8 +3164,7 @@ function mergeMetadata$1(parentMetadata, metadata) {
|
|
|
3170
3164
|
return metadata;
|
|
3171
3165
|
}
|
|
3172
3166
|
}
|
|
3173
|
-
|
|
3174
|
-
//#region src/spans/base.ts
|
|
3167
|
+
// src/spans/base.ts
|
|
3175
3168
|
const LINEAGE_KEYS = [
|
|
3176
3169
|
"parentEntityType",
|
|
3177
3170
|
"parentEntityId",
|
|
@@ -3182,10 +3175,10 @@ const LINEAGE_KEYS = [
|
|
|
3182
3175
|
"rootEntityName",
|
|
3183
3176
|
"rootEntityVersionId"
|
|
3184
3177
|
];
|
|
3185
|
-
/** Copy only the lineage fields that have values, so spans don't carry undefined keys */
|
|
3186
3178
|
function ownEntityVersionId(span) {
|
|
3187
3179
|
return span instanceof BaseSpan ? span.ownEntityVersionId : void 0;
|
|
3188
3180
|
}
|
|
3181
|
+
/** Copy only the lineage fields that have values, so spans don't carry undefined keys */
|
|
3189
3182
|
function definedLineage(source) {
|
|
3190
3183
|
const lineage = {};
|
|
3191
3184
|
for (const key of LINEAGE_KEYS) {
|
|
@@ -3264,6 +3257,19 @@ function getExternalParentId(options) {
|
|
|
3264
3257
|
if (parent.isInternal || parent.isExcluded) return parent.getParentSpanId(false);
|
|
3265
3258
|
return parent.id;
|
|
3266
3259
|
}
|
|
3260
|
+
/**
|
|
3261
|
+
* Vercel AI Gateway reports which provider served a step, and any provider
|
|
3262
|
+
* attempts that failed first, only in `providerMetadata.gateway.routing`.
|
|
3263
|
+
* Read it defensively so a throwing getter never skips the strip below.
|
|
3264
|
+
*/
|
|
3265
|
+
function readGatewayRouting(providerMetadata) {
|
|
3266
|
+
try {
|
|
3267
|
+
const gateway = isPlainRecord(providerMetadata) ? providerMetadata.gateway : void 0;
|
|
3268
|
+
return isPlainRecord(gateway) ? gateway.routing : void 0;
|
|
3269
|
+
} catch {
|
|
3270
|
+
return;
|
|
3271
|
+
}
|
|
3272
|
+
}
|
|
3267
3273
|
var BaseSpan = class BaseSpan {
|
|
3268
3274
|
name;
|
|
3269
3275
|
type;
|
|
@@ -3391,8 +3397,10 @@ var BaseSpan = class BaseSpan {
|
|
|
3391
3397
|
if (this.type !== SpanType.MODEL_STEP) return value;
|
|
3392
3398
|
try {
|
|
3393
3399
|
const prepared = { ...value };
|
|
3400
|
+
const gatewayRouting = readGatewayRouting(prepared.providerMetadata);
|
|
3394
3401
|
delete prepared.providerMetadata;
|
|
3395
3402
|
delete prepared.experimental_providerMetadata;
|
|
3403
|
+
if (gatewayRouting !== void 0) prepared.providerMetadata = { gateway: { routing: gatewayRouting } };
|
|
3396
3404
|
return prepared;
|
|
3397
3405
|
} catch {
|
|
3398
3406
|
return value;
|
|
@@ -3578,7 +3586,7 @@ var BaseSpan = class BaseSpan {
|
|
|
3578
3586
|
entityType: this.entityType,
|
|
3579
3587
|
entityId: this.entityId,
|
|
3580
3588
|
entityName: this.entityName,
|
|
3581
|
-
entityVersionId:
|
|
3589
|
+
entityVersionId: this.ownEntityVersionId,
|
|
3582
3590
|
...parentLineage,
|
|
3583
3591
|
...rootLineage,
|
|
3584
3592
|
userId: getMetadataString("userId"),
|
|
@@ -3621,6 +3629,7 @@ var BaseSpan = class BaseSpan {
|
|
|
3621
3629
|
isEvent: this.isEvent,
|
|
3622
3630
|
isRootSpan: this.isRootSpan,
|
|
3623
3631
|
...this.isInternal ? { isInternal: true } : {},
|
|
3632
|
+
...correlation.entityVersionId ? { entityVersionId: correlation.entityVersionId } : {},
|
|
3624
3633
|
...definedLineage(correlation),
|
|
3625
3634
|
parentSpanId: this.getParentSpanId(includeInternalSpans),
|
|
3626
3635
|
externalParentSpanId: this.getExportedExternalParentSpanId(includeInternalSpans),
|
|
@@ -3665,8 +3674,7 @@ var BaseSpan = class BaseSpan {
|
|
|
3665
3674
|
return fn();
|
|
3666
3675
|
}
|
|
3667
3676
|
};
|
|
3668
|
-
|
|
3669
|
-
//#region src/spans/default.ts
|
|
3677
|
+
// src/spans/default.ts
|
|
3670
3678
|
/** Every AI SDK `APICallError` (v4, v5 and v6) carries this shared marker symbol. */
|
|
3671
3679
|
const API_CALL_ERROR_MARKER = Symbol.for("vercel.ai.error.AI_APICallError");
|
|
3672
3680
|
function isApiCallError(value) {
|
|
@@ -3857,8 +3865,7 @@ function getOrCreateTraceId(options) {
|
|
|
3857
3865
|
}
|
|
3858
3866
|
return generateTraceId();
|
|
3859
3867
|
}
|
|
3860
|
-
|
|
3861
|
-
//#region src/spans/no-op.ts
|
|
3868
|
+
// src/spans/no-op.ts
|
|
3862
3869
|
var NoOpSpan = class extends BaseSpan {
|
|
3863
3870
|
id;
|
|
3864
3871
|
traceId;
|
|
@@ -3877,8 +3884,7 @@ var NoOpSpan = class extends BaseSpan {
|
|
|
3877
3884
|
return true;
|
|
3878
3885
|
}
|
|
3879
3886
|
};
|
|
3880
|
-
|
|
3881
|
-
//#region src/exporters/base.ts
|
|
3887
|
+
// src/exporters/base.ts
|
|
3882
3888
|
/**
|
|
3883
3889
|
* Base Exporter for Observability
|
|
3884
3890
|
*
|
|
@@ -4040,8 +4046,7 @@ var BaseExporter = class {
|
|
|
4040
4046
|
this.logger.info(`${this.name} shutdown complete`);
|
|
4041
4047
|
}
|
|
4042
4048
|
};
|
|
4043
|
-
|
|
4044
|
-
//#region src/exporters/event-buffer.ts
|
|
4049
|
+
// src/exporters/event-buffer.ts
|
|
4045
4050
|
/**
|
|
4046
4051
|
* Buffers observability events (creates and updates) for batch flushing.
|
|
4047
4052
|
* Handles strategy-aware routing of tracing events and tracks created spans
|
|
@@ -4052,6 +4057,8 @@ var EventBuffer = class {
|
|
|
4052
4057
|
#creates = [];
|
|
4053
4058
|
#updates = [];
|
|
4054
4059
|
#allCreatedSpans = /* @__PURE__ */ new Set();
|
|
4060
|
+
/** Spans whose SPAN_STARTED this buffer has seen but whose create isn't confirmed yet */
|
|
4061
|
+
#pendingCreateSpans = /* @__PURE__ */ new Set();
|
|
4055
4062
|
#firstEventTime;
|
|
4056
4063
|
#storageStrategy;
|
|
4057
4064
|
#maxRetries;
|
|
@@ -4102,8 +4109,11 @@ var EventBuffer = class {
|
|
|
4102
4109
|
case TracingEventType.SPAN_STARTED:
|
|
4103
4110
|
switch (this.#storageStrategy) {
|
|
4104
4111
|
case "realtime":
|
|
4105
|
-
case "
|
|
4106
|
-
|
|
4112
|
+
case "batch-with-updates":
|
|
4113
|
+
if (!event.exportedSpan.isEvent) this.#pendingCreateSpans.add(this.exportedSpanKey(event.exportedSpan));
|
|
4114
|
+
this.pushCreate(event);
|
|
4115
|
+
break;
|
|
4116
|
+
case "event-sourced": this.pushCreate(event);
|
|
4107
4117
|
}
|
|
4108
4118
|
break;
|
|
4109
4119
|
case TracingEventType.SPAN_UPDATED:
|
|
@@ -4172,28 +4182,44 @@ var EventBuffer = class {
|
|
|
4172
4182
|
buildSpanKey(span) {
|
|
4173
4183
|
return `${span.traceId}:${span.spanId}`;
|
|
4174
4184
|
}
|
|
4185
|
+
exportedSpanKey(span) {
|
|
4186
|
+
return this.buildSpanKey({
|
|
4187
|
+
traceId: span.traceId,
|
|
4188
|
+
spanId: span.id
|
|
4189
|
+
});
|
|
4190
|
+
}
|
|
4175
4191
|
/** Track successfully created spans so updates can verify span existence before flushing. */
|
|
4176
4192
|
addCreatedSpans(args) {
|
|
4177
4193
|
if (this.#storageStrategy === "event-sourced" || this.#storageStrategy === "insert-only") return;
|
|
4178
|
-
for (const createRecord of args.records) if (!createRecord.isEvent)
|
|
4194
|
+
for (const createRecord of args.records) if (!createRecord.isEvent) {
|
|
4195
|
+
const key = this.buildSpanKey(createRecord);
|
|
4196
|
+
this.#pendingCreateSpans.delete(key);
|
|
4197
|
+
this.#allCreatedSpans.add(key);
|
|
4198
|
+
}
|
|
4199
|
+
}
|
|
4200
|
+
/** Stop waiting on creates that were dropped, so their updates aren't held back for them. */
|
|
4201
|
+
forgetDroppedCreates(events) {
|
|
4202
|
+
for (const event of events) if (event.type === TracingEventType.SPAN_STARTED) this.#pendingCreateSpans.delete(this.exportedSpanKey(event.exportedSpan));
|
|
4179
4203
|
}
|
|
4180
4204
|
/** Check whether a span's create record has already been flushed to storage. */
|
|
4181
4205
|
spanExists(span) {
|
|
4182
|
-
return this.#allCreatedSpans
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4206
|
+
return this.#allCreatedSpans.has(this.exportedSpanKey(span));
|
|
4207
|
+
}
|
|
4208
|
+
/** Check whether this buffer saw the span's SPAN_STARTED but its create hasn't been confirmed yet. */
|
|
4209
|
+
isAwaitingCreate(span) {
|
|
4210
|
+
return this.#pendingCreateSpans.has(this.exportedSpanKey(span));
|
|
4186
4211
|
}
|
|
4187
4212
|
/** Remove completed spans from tracking after their SPAN_ENDED updates are flushed. */
|
|
4188
4213
|
endFinishedSpans(args) {
|
|
4189
4214
|
if (this.#storageStrategy === "event-sourced" || this.#storageStrategy === "insert-only") return;
|
|
4190
4215
|
args.records.forEach((r) => {
|
|
4191
|
-
this
|
|
4216
|
+
const key = this.buildSpanKey(r);
|
|
4217
|
+
this.#allCreatedSpans.delete(key);
|
|
4218
|
+
this.#pendingCreateSpans.delete(key);
|
|
4192
4219
|
});
|
|
4193
4220
|
}
|
|
4194
4221
|
};
|
|
4195
|
-
|
|
4196
|
-
//#region src/exporters/default.ts
|
|
4222
|
+
// src/exporters/default.ts
|
|
4197
4223
|
/**
|
|
4198
4224
|
* Resolves the final tracing storage strategy based on config and observability store hints
|
|
4199
4225
|
*/
|
|
@@ -4631,8 +4657,22 @@ var DefaultExporter = class extends BaseExporter {
|
|
|
4631
4657
|
this.logger.info("DefaultExporter shutdown complete");
|
|
4632
4658
|
}
|
|
4633
4659
|
};
|
|
4634
|
-
|
|
4635
|
-
|
|
4660
|
+
// src/exporters/span-previews.ts
|
|
4661
|
+
const buildSpanPreviews = coreObservability.buildSpanPreviews;
|
|
4662
|
+
/** Older core versions retain their existing storage preview fallback. */
|
|
4663
|
+
function withSpanPreviews(span) {
|
|
4664
|
+
if (!coreFeatures.has("observability-span-previews")) return span;
|
|
4665
|
+
try {
|
|
4666
|
+
const previews = buildSpanPreviews?.(span);
|
|
4667
|
+
return previews ? {
|
|
4668
|
+
...span,
|
|
4669
|
+
...previews
|
|
4670
|
+
} : span;
|
|
4671
|
+
} catch {
|
|
4672
|
+
return span;
|
|
4673
|
+
}
|
|
4674
|
+
}
|
|
4675
|
+
// src/exporters/mastra-storage.ts
|
|
4636
4676
|
/**
|
|
4637
4677
|
* Resolves the final tracing storage strategy based on config and observability store hints
|
|
4638
4678
|
*/
|
|
@@ -4835,6 +4875,7 @@ var MastraStorageExporter = class extends BaseExporter {
|
|
|
4835
4875
|
return { failed: true };
|
|
4836
4876
|
}
|
|
4837
4877
|
const dropped = this.#eventBuffer.reAddCreates(events);
|
|
4878
|
+
this.#eventBuffer.forgetDroppedCreates(dropped);
|
|
4838
4879
|
const retryAttempt = this.retryAttempt(events);
|
|
4839
4880
|
this.logStorageFailure(signal, events, retryAttempt, error);
|
|
4840
4881
|
this.emitDrop(signal, "retry-exhausted", dropped.length, error);
|
|
@@ -4845,7 +4886,15 @@ var MastraStorageExporter = class extends BaseExporter {
|
|
|
4845
4886
|
}
|
|
4846
4887
|
}
|
|
4847
4888
|
/**
|
|
4848
|
-
* Flush span update/end events
|
|
4889
|
+
* Flush span update/end events.
|
|
4890
|
+
*
|
|
4891
|
+
* When the store supports conditional updates, only spans this exporter started
|
|
4892
|
+
* and hasn't confirmed the create for are deferred. Everything else, including
|
|
4893
|
+
* spans another exporter instance started (such as a durable agent ending spans
|
|
4894
|
+
* it rebuilt after a crash), goes straight to storage, and updates that didn't
|
|
4895
|
+
* apply are counted as drops. Without conditional updates, updates for spans this
|
|
4896
|
+
* exporter hasn't created are deferred until their create is flushed.
|
|
4897
|
+
*
|
|
4849
4898
|
* When `isEnd` is true, successfully flushed spans are removed from tracking.
|
|
4850
4899
|
*/
|
|
4851
4900
|
async flushSpanUpdates(events, deferredUpdates, isEnd) {
|
|
@@ -4855,10 +4904,12 @@ var MastraStorageExporter = class extends BaseExporter {
|
|
|
4855
4904
|
this.emitDrop("tracing", "unsupported-storage", events.length);
|
|
4856
4905
|
return { failed: true };
|
|
4857
4906
|
}
|
|
4907
|
+
const storage = this.#observabilityStorage;
|
|
4908
|
+
const batchUpdateUnendedSpans = typeof storage.batchUpdateUnendedSpans === "function" ? storage.batchUpdateUnendedSpans.bind(storage) : void 0;
|
|
4858
4909
|
const partials = [];
|
|
4859
4910
|
for (const event of events) {
|
|
4860
4911
|
const span = event.exportedSpan;
|
|
4861
|
-
if (this.#eventBuffer.spanExists(span)) partials.push({
|
|
4912
|
+
if (batchUpdateUnendedSpans ? !this.#eventBuffer.isAwaitingCreate(span) : this.#eventBuffer.spanExists(span)) partials.push({
|
|
4862
4913
|
traceId: span.traceId,
|
|
4863
4914
|
spanId: span.id,
|
|
4864
4915
|
updates: buildUpdateSpanRecord(span)
|
|
@@ -4867,7 +4918,10 @@ var MastraStorageExporter = class extends BaseExporter {
|
|
|
4867
4918
|
}
|
|
4868
4919
|
if (partials.length === 0) return FLUSH_SUCCEEDED;
|
|
4869
4920
|
try {
|
|
4870
|
-
|
|
4921
|
+
if (batchUpdateUnendedSpans) {
|
|
4922
|
+
const { updated } = await batchUpdateUnendedSpans({ records: partials });
|
|
4923
|
+
this.emitNotApplied(partials, updated);
|
|
4924
|
+
} else await storage.batchUpdateSpans({ records: partials });
|
|
4871
4925
|
if (isEnd) this.#eventBuffer.endFinishedSpans({ records: partials });
|
|
4872
4926
|
return FLUSH_SUCCEEDED;
|
|
4873
4927
|
} catch (error) {
|
|
@@ -4891,6 +4945,27 @@ var MastraStorageExporter = class extends BaseExporter {
|
|
|
4891
4945
|
}
|
|
4892
4946
|
}
|
|
4893
4947
|
/**
|
|
4948
|
+
* Reports conditional span updates that storage didn't apply: the span wasn't
|
|
4949
|
+
* stored, or it had already ended. Ended spans are immutable, so these are dropped.
|
|
4950
|
+
*/
|
|
4951
|
+
emitNotApplied(partials, updated) {
|
|
4952
|
+
const appliedCounts = /* @__PURE__ */ new Map();
|
|
4953
|
+
for (const span of updated) {
|
|
4954
|
+
const key = `${span.traceId}:${span.spanId}`;
|
|
4955
|
+
appliedCounts.set(key, (appliedCounts.get(key) ?? 0) + 1);
|
|
4956
|
+
}
|
|
4957
|
+
let notApplied = 0;
|
|
4958
|
+
for (const partial of partials) {
|
|
4959
|
+
const key = `${partial.traceId}:${partial.spanId}`;
|
|
4960
|
+
const remaining = appliedCounts.get(key) ?? 0;
|
|
4961
|
+
if (remaining > 0) appliedCounts.set(key, remaining - 1);
|
|
4962
|
+
else notApplied++;
|
|
4963
|
+
}
|
|
4964
|
+
if (notApplied === 0) return;
|
|
4965
|
+
this.logger.debug("Span updates not applied: span not stored or already ended", { count: notApplied });
|
|
4966
|
+
this.emitDrop("tracing", "span-not-updatable", notApplied);
|
|
4967
|
+
}
|
|
4968
|
+
/**
|
|
4894
4969
|
* Runs flushBuffer() and tracks its promise so flush() can wait for writes
|
|
4895
4970
|
* that a timer or size trigger started on their own.
|
|
4896
4971
|
*/
|
|
@@ -5000,7 +5075,10 @@ var MastraStorageExporter = class extends BaseExporter {
|
|
|
5000
5075
|
this.logger.debug("Cannot store traces. Observability storage is not initialized");
|
|
5001
5076
|
return;
|
|
5002
5077
|
}
|
|
5003
|
-
this.#eventBuffer.addEvent(
|
|
5078
|
+
this.#eventBuffer.addEvent({
|
|
5079
|
+
...event,
|
|
5080
|
+
exportedSpan: withSpanPreviews(event.exportedSpan)
|
|
5081
|
+
});
|
|
5004
5082
|
await this.handleBatchedFlush();
|
|
5005
5083
|
}
|
|
5006
5084
|
/**
|
|
@@ -5069,8 +5147,7 @@ var MastraStorageExporter = class extends BaseExporter {
|
|
|
5069
5147
|
this.logger.info("MastraStorageExporter shutdown complete");
|
|
5070
5148
|
}
|
|
5071
5149
|
};
|
|
5072
|
-
|
|
5073
|
-
//#region src/instances/platform-policy.ts
|
|
5150
|
+
// src/instances/platform-policy.ts
|
|
5074
5151
|
const MASTRA_BUILT_IN_STORAGE_EXPORTER_NAMES = /* @__PURE__ */ new Set(["mastra-storage-exporter", "mastra-default-observability-exporter"]);
|
|
5075
5152
|
function isMastraPlatformDeployment() {
|
|
5076
5153
|
return Boolean(process.env.MASTRA_DEPLOYMENT_ID);
|
|
@@ -5078,8 +5155,7 @@ function isMastraPlatformDeployment() {
|
|
|
5078
5155
|
function isMastraBuiltInStorageExporter(exporter) {
|
|
5079
5156
|
return exporter instanceof MastraStorageExporter || exporter instanceof DefaultExporter || MASTRA_BUILT_IN_STORAGE_EXPORTER_NAMES.has(exporter.name);
|
|
5080
5157
|
}
|
|
5081
|
-
|
|
5082
|
-
//#region src/instances/base.ts
|
|
5158
|
+
// src/instances/base.ts
|
|
5083
5159
|
/**
|
|
5084
5160
|
* BaseObservability - Abstract base class for Observability implementations
|
|
5085
5161
|
*/
|
|
@@ -5792,13 +5868,11 @@ var BaseObservabilityInstance = class extends MastraBase {
|
|
|
5792
5868
|
this.logger.info(`[Observability] Shutdown completed [name=${this.name}]`);
|
|
5793
5869
|
}
|
|
5794
5870
|
};
|
|
5795
|
-
|
|
5796
|
-
//#region src/client/id.ts
|
|
5871
|
+
// src/client/id.ts
|
|
5797
5872
|
function generateClientSignalId() {
|
|
5798
5873
|
return globalThis.crypto.randomUUID();
|
|
5799
5874
|
}
|
|
5800
|
-
|
|
5801
|
-
//#region src/client/otlp.ts
|
|
5875
|
+
// src/client/otlp.ts
|
|
5802
5876
|
/**
|
|
5803
5877
|
* Hand-rolled OTLP/JSON decoder for the subset we need to ingest from
|
|
5804
5878
|
* client-side tool execution.
|
|
@@ -5986,8 +6060,7 @@ function buildExportedLog(decoded) {
|
|
|
5986
6060
|
data: decoded.attributes
|
|
5987
6061
|
};
|
|
5988
6062
|
}
|
|
5989
|
-
|
|
5990
|
-
//#region src/client/w3c.ts
|
|
6063
|
+
// src/client/w3c.ts
|
|
5991
6064
|
/**
|
|
5992
6065
|
* Hand-rolled W3C Trace Context and Baggage propagation.
|
|
5993
6066
|
*
|
|
@@ -6058,8 +6131,7 @@ function formatBaggage(entries) {
|
|
|
6058
6131
|
}
|
|
6059
6132
|
return parts.join(",");
|
|
6060
6133
|
}
|
|
6061
|
-
|
|
6062
|
-
//#region src/client/proxy.ts
|
|
6134
|
+
// src/client/proxy.ts
|
|
6063
6135
|
const DEFAULT_LIMITS = {
|
|
6064
6136
|
maxSpans: 10,
|
|
6065
6137
|
maxLogs: 10,
|
|
@@ -6197,8 +6269,7 @@ function validateParentLinks(spans, rootParent) {
|
|
|
6197
6269
|
function createClientObservabilityProxy(options) {
|
|
6198
6270
|
return new ClientObservabilityProxyImpl(options);
|
|
6199
6271
|
}
|
|
6200
|
-
|
|
6201
|
-
//#region src/exporters/tracking.ts
|
|
6272
|
+
// src/exporters/tracking.ts
|
|
6202
6273
|
/**
|
|
6203
6274
|
* TrackingExporter base class for vendor-specific observability exporters.
|
|
6204
6275
|
*
|
|
@@ -7279,8 +7350,7 @@ var TrackingExporter = class extends BaseExporter {
|
|
|
7279
7350
|
await super.shutdown();
|
|
7280
7351
|
}
|
|
7281
7352
|
};
|
|
7282
|
-
|
|
7283
|
-
//#region src/exporters/span-formatters.ts
|
|
7353
|
+
// src/exporters/span-formatters.ts
|
|
7284
7354
|
/**
|
|
7285
7355
|
* Chains multiple span formatters into a single formatter.
|
|
7286
7356
|
*
|
|
@@ -7317,8 +7387,7 @@ function chainFormatters(formatters) {
|
|
|
7317
7387
|
return currentSpan;
|
|
7318
7388
|
};
|
|
7319
7389
|
}
|
|
7320
|
-
|
|
7321
|
-
//#region src/exporters/auth-failure-cooldown.ts
|
|
7390
|
+
// src/exporters/auth-failure-cooldown.ts
|
|
7322
7391
|
const AUTH_FAILURE_STATUSES = /* @__PURE__ */ new Set([401, 403]);
|
|
7323
7392
|
const AUTH_COOLDOWN_BASE_MS = 6e4;
|
|
7324
7393
|
const AUTH_COOLDOWN_MAX_MS = 9e5;
|
|
@@ -7399,8 +7468,7 @@ var AuthFailureCooldown = class {
|
|
|
7399
7468
|
});
|
|
7400
7469
|
}
|
|
7401
7470
|
};
|
|
7402
|
-
|
|
7403
|
-
//#region src/exporters/cloud.ts
|
|
7471
|
+
// src/exporters/cloud.ts
|
|
7404
7472
|
const SIGNAL_PUBLISH_SUFFIXES$1 = {
|
|
7405
7473
|
traces: "/spans/publish",
|
|
7406
7474
|
logs: "/logs/publish",
|
|
@@ -7820,8 +7888,7 @@ var CloudExporter = class extends BaseExporter {
|
|
|
7820
7888
|
this.logger.info("CloudExporter shutdown complete");
|
|
7821
7889
|
}
|
|
7822
7890
|
};
|
|
7823
|
-
|
|
7824
|
-
//#region src/exporters/console.ts
|
|
7891
|
+
// src/exporters/console.ts
|
|
7825
7892
|
var ConsoleExporter = class extends BaseExporter {
|
|
7826
7893
|
name = "tracing-console-exporter";
|
|
7827
7894
|
constructor(config = {}) {
|
|
@@ -7884,8 +7951,7 @@ var ConsoleExporter = class extends BaseExporter {
|
|
|
7884
7951
|
this.logger.info("ConsoleExporter shutdown");
|
|
7885
7952
|
}
|
|
7886
7953
|
};
|
|
7887
|
-
|
|
7888
|
-
//#region src/exporters/mastra-platform.ts
|
|
7954
|
+
// src/exporters/mastra-platform.ts
|
|
7889
7955
|
const SIGNAL_PUBLISH_SUFFIXES = {
|
|
7890
7956
|
traces: "/spans/publish",
|
|
7891
7957
|
logs: "/logs/publish",
|
|
@@ -8116,7 +8182,7 @@ var MastraPlatformExporter = class extends BaseExporter {
|
|
|
8116
8182
|
}
|
|
8117
8183
|
formatSpan(span) {
|
|
8118
8184
|
return {
|
|
8119
|
-
...span,
|
|
8185
|
+
...withSpanPreviews(span),
|
|
8120
8186
|
spanId: span.id,
|
|
8121
8187
|
spanType: span.type,
|
|
8122
8188
|
startedAt: span.startTime,
|
|
@@ -8416,8 +8482,7 @@ var MastraPlatformExporter = class extends BaseExporter {
|
|
|
8416
8482
|
this.logger.info("MastraPlatformExporter shutdown complete");
|
|
8417
8483
|
}
|
|
8418
8484
|
};
|
|
8419
|
-
|
|
8420
|
-
//#region src/exporters/test.ts
|
|
8485
|
+
// src/exporters/test.ts
|
|
8421
8486
|
/**
|
|
8422
8487
|
* Test Exporter for Observability
|
|
8423
8488
|
*
|
|
@@ -9463,8 +9528,7 @@ var TestExporter = class extends BaseExporter {
|
|
|
9463
9528
|
* @deprecated Use `TestExporter` instead. This alias will be removed in a future version.
|
|
9464
9529
|
*/
|
|
9465
9530
|
const JsonExporter = TestExporter;
|
|
9466
|
-
|
|
9467
|
-
//#region src/instances/default.ts
|
|
9531
|
+
// src/instances/default.ts
|
|
9468
9532
|
var DefaultObservabilityInstance = class extends BaseObservabilityInstance {
|
|
9469
9533
|
constructor(config) {
|
|
9470
9534
|
super(config);
|
|
@@ -9473,8 +9537,7 @@ var DefaultObservabilityInstance = class extends BaseObservabilityInstance {
|
|
|
9473
9537
|
return new DefaultSpan(options, this);
|
|
9474
9538
|
}
|
|
9475
9539
|
};
|
|
9476
|
-
|
|
9477
|
-
//#region src/recorded.ts
|
|
9540
|
+
// src/recorded.ts
|
|
9478
9541
|
function nullToUndefined(value) {
|
|
9479
9542
|
return value ?? void 0;
|
|
9480
9543
|
}
|
|
@@ -9778,8 +9841,7 @@ function hydrateRecordedTrace(args) {
|
|
|
9778
9841
|
debugRecordedAnnotationUnavailable
|
|
9779
9842
|
});
|
|
9780
9843
|
}
|
|
9781
|
-
|
|
9782
|
-
//#region src/registry.ts
|
|
9844
|
+
// src/registry.ts
|
|
9783
9845
|
/**
|
|
9784
9846
|
* Registry for Observability instances.
|
|
9785
9847
|
*/
|
|
@@ -9868,8 +9930,7 @@ var ObservabilityRegistry = class {
|
|
|
9868
9930
|
return new Map(this.#instances);
|
|
9869
9931
|
}
|
|
9870
9932
|
};
|
|
9871
|
-
|
|
9872
|
-
//#region src/span_processors/sensitive-data-filter.ts
|
|
9933
|
+
// src/span_processors/sensitive-data-filter.ts
|
|
9873
9934
|
/**
|
|
9874
9935
|
* Maximum number of traces to keep indexed-redaction state for.
|
|
9875
9936
|
* Spans never signal trace completion, so state is evicted least-recently-used.
|
|
@@ -10079,8 +10140,7 @@ var SensitiveDataFilter = class {
|
|
|
10079
10140
|
this.traceStates.clear();
|
|
10080
10141
|
}
|
|
10081
10142
|
};
|
|
10082
|
-
|
|
10083
|
-
//#region src/default.ts
|
|
10143
|
+
// src/default.ts
|
|
10084
10144
|
/**
|
|
10085
10145
|
* Type guard to check if an object is a BaseObservability instance
|
|
10086
10146
|
*/
|
|
@@ -10415,8 +10475,7 @@ var Observability = class extends MastraBase {
|
|
|
10415
10475
|
if (handlerResults.length > 0) await Promise.allSettled(handlerResults);
|
|
10416
10476
|
}
|
|
10417
10477
|
};
|
|
10418
|
-
|
|
10419
|
-
//#region src/features.ts
|
|
10478
|
+
// src/features.ts
|
|
10420
10479
|
/**
|
|
10421
10480
|
* Feature flags for @mastra/observability
|
|
10422
10481
|
*
|
|
@@ -10455,8 +10514,7 @@ var Observability = class extends MastraBase {
|
|
|
10455
10514
|
* ```
|
|
10456
10515
|
*/
|
|
10457
10516
|
const observabilityFeatures = /* @__PURE__ */ new Set(["model-inference-span", "internal-usage-rollup"]);
|
|
10458
|
-
|
|
10459
|
-
//#region src/tracing-options.ts
|
|
10517
|
+
// src/tracing-options.ts
|
|
10460
10518
|
/**
|
|
10461
10519
|
* Builds TracingOptions by composing one or more updater functions.
|
|
10462
10520
|
*
|
|
@@ -10477,7 +10535,6 @@ const observabilityFeatures = /* @__PURE__ */ new Set(["model-inference-span", "
|
|
|
10477
10535
|
function buildTracingOptions(...updaters) {
|
|
10478
10536
|
return updaters.reduce((opts, updater) => updater(opts), {});
|
|
10479
10537
|
}
|
|
10480
|
-
//#endregion
|
|
10481
10538
|
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 };
|
|
10482
10539
|
|
|
10483
10540
|
//# sourceMappingURL=index.js.map
|