@mastra/observability 1.7.3 → 1.8.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 +42 -0
- package/dist/bus/observability-bus.d.ts +6 -2
- package/dist/bus/observability-bus.d.ts.map +1 -1
- package/dist/exporters/cloud.d.ts +23 -2
- package/dist/exporters/cloud.d.ts.map +1 -1
- package/dist/index.cjs +757 -345
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +756 -346
- package/dist/index.js.map +1 -1
- package/dist/instances/base.d.ts.map +1 -1
- package/dist/spans/serialization.d.ts +8 -0
- package/dist/spans/serialization.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -15026,18 +15026,144 @@ function chainFormatters(formatters) {
|
|
|
15026
15026
|
return currentSpan;
|
|
15027
15027
|
};
|
|
15028
15028
|
}
|
|
15029
|
+
var SIGNAL_PUBLISH_SUFFIXES = {
|
|
15030
|
+
traces: "/spans/publish",
|
|
15031
|
+
logs: "/logs/publish",
|
|
15032
|
+
metrics: "/metrics/publish",
|
|
15033
|
+
scores: "/scores/publish",
|
|
15034
|
+
feedback: "/feedback/publish"
|
|
15035
|
+
};
|
|
15036
|
+
var SIGNAL_PUBLISH_PATHS = {
|
|
15037
|
+
traces: "/ai/spans/publish",
|
|
15038
|
+
logs: "/ai/logs/publish",
|
|
15039
|
+
metrics: "/ai/metrics/publish",
|
|
15040
|
+
scores: "/ai/scores/publish",
|
|
15041
|
+
feedback: "/ai/feedback/publish"
|
|
15042
|
+
};
|
|
15043
|
+
var SIGNAL_PAYLOAD_KEYS = {
|
|
15044
|
+
traces: "spans",
|
|
15045
|
+
logs: "logs",
|
|
15046
|
+
metrics: "metrics",
|
|
15047
|
+
scores: "scores",
|
|
15048
|
+
feedback: "feedback"
|
|
15049
|
+
};
|
|
15050
|
+
var DEFAULT_CLOUD_ENDPOINT = "https://api.mastra.ai";
|
|
15051
|
+
function trimTrailingSlashes(value) {
|
|
15052
|
+
let end = value.length;
|
|
15053
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47) {
|
|
15054
|
+
end--;
|
|
15055
|
+
}
|
|
15056
|
+
return end === value.length ? value : value.slice(0, end);
|
|
15057
|
+
}
|
|
15058
|
+
function createInvalidEndpointError(endpoint, text, cause) {
|
|
15059
|
+
return new MastraError(
|
|
15060
|
+
{
|
|
15061
|
+
id: `CLOUD_EXPORTER_INVALID_ENDPOINT`,
|
|
15062
|
+
text,
|
|
15063
|
+
domain: ErrorDomain.MASTRA_OBSERVABILITY,
|
|
15064
|
+
category: ErrorCategory.USER,
|
|
15065
|
+
details: {
|
|
15066
|
+
endpoint
|
|
15067
|
+
}
|
|
15068
|
+
},
|
|
15069
|
+
cause
|
|
15070
|
+
);
|
|
15071
|
+
}
|
|
15072
|
+
function resolveBaseEndpoint(baseEndpoint) {
|
|
15073
|
+
const normalizedEndpoint = trimTrailingSlashes(baseEndpoint);
|
|
15074
|
+
const invalidText = 'CloudExporter endpoint must be a base origin like "https://collector.example.com" with no path, search, or hash.';
|
|
15075
|
+
try {
|
|
15076
|
+
const parsedEndpoint = new URL(normalizedEndpoint);
|
|
15077
|
+
if (parsedEndpoint.pathname !== "/" || parsedEndpoint.search || parsedEndpoint.hash) {
|
|
15078
|
+
throw createInvalidEndpointError(baseEndpoint, invalidText);
|
|
15079
|
+
}
|
|
15080
|
+
return trimTrailingSlashes(parsedEndpoint.origin);
|
|
15081
|
+
} catch (error48) {
|
|
15082
|
+
if (error48 instanceof MastraError) {
|
|
15083
|
+
throw error48;
|
|
15084
|
+
}
|
|
15085
|
+
throw createInvalidEndpointError(baseEndpoint, invalidText, error48);
|
|
15086
|
+
}
|
|
15087
|
+
}
|
|
15088
|
+
function buildSignalEndpoint(baseEndpoint, signal) {
|
|
15089
|
+
return `${baseEndpoint}${SIGNAL_PUBLISH_PATHS[signal]}`;
|
|
15090
|
+
}
|
|
15091
|
+
function resolveExplicitSignalEndpoint(signal, endpoint) {
|
|
15092
|
+
const normalizedEndpoint = trimTrailingSlashes(endpoint);
|
|
15093
|
+
const invalidText = `CloudExporter ${signal}Endpoint must be a base origin like "https://collector.example.com" or a full ${signal} publish URL ending in "${SIGNAL_PUBLISH_SUFFIXES[signal]}".`;
|
|
15094
|
+
try {
|
|
15095
|
+
const parsedEndpoint = new URL(normalizedEndpoint);
|
|
15096
|
+
if (parsedEndpoint.search || parsedEndpoint.hash) {
|
|
15097
|
+
throw createInvalidEndpointError(endpoint, invalidText);
|
|
15098
|
+
}
|
|
15099
|
+
const normalizedOrigin = trimTrailingSlashes(parsedEndpoint.origin);
|
|
15100
|
+
const normalizedPathname = trimTrailingSlashes(parsedEndpoint.pathname);
|
|
15101
|
+
if (!normalizedPathname || normalizedPathname === "/") {
|
|
15102
|
+
return buildSignalEndpoint(normalizedOrigin, signal);
|
|
15103
|
+
}
|
|
15104
|
+
if (normalizedPathname.endsWith(SIGNAL_PUBLISH_SUFFIXES[signal])) {
|
|
15105
|
+
return `${normalizedOrigin}${normalizedPathname}`;
|
|
15106
|
+
}
|
|
15107
|
+
throw createInvalidEndpointError(endpoint, invalidText);
|
|
15108
|
+
} catch (error48) {
|
|
15109
|
+
if (error48 instanceof MastraError) {
|
|
15110
|
+
throw error48;
|
|
15111
|
+
}
|
|
15112
|
+
throw createInvalidEndpointError(endpoint, invalidText, error48);
|
|
15113
|
+
}
|
|
15114
|
+
}
|
|
15115
|
+
function deriveSignalEndpointFromTracesEndpoint(signal, tracesEndpoint) {
|
|
15116
|
+
if (signal === "traces") {
|
|
15117
|
+
return tracesEndpoint;
|
|
15118
|
+
}
|
|
15119
|
+
const normalizedTracesEndpoint = trimTrailingSlashes(tracesEndpoint);
|
|
15120
|
+
const invalidText = 'CloudExporter tracesEndpoint must be a base origin like "https://collector.example.com" or a full traces publish URL ending in "/spans/publish".';
|
|
15121
|
+
try {
|
|
15122
|
+
const parsedEndpoint = new URL(normalizedTracesEndpoint);
|
|
15123
|
+
const normalizedOrigin = trimTrailingSlashes(parsedEndpoint.origin);
|
|
15124
|
+
const normalizedPathname = trimTrailingSlashes(parsedEndpoint.pathname);
|
|
15125
|
+
if (!normalizedPathname.endsWith(SIGNAL_PUBLISH_SUFFIXES.traces)) {
|
|
15126
|
+
throw createInvalidEndpointError(tracesEndpoint, invalidText);
|
|
15127
|
+
}
|
|
15128
|
+
const basePath = normalizedPathname.slice(0, -SIGNAL_PUBLISH_SUFFIXES.traces.length);
|
|
15129
|
+
return `${normalizedOrigin}${basePath}${SIGNAL_PUBLISH_SUFFIXES[signal]}`;
|
|
15130
|
+
} catch (error48) {
|
|
15131
|
+
if (error48 instanceof MastraError) {
|
|
15132
|
+
throw error48;
|
|
15133
|
+
}
|
|
15134
|
+
throw createInvalidEndpointError(tracesEndpoint, invalidText, error48);
|
|
15135
|
+
}
|
|
15136
|
+
}
|
|
15029
15137
|
var CloudExporter = class extends BaseExporter {
|
|
15030
15138
|
name = "mastra-cloud-observability-exporter";
|
|
15031
15139
|
cloudConfig;
|
|
15032
15140
|
buffer;
|
|
15033
15141
|
flushTimer = null;
|
|
15142
|
+
inFlightFlushes = /* @__PURE__ */ new Set();
|
|
15034
15143
|
constructor(config2 = {}) {
|
|
15035
15144
|
super(config2);
|
|
15036
15145
|
const accessToken = config2.accessToken ?? process.env.MASTRA_CLOUD_ACCESS_TOKEN;
|
|
15037
15146
|
if (!accessToken) {
|
|
15038
15147
|
this.setDisabled("MASTRA_CLOUD_ACCESS_TOKEN environment variable not set.");
|
|
15039
15148
|
}
|
|
15040
|
-
const
|
|
15149
|
+
const tracesEndpointOverride = config2.tracesEndpoint ?? process.env.MASTRA_CLOUD_TRACES_ENDPOINT;
|
|
15150
|
+
let baseEndpoint;
|
|
15151
|
+
let tracesEndpoint;
|
|
15152
|
+
if (tracesEndpointOverride) {
|
|
15153
|
+
tracesEndpoint = resolveExplicitSignalEndpoint("traces", tracesEndpointOverride);
|
|
15154
|
+
} else {
|
|
15155
|
+
baseEndpoint = resolveBaseEndpoint(config2.endpoint ?? DEFAULT_CLOUD_ENDPOINT);
|
|
15156
|
+
tracesEndpoint = buildSignalEndpoint(baseEndpoint, "traces");
|
|
15157
|
+
}
|
|
15158
|
+
const resolveConfiguredSignalEndpoint = (signal, explicitEndpoint) => {
|
|
15159
|
+
if (explicitEndpoint) {
|
|
15160
|
+
return resolveExplicitSignalEndpoint(signal, explicitEndpoint);
|
|
15161
|
+
}
|
|
15162
|
+
if (tracesEndpointOverride) {
|
|
15163
|
+
return deriveSignalEndpointFromTracesEndpoint(signal, tracesEndpoint);
|
|
15164
|
+
}
|
|
15165
|
+
return buildSignalEndpoint(baseEndpoint, signal);
|
|
15166
|
+
};
|
|
15041
15167
|
this.cloudConfig = {
|
|
15042
15168
|
logger: this.logger,
|
|
15043
15169
|
logLevel: config2.logLevel ?? LogLevel.INFO,
|
|
@@ -15045,10 +15171,18 @@ var CloudExporter = class extends BaseExporter {
|
|
|
15045
15171
|
maxBatchWaitMs: config2.maxBatchWaitMs ?? 5e3,
|
|
15046
15172
|
maxRetries: config2.maxRetries ?? 3,
|
|
15047
15173
|
accessToken: accessToken || "",
|
|
15048
|
-
|
|
15174
|
+
tracesEndpoint,
|
|
15175
|
+
logsEndpoint: resolveConfiguredSignalEndpoint("logs", config2.logsEndpoint),
|
|
15176
|
+
metricsEndpoint: resolveConfiguredSignalEndpoint("metrics", config2.metricsEndpoint),
|
|
15177
|
+
scoresEndpoint: resolveConfiguredSignalEndpoint("scores", config2.scoresEndpoint),
|
|
15178
|
+
feedbackEndpoint: resolveConfiguredSignalEndpoint("feedback", config2.feedbackEndpoint)
|
|
15049
15179
|
};
|
|
15050
15180
|
this.buffer = {
|
|
15051
15181
|
spans: [],
|
|
15182
|
+
logs: [],
|
|
15183
|
+
metrics: [],
|
|
15184
|
+
scores: [],
|
|
15185
|
+
feedback: [],
|
|
15052
15186
|
totalSize: 0
|
|
15053
15187
|
};
|
|
15054
15188
|
}
|
|
@@ -15057,45 +15191,111 @@ var CloudExporter = class extends BaseExporter {
|
|
|
15057
15191
|
return;
|
|
15058
15192
|
}
|
|
15059
15193
|
this.addToBuffer(event);
|
|
15060
|
-
|
|
15061
|
-
|
|
15062
|
-
|
|
15063
|
-
|
|
15064
|
-
|
|
15065
|
-
});
|
|
15066
|
-
} else if (this.buffer.totalSize === 1) {
|
|
15067
|
-
this.scheduleFlush();
|
|
15194
|
+
await this.handleBufferedEvent();
|
|
15195
|
+
}
|
|
15196
|
+
async onLogEvent(event) {
|
|
15197
|
+
if (this.isDisabled) {
|
|
15198
|
+
return;
|
|
15068
15199
|
}
|
|
15200
|
+
this.addLogToBuffer(event);
|
|
15201
|
+
await this.handleBufferedEvent();
|
|
15069
15202
|
}
|
|
15070
|
-
|
|
15071
|
-
if (this.
|
|
15072
|
-
|
|
15203
|
+
async onMetricEvent(event) {
|
|
15204
|
+
if (this.isDisabled) {
|
|
15205
|
+
return;
|
|
15206
|
+
}
|
|
15207
|
+
this.addMetricToBuffer(event);
|
|
15208
|
+
await this.handleBufferedEvent();
|
|
15209
|
+
}
|
|
15210
|
+
async onScoreEvent(event) {
|
|
15211
|
+
if (this.isDisabled) {
|
|
15212
|
+
return;
|
|
15213
|
+
}
|
|
15214
|
+
this.addScoreToBuffer(event);
|
|
15215
|
+
await this.handleBufferedEvent();
|
|
15216
|
+
}
|
|
15217
|
+
async onFeedbackEvent(event) {
|
|
15218
|
+
if (this.isDisabled) {
|
|
15219
|
+
return;
|
|
15073
15220
|
}
|
|
15221
|
+
this.addFeedbackToBuffer(event);
|
|
15222
|
+
await this.handleBufferedEvent();
|
|
15223
|
+
}
|
|
15224
|
+
addToBuffer(event) {
|
|
15225
|
+
this.markBufferStart();
|
|
15074
15226
|
const spanRecord = this.formatSpan(event.exportedSpan);
|
|
15075
15227
|
this.buffer.spans.push(spanRecord);
|
|
15076
15228
|
this.buffer.totalSize++;
|
|
15077
15229
|
}
|
|
15230
|
+
addLogToBuffer(event) {
|
|
15231
|
+
this.markBufferStart();
|
|
15232
|
+
this.buffer.logs.push(this.formatLog(event.log));
|
|
15233
|
+
this.buffer.totalSize++;
|
|
15234
|
+
}
|
|
15235
|
+
addMetricToBuffer(event) {
|
|
15236
|
+
this.markBufferStart();
|
|
15237
|
+
this.buffer.metrics.push(this.formatMetric(event.metric));
|
|
15238
|
+
this.buffer.totalSize++;
|
|
15239
|
+
}
|
|
15240
|
+
addScoreToBuffer(event) {
|
|
15241
|
+
this.markBufferStart();
|
|
15242
|
+
this.buffer.scores.push(this.formatScore(event.score));
|
|
15243
|
+
this.buffer.totalSize++;
|
|
15244
|
+
}
|
|
15245
|
+
addFeedbackToBuffer(event) {
|
|
15246
|
+
this.markBufferStart();
|
|
15247
|
+
this.buffer.feedback.push(this.formatFeedback(event.feedback));
|
|
15248
|
+
this.buffer.totalSize++;
|
|
15249
|
+
}
|
|
15250
|
+
markBufferStart() {
|
|
15251
|
+
if (this.buffer.totalSize === 0) {
|
|
15252
|
+
this.buffer.firstEventTime = /* @__PURE__ */ new Date();
|
|
15253
|
+
}
|
|
15254
|
+
}
|
|
15078
15255
|
formatSpan(span) {
|
|
15079
15256
|
const spanRecord = {
|
|
15080
|
-
|
|
15257
|
+
...span,
|
|
15081
15258
|
spanId: span.id,
|
|
15082
|
-
parentSpanId: span.parentSpanId ?? null,
|
|
15083
|
-
name: span.name,
|
|
15084
15259
|
spanType: span.type,
|
|
15085
|
-
attributes: span.attributes ?? null,
|
|
15086
|
-
metadata: span.metadata ?? null,
|
|
15087
|
-
requestContext: span.requestContext ?? null,
|
|
15088
15260
|
startedAt: span.startTime,
|
|
15089
15261
|
endedAt: span.endTime ?? null,
|
|
15090
|
-
|
|
15091
|
-
output: span.output ?? null,
|
|
15092
|
-
error: span.errorInfo,
|
|
15093
|
-
isEvent: span.isEvent,
|
|
15262
|
+
error: span.errorInfo ?? null,
|
|
15094
15263
|
createdAt: /* @__PURE__ */ new Date(),
|
|
15095
15264
|
updatedAt: null
|
|
15096
15265
|
};
|
|
15097
15266
|
return spanRecord;
|
|
15098
15267
|
}
|
|
15268
|
+
formatLog(log) {
|
|
15269
|
+
return {
|
|
15270
|
+
...log
|
|
15271
|
+
};
|
|
15272
|
+
}
|
|
15273
|
+
formatMetric(metric) {
|
|
15274
|
+
return {
|
|
15275
|
+
...metric
|
|
15276
|
+
};
|
|
15277
|
+
}
|
|
15278
|
+
formatScore(score) {
|
|
15279
|
+
return {
|
|
15280
|
+
...score
|
|
15281
|
+
};
|
|
15282
|
+
}
|
|
15283
|
+
formatFeedback(feedback) {
|
|
15284
|
+
return {
|
|
15285
|
+
...feedback
|
|
15286
|
+
};
|
|
15287
|
+
}
|
|
15288
|
+
async handleBufferedEvent() {
|
|
15289
|
+
if (this.shouldFlush()) {
|
|
15290
|
+
void this.flush().catch((error48) => {
|
|
15291
|
+
this.logger.error("Batch flush failed", {
|
|
15292
|
+
error: error48 instanceof Error ? error48.message : String(error48)
|
|
15293
|
+
});
|
|
15294
|
+
});
|
|
15295
|
+
} else if (this.buffer.totalSize === 1) {
|
|
15296
|
+
this.scheduleFlush();
|
|
15297
|
+
}
|
|
15298
|
+
}
|
|
15099
15299
|
shouldFlush() {
|
|
15100
15300
|
if (this.buffer.totalSize >= this.cloudConfig.maxBatchSize) {
|
|
15101
15301
|
return true;
|
|
@@ -15113,7 +15313,7 @@ var CloudExporter = class extends BaseExporter {
|
|
|
15113
15313
|
clearTimeout(this.flushTimer);
|
|
15114
15314
|
}
|
|
15115
15315
|
this.flushTimer = setTimeout(() => {
|
|
15116
|
-
this.flush().catch((error48) => {
|
|
15316
|
+
void this.flush().catch((error48) => {
|
|
15117
15317
|
const mastraError = new MastraError(
|
|
15118
15318
|
{
|
|
15119
15319
|
id: `CLOUD_EXPORTER_FAILED_TO_SCHEDULE_FLUSH`,
|
|
@@ -15137,49 +15337,91 @@ var CloudExporter = class extends BaseExporter {
|
|
|
15137
15337
|
}
|
|
15138
15338
|
const startTime = Date.now();
|
|
15139
15339
|
const spansCopy = [...this.buffer.spans];
|
|
15340
|
+
const logsCopy = [...this.buffer.logs];
|
|
15341
|
+
const metricsCopy = [...this.buffer.metrics];
|
|
15342
|
+
const scoresCopy = [...this.buffer.scores];
|
|
15343
|
+
const feedbackCopy = [...this.buffer.feedback];
|
|
15344
|
+
const batchSize = this.buffer.totalSize;
|
|
15140
15345
|
const flushReason = this.buffer.totalSize >= this.cloudConfig.maxBatchSize ? "size" : "time";
|
|
15141
15346
|
this.resetBuffer();
|
|
15142
|
-
|
|
15143
|
-
|
|
15144
|
-
|
|
15347
|
+
const results = await Promise.all([
|
|
15348
|
+
this.flushSignalBatch("traces", spansCopy),
|
|
15349
|
+
this.flushSignalBatch("logs", logsCopy),
|
|
15350
|
+
this.flushSignalBatch("metrics", metricsCopy),
|
|
15351
|
+
this.flushSignalBatch("scores", scoresCopy),
|
|
15352
|
+
this.flushSignalBatch("feedback", feedbackCopy)
|
|
15353
|
+
]);
|
|
15354
|
+
const failedSignals = results.filter((result) => !result.succeeded).map((result) => result.signal);
|
|
15355
|
+
const elapsed = Date.now() - startTime;
|
|
15356
|
+
if (failedSignals.length === 0) {
|
|
15145
15357
|
this.logger.debug("Batch flushed successfully", {
|
|
15146
|
-
batchSize
|
|
15358
|
+
batchSize,
|
|
15147
15359
|
flushReason,
|
|
15148
15360
|
durationMs: elapsed
|
|
15149
15361
|
});
|
|
15362
|
+
return;
|
|
15363
|
+
}
|
|
15364
|
+
this.logger.warn("Batch flush completed with dropped signal batches", {
|
|
15365
|
+
batchSize,
|
|
15366
|
+
flushReason,
|
|
15367
|
+
durationMs: elapsed,
|
|
15368
|
+
failedSignals
|
|
15369
|
+
});
|
|
15370
|
+
}
|
|
15371
|
+
/**
|
|
15372
|
+
* Uploads a signal batch to the configured cloud API using fetchWithRetry.
|
|
15373
|
+
*/
|
|
15374
|
+
async batchUpload(signal, records) {
|
|
15375
|
+
const headers = {
|
|
15376
|
+
Authorization: `Bearer ${this.cloudConfig.accessToken}`,
|
|
15377
|
+
"Content-Type": "application/json"
|
|
15378
|
+
};
|
|
15379
|
+
const endpointMap = {
|
|
15380
|
+
traces: this.cloudConfig.tracesEndpoint,
|
|
15381
|
+
logs: this.cloudConfig.logsEndpoint,
|
|
15382
|
+
metrics: this.cloudConfig.metricsEndpoint,
|
|
15383
|
+
scores: this.cloudConfig.scoresEndpoint,
|
|
15384
|
+
feedback: this.cloudConfig.feedbackEndpoint
|
|
15385
|
+
};
|
|
15386
|
+
const options = {
|
|
15387
|
+
method: "POST",
|
|
15388
|
+
headers,
|
|
15389
|
+
body: JSON.stringify({ [SIGNAL_PAYLOAD_KEYS[signal]]: records })
|
|
15390
|
+
};
|
|
15391
|
+
await fetchWithRetry(endpointMap[signal], options, this.cloudConfig.maxRetries);
|
|
15392
|
+
}
|
|
15393
|
+
async flushSignalBatch(signal, records) {
|
|
15394
|
+
if (records.length === 0) {
|
|
15395
|
+
return { signal, succeeded: true };
|
|
15396
|
+
}
|
|
15397
|
+
try {
|
|
15398
|
+
await this.batchUpload(signal, records);
|
|
15399
|
+
return { signal, succeeded: true };
|
|
15150
15400
|
} catch (error48) {
|
|
15401
|
+
const errorId = `CLOUD_EXPORTER_FAILED_TO_BATCH_UPLOAD_${signal.toUpperCase()}`;
|
|
15151
15402
|
const mastraError = new MastraError(
|
|
15152
15403
|
{
|
|
15153
|
-
id:
|
|
15404
|
+
id: errorId,
|
|
15154
15405
|
domain: ErrorDomain.MASTRA_OBSERVABILITY,
|
|
15155
15406
|
category: ErrorCategory.USER,
|
|
15156
15407
|
details: {
|
|
15157
|
-
|
|
15408
|
+
signal,
|
|
15409
|
+
droppedBatchSize: records.length
|
|
15158
15410
|
}
|
|
15159
15411
|
},
|
|
15160
15412
|
error48
|
|
15161
15413
|
);
|
|
15162
15414
|
this.logger.trackException(mastraError);
|
|
15163
15415
|
this.logger.error("Batch upload failed after all retries, dropping batch", mastraError);
|
|
15416
|
+
return { signal, succeeded: false };
|
|
15164
15417
|
}
|
|
15165
15418
|
}
|
|
15166
|
-
/**
|
|
15167
|
-
* Uploads spans to cloud API using fetchWithRetry for all retry logic
|
|
15168
|
-
*/
|
|
15169
|
-
async batchUpload(spans) {
|
|
15170
|
-
const headers = {
|
|
15171
|
-
Authorization: `Bearer ${this.cloudConfig.accessToken}`,
|
|
15172
|
-
"Content-Type": "application/json"
|
|
15173
|
-
};
|
|
15174
|
-
const options = {
|
|
15175
|
-
method: "POST",
|
|
15176
|
-
headers,
|
|
15177
|
-
body: JSON.stringify({ spans })
|
|
15178
|
-
};
|
|
15179
|
-
await fetchWithRetry(this.cloudConfig.endpoint, options, this.cloudConfig.maxRetries);
|
|
15180
|
-
}
|
|
15181
15419
|
resetBuffer() {
|
|
15182
15420
|
this.buffer.spans = [];
|
|
15421
|
+
this.buffer.logs = [];
|
|
15422
|
+
this.buffer.metrics = [];
|
|
15423
|
+
this.buffer.scores = [];
|
|
15424
|
+
this.buffer.feedback = [];
|
|
15183
15425
|
this.buffer.firstEventTime = void 0;
|
|
15184
15426
|
this.buffer.totalSize = 0;
|
|
15185
15427
|
}
|
|
@@ -15192,11 +15434,21 @@ var CloudExporter = class extends BaseExporter {
|
|
|
15192
15434
|
if (this.isDisabled) {
|
|
15193
15435
|
return;
|
|
15194
15436
|
}
|
|
15195
|
-
|
|
15196
|
-
this.
|
|
15197
|
-
|
|
15198
|
-
|
|
15199
|
-
|
|
15437
|
+
while (this.buffer.totalSize > 0 || this.inFlightFlushes.size > 0) {
|
|
15438
|
+
if (this.buffer.totalSize > 0) {
|
|
15439
|
+
this.logger.debug("Flushing buffered events", {
|
|
15440
|
+
bufferedEvents: this.buffer.totalSize
|
|
15441
|
+
});
|
|
15442
|
+
const flushPromise = this.flushBuffer();
|
|
15443
|
+
this.inFlightFlushes.add(flushPromise);
|
|
15444
|
+
try {
|
|
15445
|
+
await flushPromise;
|
|
15446
|
+
} finally {
|
|
15447
|
+
this.inFlightFlushes.delete(flushPromise);
|
|
15448
|
+
}
|
|
15449
|
+
continue;
|
|
15450
|
+
}
|
|
15451
|
+
await Promise.allSettled([...this.inFlightFlushes]);
|
|
15200
15452
|
}
|
|
15201
15453
|
}
|
|
15202
15454
|
async shutdown() {
|
|
@@ -17036,96 +17288,464 @@ var BaseObservabilityEventBus = class _BaseObservabilityEventBus extends MastraB
|
|
|
17036
17288
|
}
|
|
17037
17289
|
};
|
|
17038
17290
|
|
|
17039
|
-
// src/
|
|
17040
|
-
var
|
|
17041
|
-
|
|
17042
|
-
|
|
17043
|
-
|
|
17044
|
-
|
|
17045
|
-
|
|
17046
|
-
|
|
17047
|
-
|
|
17291
|
+
// src/spans/serialization.ts
|
|
17292
|
+
var DEFAULT_KEYS_TO_STRIP = /* @__PURE__ */ new Set([
|
|
17293
|
+
"logger",
|
|
17294
|
+
"experimental_providerMetadata",
|
|
17295
|
+
"providerMetadata",
|
|
17296
|
+
"steps",
|
|
17297
|
+
"tracingContext",
|
|
17298
|
+
"execute",
|
|
17299
|
+
// Tool execute functions
|
|
17300
|
+
"validate"
|
|
17301
|
+
// Schema validate functions
|
|
17302
|
+
]);
|
|
17303
|
+
var DEFAULT_DEEP_CLEAN_OPTIONS = Object.freeze({
|
|
17304
|
+
keysToStrip: DEFAULT_KEYS_TO_STRIP,
|
|
17305
|
+
maxDepth: 8,
|
|
17306
|
+
maxStringLength: 128 * 1024,
|
|
17307
|
+
// 128KB - sufficient for large LLM prompts/responses
|
|
17308
|
+
maxArrayLength: 50,
|
|
17309
|
+
maxObjectKeys: 50
|
|
17310
|
+
});
|
|
17311
|
+
function mergeSerializationOptions(userOptions) {
|
|
17312
|
+
if (!userOptions) {
|
|
17313
|
+
return DEFAULT_DEEP_CLEAN_OPTIONS;
|
|
17048
17314
|
}
|
|
17049
|
-
|
|
17050
|
-
|
|
17051
|
-
|
|
17052
|
-
|
|
17053
|
-
|
|
17054
|
-
|
|
17055
|
-
|
|
17056
|
-
|
|
17057
|
-
|
|
17058
|
-
|
|
17059
|
-
|
|
17315
|
+
return {
|
|
17316
|
+
keysToStrip: DEFAULT_KEYS_TO_STRIP,
|
|
17317
|
+
maxDepth: userOptions.maxDepth ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxDepth,
|
|
17318
|
+
maxStringLength: userOptions.maxStringLength ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxStringLength,
|
|
17319
|
+
maxArrayLength: userOptions.maxArrayLength ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxArrayLength,
|
|
17320
|
+
maxObjectKeys: userOptions.maxObjectKeys ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxObjectKeys
|
|
17321
|
+
};
|
|
17322
|
+
}
|
|
17323
|
+
function truncateString(s, maxChars) {
|
|
17324
|
+
if (s.length <= maxChars) {
|
|
17325
|
+
return s;
|
|
17060
17326
|
}
|
|
17061
|
-
|
|
17062
|
-
|
|
17063
|
-
|
|
17064
|
-
|
|
17065
|
-
|
|
17066
|
-
|
|
17067
|
-
|
|
17068
|
-
|
|
17069
|
-
if (index !== -1) {
|
|
17070
|
-
this.exporters.splice(index, 1);
|
|
17071
|
-
return true;
|
|
17072
|
-
}
|
|
17073
|
-
return false;
|
|
17327
|
+
return s.slice(0, maxChars) + "\u2026[truncated]";
|
|
17328
|
+
}
|
|
17329
|
+
function formatSerializationError(error48) {
|
|
17330
|
+
return `[${error48 instanceof Error ? truncateString(error48.message, 256) : "unknown error"}]`;
|
|
17331
|
+
}
|
|
17332
|
+
function getMapKeyType(key) {
|
|
17333
|
+
if (key === null) {
|
|
17334
|
+
return "null";
|
|
17074
17335
|
}
|
|
17075
|
-
|
|
17076
|
-
|
|
17077
|
-
*/
|
|
17078
|
-
getExporters() {
|
|
17079
|
-
return [...this.exporters];
|
|
17336
|
+
if (key instanceof Date) {
|
|
17337
|
+
return "date";
|
|
17080
17338
|
}
|
|
17081
|
-
|
|
17082
|
-
|
|
17083
|
-
* Only one bridge can be registered at a time; replacing an existing bridge
|
|
17084
|
-
* logs a warning.
|
|
17085
|
-
*
|
|
17086
|
-
* @param bridge - The bridge to register.
|
|
17087
|
-
*/
|
|
17088
|
-
registerBridge(bridge) {
|
|
17089
|
-
if (this.bridge) {
|
|
17090
|
-
this.logger.warn(`[ObservabilityBus] Replacing existing bridge with new bridge`);
|
|
17091
|
-
}
|
|
17092
|
-
this.bridge = bridge;
|
|
17339
|
+
if (Array.isArray(key)) {
|
|
17340
|
+
return "array";
|
|
17093
17341
|
}
|
|
17094
|
-
|
|
17095
|
-
|
|
17096
|
-
*
|
|
17097
|
-
* @returns `true` if a bridge was registered and removed, `false` otherwise.
|
|
17098
|
-
*/
|
|
17099
|
-
unregisterBridge() {
|
|
17100
|
-
if (this.bridge) {
|
|
17101
|
-
this.bridge = void 0;
|
|
17102
|
-
return true;
|
|
17103
|
-
}
|
|
17104
|
-
return false;
|
|
17342
|
+
if (key instanceof Map) {
|
|
17343
|
+
return "map";
|
|
17105
17344
|
}
|
|
17106
|
-
|
|
17107
|
-
|
|
17108
|
-
*/
|
|
17109
|
-
getBridge() {
|
|
17110
|
-
return this.bridge;
|
|
17345
|
+
if (key instanceof Set) {
|
|
17346
|
+
return "set";
|
|
17111
17347
|
}
|
|
17112
|
-
|
|
17113
|
-
|
|
17114
|
-
* class for subscriber delivery.
|
|
17115
|
-
*
|
|
17116
|
-
* emit() is synchronous — async handler promises are tracked internally
|
|
17117
|
-
* and can be drained via flush().
|
|
17118
|
-
*/
|
|
17119
|
-
emit(event) {
|
|
17120
|
-
for (const exporter of this.exporters) {
|
|
17121
|
-
this.trackPromise(routeToHandler(exporter, event, this.logger));
|
|
17122
|
-
}
|
|
17123
|
-
if (this.bridge) {
|
|
17124
|
-
this.trackPromise(routeToHandler(this.bridge, event, this.logger));
|
|
17125
|
-
}
|
|
17126
|
-
super.emit(event);
|
|
17348
|
+
if (key instanceof Error) {
|
|
17349
|
+
return "error";
|
|
17127
17350
|
}
|
|
17128
|
-
|
|
17351
|
+
return typeof key;
|
|
17352
|
+
}
|
|
17353
|
+
function restoreSerializedMapKey(keyType, key) {
|
|
17354
|
+
switch (keyType) {
|
|
17355
|
+
case "undefined":
|
|
17356
|
+
return void 0;
|
|
17357
|
+
case "null":
|
|
17358
|
+
return null;
|
|
17359
|
+
case "bigint":
|
|
17360
|
+
return typeof key === "string" && key.endsWith("n") ? BigInt(key.slice(0, -1)) : key;
|
|
17361
|
+
case "date":
|
|
17362
|
+
return typeof key === "string" ? new Date(key) : key;
|
|
17363
|
+
default:
|
|
17364
|
+
return key;
|
|
17365
|
+
}
|
|
17366
|
+
}
|
|
17367
|
+
function isSerializedMap(value) {
|
|
17368
|
+
return typeof value === "object" && value !== null && value.__type === "Map" && Array.isArray(value.__map_entries);
|
|
17369
|
+
}
|
|
17370
|
+
function reconstructSerializedMap(value) {
|
|
17371
|
+
return new Map(
|
|
17372
|
+
value.__map_entries.map(([keyType, key, mapValue]) => [restoreSerializedMapKey(keyType, key), mapValue])
|
|
17373
|
+
);
|
|
17374
|
+
}
|
|
17375
|
+
function isJsonSchema(val) {
|
|
17376
|
+
if (typeof val !== "object" || val === null) return false;
|
|
17377
|
+
if (val.$schema && typeof val.$schema === "string" && val.$schema.includes("json-schema")) {
|
|
17378
|
+
return true;
|
|
17379
|
+
}
|
|
17380
|
+
if (val.type === "object" && val.properties && typeof val.properties === "object") {
|
|
17381
|
+
return true;
|
|
17382
|
+
}
|
|
17383
|
+
return false;
|
|
17384
|
+
}
|
|
17385
|
+
function compressJsonSchema(schema, depth = 0) {
|
|
17386
|
+
if (depth > 3) {
|
|
17387
|
+
return schema.type || "object";
|
|
17388
|
+
}
|
|
17389
|
+
const compositionKeys = ["oneOf", "anyOf", "allOf"].filter((key) => Array.isArray(schema[key]));
|
|
17390
|
+
if (compositionKeys.length > 0) {
|
|
17391
|
+
const compressed2 = {};
|
|
17392
|
+
for (const key of compositionKeys) {
|
|
17393
|
+
compressed2[key] = schema[key].map((entry) => compressJsonSchema(entry, depth + 1));
|
|
17394
|
+
}
|
|
17395
|
+
if (typeof schema.type === "string") {
|
|
17396
|
+
compressed2.type = schema.type;
|
|
17397
|
+
}
|
|
17398
|
+
return compressed2;
|
|
17399
|
+
}
|
|
17400
|
+
if (schema.type !== "object" || !schema.properties) {
|
|
17401
|
+
return schema.type || schema;
|
|
17402
|
+
}
|
|
17403
|
+
const required2 = new Set(Array.isArray(schema.required) ? schema.required : []);
|
|
17404
|
+
const compressed = {};
|
|
17405
|
+
for (const [key, propSchema] of Object.entries(schema.properties)) {
|
|
17406
|
+
const prop = propSchema;
|
|
17407
|
+
let value = prop.type || "unknown";
|
|
17408
|
+
if (prop.type === "object" && prop.properties) {
|
|
17409
|
+
value = compressJsonSchema(prop, depth + 1);
|
|
17410
|
+
if (required2.has(key)) {
|
|
17411
|
+
compressed[key + " (required)"] = value;
|
|
17412
|
+
continue;
|
|
17413
|
+
}
|
|
17414
|
+
} else if (prop.type === "array" && prop.items) {
|
|
17415
|
+
if (prop.items.type === "object" && prop.items.properties) {
|
|
17416
|
+
value = [compressJsonSchema(prop.items, depth + 1)];
|
|
17417
|
+
} else {
|
|
17418
|
+
value = `${prop.items.type || "any"}[]`;
|
|
17419
|
+
}
|
|
17420
|
+
} else if (prop.enum) {
|
|
17421
|
+
value = prop.enum.map((v) => JSON.stringify(v)).join(" | ");
|
|
17422
|
+
}
|
|
17423
|
+
if (required2.has(key) && typeof value === "string") {
|
|
17424
|
+
value += " (required)";
|
|
17425
|
+
}
|
|
17426
|
+
compressed[key] = value;
|
|
17427
|
+
}
|
|
17428
|
+
return compressed;
|
|
17429
|
+
}
|
|
17430
|
+
function deepClean(value, options = DEFAULT_DEEP_CLEAN_OPTIONS) {
|
|
17431
|
+
const { keysToStrip, maxDepth, maxStringLength, maxArrayLength, maxObjectKeys } = options;
|
|
17432
|
+
const stripSet = keysToStrip instanceof Set ? keysToStrip : new Set(Array.isArray(keysToStrip) ? keysToStrip : Object.keys(keysToStrip));
|
|
17433
|
+
const ancestors = /* @__PURE__ */ new WeakSet();
|
|
17434
|
+
function helper(val, depth) {
|
|
17435
|
+
if (depth > maxDepth) {
|
|
17436
|
+
return "[MaxDepth]";
|
|
17437
|
+
}
|
|
17438
|
+
if (val === null || val === void 0) {
|
|
17439
|
+
return val;
|
|
17440
|
+
}
|
|
17441
|
+
if (typeof val === "string") {
|
|
17442
|
+
return truncateString(val, maxStringLength);
|
|
17443
|
+
}
|
|
17444
|
+
if (typeof val === "number" || typeof val === "boolean") {
|
|
17445
|
+
return val;
|
|
17446
|
+
}
|
|
17447
|
+
if (typeof val === "bigint") {
|
|
17448
|
+
return `${val}n`;
|
|
17449
|
+
}
|
|
17450
|
+
if (typeof val === "function") {
|
|
17451
|
+
return "[Function]";
|
|
17452
|
+
}
|
|
17453
|
+
if (typeof val === "symbol") {
|
|
17454
|
+
return val.description ? `[Symbol(${val.description})]` : "[Symbol]";
|
|
17455
|
+
}
|
|
17456
|
+
if (val instanceof Date) {
|
|
17457
|
+
return val;
|
|
17458
|
+
}
|
|
17459
|
+
if (typeof val === "object") {
|
|
17460
|
+
if (ancestors.has(val)) {
|
|
17461
|
+
return "[Circular]";
|
|
17462
|
+
}
|
|
17463
|
+
ancestors.add(val);
|
|
17464
|
+
}
|
|
17465
|
+
try {
|
|
17466
|
+
if (val instanceof Error) {
|
|
17467
|
+
let errorName;
|
|
17468
|
+
let errorMessage;
|
|
17469
|
+
let errorStack;
|
|
17470
|
+
let rawCause;
|
|
17471
|
+
let causeReadFailed = false;
|
|
17472
|
+
try {
|
|
17473
|
+
errorName = val.name;
|
|
17474
|
+
} catch (error48) {
|
|
17475
|
+
errorName = formatSerializationError(error48);
|
|
17476
|
+
}
|
|
17477
|
+
try {
|
|
17478
|
+
errorMessage = val.message;
|
|
17479
|
+
} catch (error48) {
|
|
17480
|
+
errorMessage = formatSerializationError(error48);
|
|
17481
|
+
}
|
|
17482
|
+
try {
|
|
17483
|
+
errorStack = val.stack;
|
|
17484
|
+
} catch (error48) {
|
|
17485
|
+
errorStack = formatSerializationError(error48);
|
|
17486
|
+
}
|
|
17487
|
+
try {
|
|
17488
|
+
rawCause = val.cause;
|
|
17489
|
+
} catch (error48) {
|
|
17490
|
+
causeReadFailed = true;
|
|
17491
|
+
rawCause = formatSerializationError(error48);
|
|
17492
|
+
}
|
|
17493
|
+
const cleanedError = {
|
|
17494
|
+
name: typeof errorName === "string" ? truncateString(errorName, maxStringLength) : errorName,
|
|
17495
|
+
message: typeof errorMessage === "string" ? truncateString(errorMessage, maxStringLength) : errorMessage
|
|
17496
|
+
};
|
|
17497
|
+
if (typeof errorStack === "string") {
|
|
17498
|
+
cleanedError.stack = truncateString(errorStack, maxStringLength);
|
|
17499
|
+
} else if (errorStack !== void 0) {
|
|
17500
|
+
cleanedError.stack = errorStack;
|
|
17501
|
+
}
|
|
17502
|
+
if (causeReadFailed) {
|
|
17503
|
+
cleanedError.cause = rawCause;
|
|
17504
|
+
} else if (rawCause !== void 0) {
|
|
17505
|
+
try {
|
|
17506
|
+
cleanedError.cause = helper(rawCause, depth + 1);
|
|
17507
|
+
} catch (error48) {
|
|
17508
|
+
cleanedError.cause = formatSerializationError(error48);
|
|
17509
|
+
}
|
|
17510
|
+
}
|
|
17511
|
+
return cleanedError;
|
|
17512
|
+
}
|
|
17513
|
+
if (val instanceof Map) {
|
|
17514
|
+
const cleanedMap = { __type: "Map", __map_entries: [] };
|
|
17515
|
+
let mapKeyCount = 0;
|
|
17516
|
+
let omittedMapEntries = 0;
|
|
17517
|
+
for (const [mapKey, mapVal] of val) {
|
|
17518
|
+
if (typeof mapKey === "string" && stripSet.has(mapKey)) {
|
|
17519
|
+
continue;
|
|
17520
|
+
}
|
|
17521
|
+
if (mapKeyCount >= maxObjectKeys) {
|
|
17522
|
+
omittedMapEntries++;
|
|
17523
|
+
continue;
|
|
17524
|
+
}
|
|
17525
|
+
const mapKeyType = getMapKeyType(mapKey);
|
|
17526
|
+
let cleanedMapKey;
|
|
17527
|
+
let cleanedMapValue;
|
|
17528
|
+
try {
|
|
17529
|
+
cleanedMapKey = helper(mapKey, depth + 1);
|
|
17530
|
+
} catch (error48) {
|
|
17531
|
+
cleanedMapKey = formatSerializationError(error48);
|
|
17532
|
+
}
|
|
17533
|
+
try {
|
|
17534
|
+
cleanedMapValue = helper(mapVal, depth + 1);
|
|
17535
|
+
} catch (error48) {
|
|
17536
|
+
cleanedMapValue = formatSerializationError(error48);
|
|
17537
|
+
}
|
|
17538
|
+
cleanedMap.__map_entries.push([mapKeyType, cleanedMapKey, cleanedMapValue]);
|
|
17539
|
+
mapKeyCount++;
|
|
17540
|
+
}
|
|
17541
|
+
if (omittedMapEntries > 0) {
|
|
17542
|
+
cleanedMap.__truncated = `${omittedMapEntries} more keys omitted`;
|
|
17543
|
+
}
|
|
17544
|
+
return cleanedMap;
|
|
17545
|
+
}
|
|
17546
|
+
if (val instanceof Set) {
|
|
17547
|
+
const cleanedSet = [];
|
|
17548
|
+
let i = 0;
|
|
17549
|
+
const totalSetSize = val.size;
|
|
17550
|
+
for (const item of val) {
|
|
17551
|
+
if (i >= maxArrayLength) break;
|
|
17552
|
+
try {
|
|
17553
|
+
cleanedSet.push(helper(item, depth + 1));
|
|
17554
|
+
} catch (error48) {
|
|
17555
|
+
cleanedSet.push(formatSerializationError(error48));
|
|
17556
|
+
}
|
|
17557
|
+
i++;
|
|
17558
|
+
}
|
|
17559
|
+
if (totalSetSize > maxArrayLength) {
|
|
17560
|
+
cleanedSet.push(`[\u2026${totalSetSize - maxArrayLength} more items]`);
|
|
17561
|
+
}
|
|
17562
|
+
return cleanedSet;
|
|
17563
|
+
}
|
|
17564
|
+
if (Array.isArray(val)) {
|
|
17565
|
+
const cleaned2 = [];
|
|
17566
|
+
for (let i = 0; i < Math.min(val.length, maxArrayLength); i++) {
|
|
17567
|
+
try {
|
|
17568
|
+
cleaned2.push(helper(val[i], depth + 1));
|
|
17569
|
+
} catch (error48) {
|
|
17570
|
+
cleaned2.push(formatSerializationError(error48));
|
|
17571
|
+
}
|
|
17572
|
+
}
|
|
17573
|
+
if (val.length > maxArrayLength) {
|
|
17574
|
+
cleaned2.push(`[\u2026${val.length - maxArrayLength} more items]`);
|
|
17575
|
+
}
|
|
17576
|
+
return cleaned2;
|
|
17577
|
+
}
|
|
17578
|
+
if (typeof Buffer !== "undefined" && Buffer.isBuffer(val)) {
|
|
17579
|
+
return `[Buffer length=${val.length}]`;
|
|
17580
|
+
}
|
|
17581
|
+
if (ArrayBuffer.isView(val)) {
|
|
17582
|
+
const ctor = val.constructor?.name ?? "TypedArray";
|
|
17583
|
+
const byteLength = val.byteLength ?? "?";
|
|
17584
|
+
return `[${ctor} byteLength=${byteLength}]`;
|
|
17585
|
+
}
|
|
17586
|
+
if (val instanceof ArrayBuffer) {
|
|
17587
|
+
return `[ArrayBuffer byteLength=${val.byteLength}]`;
|
|
17588
|
+
}
|
|
17589
|
+
let serializeForSpan;
|
|
17590
|
+
try {
|
|
17591
|
+
serializeForSpan = val.serializeForSpan;
|
|
17592
|
+
} catch (error48) {
|
|
17593
|
+
return `[serializeForSpan failed: ${error48 instanceof Error ? truncateString(error48.message, 256) : "unknown error"}]`;
|
|
17594
|
+
}
|
|
17595
|
+
if (typeof serializeForSpan === "function") {
|
|
17596
|
+
try {
|
|
17597
|
+
return helper(serializeForSpan.call(val), depth);
|
|
17598
|
+
} catch (error48) {
|
|
17599
|
+
return `[serializeForSpan failed: ${error48 instanceof Error ? truncateString(error48.message, 256) : "unknown error"}]`;
|
|
17600
|
+
}
|
|
17601
|
+
}
|
|
17602
|
+
let looksLikeJsonSchema = false;
|
|
17603
|
+
try {
|
|
17604
|
+
looksLikeJsonSchema = isJsonSchema(val);
|
|
17605
|
+
} catch {
|
|
17606
|
+
looksLikeJsonSchema = false;
|
|
17607
|
+
}
|
|
17608
|
+
if (looksLikeJsonSchema) {
|
|
17609
|
+
try {
|
|
17610
|
+
const compressed = compressJsonSchema(val);
|
|
17611
|
+
return compressed === val ? "[JSONSchema]" : helper(compressed, depth);
|
|
17612
|
+
} catch {
|
|
17613
|
+
}
|
|
17614
|
+
}
|
|
17615
|
+
const cleaned = {};
|
|
17616
|
+
const keys = Object.keys(val).filter((key) => !stripSet.has(key));
|
|
17617
|
+
let keyCount = 0;
|
|
17618
|
+
for (const key of keys) {
|
|
17619
|
+
if (keyCount >= maxObjectKeys) {
|
|
17620
|
+
cleaned["__truncated"] = `${keys.length - keyCount} more keys omitted`;
|
|
17621
|
+
break;
|
|
17622
|
+
}
|
|
17623
|
+
try {
|
|
17624
|
+
cleaned[key] = helper(val[key], depth + 1);
|
|
17625
|
+
keyCount++;
|
|
17626
|
+
} catch (error48) {
|
|
17627
|
+
cleaned[key] = formatSerializationError(error48);
|
|
17628
|
+
keyCount++;
|
|
17629
|
+
}
|
|
17630
|
+
}
|
|
17631
|
+
return cleaned;
|
|
17632
|
+
} finally {
|
|
17633
|
+
if (typeof val === "object" && val !== null) {
|
|
17634
|
+
ancestors.delete(val);
|
|
17635
|
+
}
|
|
17636
|
+
}
|
|
17637
|
+
}
|
|
17638
|
+
return helper(value, 0);
|
|
17639
|
+
}
|
|
17640
|
+
|
|
17641
|
+
// src/bus/observability-bus.ts
|
|
17642
|
+
function cleanEvent(event, options) {
|
|
17643
|
+
switch (event.type) {
|
|
17644
|
+
case "log":
|
|
17645
|
+
return { type: "log", log: deepClean(event.log, options) };
|
|
17646
|
+
case "metric":
|
|
17647
|
+
return { type: "metric", metric: deepClean(event.metric, options) };
|
|
17648
|
+
case "score":
|
|
17649
|
+
return { type: "score", score: deepClean(event.score, options) };
|
|
17650
|
+
case "feedback":
|
|
17651
|
+
return { type: "feedback", feedback: deepClean(event.feedback, options) };
|
|
17652
|
+
default:
|
|
17653
|
+
return event;
|
|
17654
|
+
}
|
|
17655
|
+
}
|
|
17656
|
+
var MAX_FLUSH_ITERATIONS = 3;
|
|
17657
|
+
var ObservabilityBus = class extends BaseObservabilityEventBus {
|
|
17658
|
+
exporters = [];
|
|
17659
|
+
bridge;
|
|
17660
|
+
/** In-flight handler promises from routeToHandler. Self-cleaning via .finally(). */
|
|
17661
|
+
pendingHandlers = /* @__PURE__ */ new Set();
|
|
17662
|
+
/** Resolved deepClean options applied to non-tracing events before fan-out. */
|
|
17663
|
+
deepCleanOptions;
|
|
17664
|
+
constructor(opts) {
|
|
17665
|
+
super({ name: "ObservabilityBus" });
|
|
17666
|
+
this.deepCleanOptions = mergeSerializationOptions(opts?.serializationOptions);
|
|
17667
|
+
}
|
|
17668
|
+
/**
|
|
17669
|
+
* Register an exporter to receive routed events.
|
|
17670
|
+
* Duplicate registrations (same instance) are silently ignored.
|
|
17671
|
+
*
|
|
17672
|
+
* @param exporter - The exporter to register.
|
|
17673
|
+
*/
|
|
17674
|
+
registerExporter(exporter) {
|
|
17675
|
+
if (this.exporters.includes(exporter)) {
|
|
17676
|
+
return;
|
|
17677
|
+
}
|
|
17678
|
+
this.exporters.push(exporter);
|
|
17679
|
+
}
|
|
17680
|
+
/**
|
|
17681
|
+
* Unregister an exporter.
|
|
17682
|
+
*
|
|
17683
|
+
* @param exporter - The exporter instance to remove.
|
|
17684
|
+
* @returns `true` if the exporter was found and removed, `false` otherwise.
|
|
17685
|
+
*/
|
|
17686
|
+
unregisterExporter(exporter) {
|
|
17687
|
+
const index = this.exporters.indexOf(exporter);
|
|
17688
|
+
if (index !== -1) {
|
|
17689
|
+
this.exporters.splice(index, 1);
|
|
17690
|
+
return true;
|
|
17691
|
+
}
|
|
17692
|
+
return false;
|
|
17693
|
+
}
|
|
17694
|
+
/**
|
|
17695
|
+
* Get registered exporters (read-only snapshot).
|
|
17696
|
+
*/
|
|
17697
|
+
getExporters() {
|
|
17698
|
+
return [...this.exporters];
|
|
17699
|
+
}
|
|
17700
|
+
/**
|
|
17701
|
+
* Register a bridge to receive all routed events alongside exporters.
|
|
17702
|
+
* Only one bridge can be registered at a time; replacing an existing bridge
|
|
17703
|
+
* logs a warning.
|
|
17704
|
+
*
|
|
17705
|
+
* @param bridge - The bridge to register.
|
|
17706
|
+
*/
|
|
17707
|
+
registerBridge(bridge) {
|
|
17708
|
+
if (this.bridge) {
|
|
17709
|
+
this.logger.warn(`[ObservabilityBus] Replacing existing bridge with new bridge`);
|
|
17710
|
+
}
|
|
17711
|
+
this.bridge = bridge;
|
|
17712
|
+
}
|
|
17713
|
+
/**
|
|
17714
|
+
* Unregister the bridge.
|
|
17715
|
+
*
|
|
17716
|
+
* @returns `true` if a bridge was registered and removed, `false` otherwise.
|
|
17717
|
+
*/
|
|
17718
|
+
unregisterBridge() {
|
|
17719
|
+
if (this.bridge) {
|
|
17720
|
+
this.bridge = void 0;
|
|
17721
|
+
return true;
|
|
17722
|
+
}
|
|
17723
|
+
return false;
|
|
17724
|
+
}
|
|
17725
|
+
/**
|
|
17726
|
+
* Get the registered bridge, if any.
|
|
17727
|
+
*/
|
|
17728
|
+
getBridge() {
|
|
17729
|
+
return this.bridge;
|
|
17730
|
+
}
|
|
17731
|
+
/**
|
|
17732
|
+
* Emit an event: route to exporter/bridge handlers, then forward to base
|
|
17733
|
+
* class for subscriber delivery.
|
|
17734
|
+
*
|
|
17735
|
+
* emit() is synchronous — async handler promises are tracked internally
|
|
17736
|
+
* and can be drained via flush().
|
|
17737
|
+
*/
|
|
17738
|
+
emit(event) {
|
|
17739
|
+
const cleaned = cleanEvent(event, this.deepCleanOptions);
|
|
17740
|
+
for (const exporter of this.exporters) {
|
|
17741
|
+
this.trackPromise(routeToHandler(exporter, cleaned, this.logger));
|
|
17742
|
+
}
|
|
17743
|
+
if (this.bridge) {
|
|
17744
|
+
this.trackPromise(routeToHandler(this.bridge, cleaned, this.logger));
|
|
17745
|
+
}
|
|
17746
|
+
super.emit(cleaned);
|
|
17747
|
+
}
|
|
17748
|
+
/**
|
|
17129
17749
|
* Track an async handler promise so flush() can await it.
|
|
17130
17750
|
* No-ops for sync (void) results.
|
|
17131
17751
|
*/
|
|
@@ -18394,218 +19014,6 @@ var ModelSpanTracker = class {
|
|
|
18394
19014
|
}
|
|
18395
19015
|
};
|
|
18396
19016
|
|
|
18397
|
-
// src/spans/serialization.ts
|
|
18398
|
-
var DEFAULT_KEYS_TO_STRIP = /* @__PURE__ */ new Set([
|
|
18399
|
-
"logger",
|
|
18400
|
-
"experimental_providerMetadata",
|
|
18401
|
-
"providerMetadata",
|
|
18402
|
-
"steps",
|
|
18403
|
-
"tracingContext",
|
|
18404
|
-
"execute",
|
|
18405
|
-
// Tool execute functions
|
|
18406
|
-
"validate"
|
|
18407
|
-
// Schema validate functions
|
|
18408
|
-
]);
|
|
18409
|
-
var DEFAULT_DEEP_CLEAN_OPTIONS = Object.freeze({
|
|
18410
|
-
keysToStrip: DEFAULT_KEYS_TO_STRIP,
|
|
18411
|
-
maxDepth: 8,
|
|
18412
|
-
maxStringLength: 128 * 1024,
|
|
18413
|
-
// 128KB - sufficient for large LLM prompts/responses
|
|
18414
|
-
maxArrayLength: 50,
|
|
18415
|
-
maxObjectKeys: 50
|
|
18416
|
-
});
|
|
18417
|
-
function mergeSerializationOptions(userOptions) {
|
|
18418
|
-
if (!userOptions) {
|
|
18419
|
-
return DEFAULT_DEEP_CLEAN_OPTIONS;
|
|
18420
|
-
}
|
|
18421
|
-
return {
|
|
18422
|
-
keysToStrip: DEFAULT_KEYS_TO_STRIP,
|
|
18423
|
-
maxDepth: userOptions.maxDepth ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxDepth,
|
|
18424
|
-
maxStringLength: userOptions.maxStringLength ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxStringLength,
|
|
18425
|
-
maxArrayLength: userOptions.maxArrayLength ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxArrayLength,
|
|
18426
|
-
maxObjectKeys: userOptions.maxObjectKeys ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxObjectKeys
|
|
18427
|
-
};
|
|
18428
|
-
}
|
|
18429
|
-
function truncateString(s, maxChars) {
|
|
18430
|
-
if (s.length <= maxChars) {
|
|
18431
|
-
return s;
|
|
18432
|
-
}
|
|
18433
|
-
return s.slice(0, maxChars) + "\u2026[truncated]";
|
|
18434
|
-
}
|
|
18435
|
-
function isJsonSchema(val) {
|
|
18436
|
-
if (typeof val !== "object" || val === null) return false;
|
|
18437
|
-
if (val.$schema && typeof val.$schema === "string" && val.$schema.includes("json-schema")) {
|
|
18438
|
-
return true;
|
|
18439
|
-
}
|
|
18440
|
-
if (val.type === "object" && val.properties && typeof val.properties === "object") {
|
|
18441
|
-
return true;
|
|
18442
|
-
}
|
|
18443
|
-
return false;
|
|
18444
|
-
}
|
|
18445
|
-
function compressJsonSchema(schema, depth = 0) {
|
|
18446
|
-
if (depth > 3) {
|
|
18447
|
-
return schema.type || "object";
|
|
18448
|
-
}
|
|
18449
|
-
const compositionKeys = ["oneOf", "anyOf", "allOf"].filter((key) => Array.isArray(schema[key]));
|
|
18450
|
-
if (compositionKeys.length > 0) {
|
|
18451
|
-
const compressed2 = {};
|
|
18452
|
-
for (const key of compositionKeys) {
|
|
18453
|
-
compressed2[key] = schema[key].map((entry) => compressJsonSchema(entry, depth + 1));
|
|
18454
|
-
}
|
|
18455
|
-
if (typeof schema.type === "string") {
|
|
18456
|
-
compressed2.type = schema.type;
|
|
18457
|
-
}
|
|
18458
|
-
return compressed2;
|
|
18459
|
-
}
|
|
18460
|
-
if (schema.type !== "object" || !schema.properties) {
|
|
18461
|
-
return schema.type || schema;
|
|
18462
|
-
}
|
|
18463
|
-
const required2 = new Set(Array.isArray(schema.required) ? schema.required : []);
|
|
18464
|
-
const compressed = {};
|
|
18465
|
-
for (const [key, propSchema] of Object.entries(schema.properties)) {
|
|
18466
|
-
const prop = propSchema;
|
|
18467
|
-
let value = prop.type || "unknown";
|
|
18468
|
-
if (prop.type === "object" && prop.properties) {
|
|
18469
|
-
value = compressJsonSchema(prop, depth + 1);
|
|
18470
|
-
if (required2.has(key)) {
|
|
18471
|
-
compressed[key + " (required)"] = value;
|
|
18472
|
-
continue;
|
|
18473
|
-
}
|
|
18474
|
-
} else if (prop.type === "array" && prop.items) {
|
|
18475
|
-
if (prop.items.type === "object" && prop.items.properties) {
|
|
18476
|
-
value = [compressJsonSchema(prop.items, depth + 1)];
|
|
18477
|
-
} else {
|
|
18478
|
-
value = `${prop.items.type || "any"}[]`;
|
|
18479
|
-
}
|
|
18480
|
-
} else if (prop.enum) {
|
|
18481
|
-
value = prop.enum.map((v) => JSON.stringify(v)).join(" | ");
|
|
18482
|
-
}
|
|
18483
|
-
if (required2.has(key) && typeof value === "string") {
|
|
18484
|
-
value += " (required)";
|
|
18485
|
-
}
|
|
18486
|
-
compressed[key] = value;
|
|
18487
|
-
}
|
|
18488
|
-
return compressed;
|
|
18489
|
-
}
|
|
18490
|
-
function deepClean(value, options = DEFAULT_DEEP_CLEAN_OPTIONS) {
|
|
18491
|
-
const { keysToStrip, maxDepth, maxStringLength, maxArrayLength, maxObjectKeys } = options;
|
|
18492
|
-
const stripSet = keysToStrip instanceof Set ? keysToStrip : new Set(Array.isArray(keysToStrip) ? keysToStrip : Object.keys(keysToStrip));
|
|
18493
|
-
const ancestors = /* @__PURE__ */ new WeakSet();
|
|
18494
|
-
function helper(val, depth) {
|
|
18495
|
-
if (depth > maxDepth) {
|
|
18496
|
-
return "[MaxDepth]";
|
|
18497
|
-
}
|
|
18498
|
-
if (val === null || val === void 0) {
|
|
18499
|
-
return val;
|
|
18500
|
-
}
|
|
18501
|
-
if (typeof val === "string") {
|
|
18502
|
-
return truncateString(val, maxStringLength);
|
|
18503
|
-
}
|
|
18504
|
-
if (typeof val === "number" || typeof val === "boolean") {
|
|
18505
|
-
return val;
|
|
18506
|
-
}
|
|
18507
|
-
if (typeof val === "bigint") {
|
|
18508
|
-
return `${val}n`;
|
|
18509
|
-
}
|
|
18510
|
-
if (typeof val === "function") {
|
|
18511
|
-
return "[Function]";
|
|
18512
|
-
}
|
|
18513
|
-
if (typeof val === "symbol") {
|
|
18514
|
-
return val.description ? `[Symbol(${val.description})]` : "[Symbol]";
|
|
18515
|
-
}
|
|
18516
|
-
if (val instanceof Date) {
|
|
18517
|
-
return val;
|
|
18518
|
-
}
|
|
18519
|
-
if (val instanceof Error) {
|
|
18520
|
-
return {
|
|
18521
|
-
name: val.name,
|
|
18522
|
-
message: val.message ? truncateString(val.message, maxStringLength) : void 0
|
|
18523
|
-
};
|
|
18524
|
-
}
|
|
18525
|
-
if (typeof val === "object") {
|
|
18526
|
-
if (ancestors.has(val)) {
|
|
18527
|
-
return "[Circular]";
|
|
18528
|
-
}
|
|
18529
|
-
ancestors.add(val);
|
|
18530
|
-
}
|
|
18531
|
-
try {
|
|
18532
|
-
if (Array.isArray(val)) {
|
|
18533
|
-
const cleaned2 = [];
|
|
18534
|
-
for (let i = 0; i < Math.min(val.length, maxArrayLength); i++) {
|
|
18535
|
-
try {
|
|
18536
|
-
cleaned2.push(helper(val[i], depth + 1));
|
|
18537
|
-
} catch (error48) {
|
|
18538
|
-
cleaned2.push(`[${error48 instanceof Error ? truncateString(error48.message, 256) : "unknown error"}]`);
|
|
18539
|
-
}
|
|
18540
|
-
}
|
|
18541
|
-
if (val.length > maxArrayLength) {
|
|
18542
|
-
cleaned2.push(`[\u2026${val.length - maxArrayLength} more items]`);
|
|
18543
|
-
}
|
|
18544
|
-
return cleaned2;
|
|
18545
|
-
}
|
|
18546
|
-
if (typeof Buffer !== "undefined" && Buffer.isBuffer(val)) {
|
|
18547
|
-
return `[Buffer length=${val.length}]`;
|
|
18548
|
-
}
|
|
18549
|
-
if (ArrayBuffer.isView(val)) {
|
|
18550
|
-
const ctor = val.constructor?.name ?? "TypedArray";
|
|
18551
|
-
const byteLength = val.byteLength ?? "?";
|
|
18552
|
-
return `[${ctor} byteLength=${byteLength}]`;
|
|
18553
|
-
}
|
|
18554
|
-
if (val instanceof ArrayBuffer) {
|
|
18555
|
-
return `[ArrayBuffer byteLength=${val.byteLength}]`;
|
|
18556
|
-
}
|
|
18557
|
-
let serializeForSpan;
|
|
18558
|
-
try {
|
|
18559
|
-
serializeForSpan = val.serializeForSpan;
|
|
18560
|
-
} catch (error48) {
|
|
18561
|
-
return `[serializeForSpan failed: ${error48 instanceof Error ? truncateString(error48.message, 256) : "unknown error"}]`;
|
|
18562
|
-
}
|
|
18563
|
-
if (typeof serializeForSpan === "function") {
|
|
18564
|
-
try {
|
|
18565
|
-
return helper(serializeForSpan.call(val), depth);
|
|
18566
|
-
} catch (error48) {
|
|
18567
|
-
return `[serializeForSpan failed: ${error48 instanceof Error ? truncateString(error48.message, 256) : "unknown error"}]`;
|
|
18568
|
-
}
|
|
18569
|
-
}
|
|
18570
|
-
let looksLikeJsonSchema = false;
|
|
18571
|
-
try {
|
|
18572
|
-
looksLikeJsonSchema = isJsonSchema(val);
|
|
18573
|
-
} catch {
|
|
18574
|
-
looksLikeJsonSchema = false;
|
|
18575
|
-
}
|
|
18576
|
-
if (looksLikeJsonSchema) {
|
|
18577
|
-
try {
|
|
18578
|
-
const compressed = compressJsonSchema(val);
|
|
18579
|
-
return compressed === val ? "[JSONSchema]" : helper(compressed, depth);
|
|
18580
|
-
} catch {
|
|
18581
|
-
}
|
|
18582
|
-
}
|
|
18583
|
-
const cleaned = {};
|
|
18584
|
-
const keys = Object.keys(val).filter((key) => !stripSet.has(key));
|
|
18585
|
-
let keyCount = 0;
|
|
18586
|
-
for (const key of keys) {
|
|
18587
|
-
if (keyCount >= maxObjectKeys) {
|
|
18588
|
-
cleaned["__truncated"] = `${keys.length - keyCount} more keys omitted`;
|
|
18589
|
-
break;
|
|
18590
|
-
}
|
|
18591
|
-
try {
|
|
18592
|
-
cleaned[key] = helper(val[key], depth + 1);
|
|
18593
|
-
keyCount++;
|
|
18594
|
-
} catch (error48) {
|
|
18595
|
-
cleaned[key] = `[${error48 instanceof Error ? truncateString(error48.message, 256) : "unknown error"}]`;
|
|
18596
|
-
keyCount++;
|
|
18597
|
-
}
|
|
18598
|
-
}
|
|
18599
|
-
return cleaned;
|
|
18600
|
-
} finally {
|
|
18601
|
-
if (typeof val === "object" && val !== null) {
|
|
18602
|
-
ancestors.delete(val);
|
|
18603
|
-
}
|
|
18604
|
-
}
|
|
18605
|
-
}
|
|
18606
|
-
return helper(value, 0);
|
|
18607
|
-
}
|
|
18608
|
-
|
|
18609
19017
|
// src/spans/base.ts
|
|
18610
19018
|
function isSpanInternal(spanType, flags) {
|
|
18611
19019
|
if (flags === void 0 || flags === InternalSpans.NONE) {
|
|
@@ -19064,7 +19472,9 @@ var BaseObservabilityInstance = class extends MastraBase {
|
|
|
19064
19472
|
logging: config2.logging
|
|
19065
19473
|
};
|
|
19066
19474
|
this.cardinalityFilter = new CardinalityFilter(config2.cardinality);
|
|
19067
|
-
this.observabilityBus = new ObservabilityBus(
|
|
19475
|
+
this.observabilityBus = new ObservabilityBus({
|
|
19476
|
+
serializationOptions: this.config.serializationOptions
|
|
19477
|
+
});
|
|
19068
19478
|
for (const exporter of this.exporters) {
|
|
19069
19479
|
this.observabilityBus.registerExporter(exporter);
|
|
19070
19480
|
}
|
|
@@ -20397,6 +20807,6 @@ function buildTracingOptions(...updaters) {
|
|
|
20397
20807
|
return updaters.reduce((opts, updater) => updater(opts), {});
|
|
20398
20808
|
}
|
|
20399
20809
|
|
|
20400
|
-
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 };
|
|
20810
|
+
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, isSerializedMap, mergeSerializationOptions, observabilityConfigValueSchema, observabilityInstanceConfigSchema, observabilityRegistryConfigSchema, reconstructSerializedMap, routeToHandler, samplingStrategySchema, serializationOptionsSchema, truncateString };
|
|
20401
20811
|
//# sourceMappingURL=index.js.map
|
|
20402
20812
|
//# sourceMappingURL=index.js.map
|