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