@mastra/observability 1.0.0-beta.1 → 1.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -0
- package/dist/config.d.ts +107 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/exporters/index.d.ts +1 -0
- package/dist/exporters/index.d.ts.map +1 -1
- package/dist/exporters/test.d.ts +13 -0
- package/dist/exporters/test.d.ts.map +1 -0
- package/dist/index.cjs +300 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +298 -30
- package/dist/index.js.map +1 -1
- package/dist/instances/base.d.ts +9 -5
- package/dist/instances/base.d.ts.map +1 -1
- package/dist/model-tracing.d.ts +0 -6
- package/dist/model-tracing.d.ts.map +1 -1
- package/dist/span_processors/sensitive-data-filter.d.ts +7 -0
- package/dist/span_processors/sensitive-data-filter.d.ts.map +1 -1
- package/dist/spans/base.d.ts +39 -0
- package/dist/spans/base.d.ts.map +1 -1
- package/dist/spans/default.d.ts.map +1 -1
- package/dist/tracing-options.d.ts +27 -0
- package/dist/tracing-options.d.ts.map +1 -0
- package/package.json +8 -6
package/dist/index.cjs
CHANGED
|
@@ -37,18 +37,38 @@ var observabilityInstanceConfigSchema = zod.z.object({
|
|
|
37
37
|
serviceName: zod.z.string().min(1, "Service name is required"),
|
|
38
38
|
sampling: samplingStrategySchema.optional(),
|
|
39
39
|
exporters: zod.z.array(zod.z.any()).optional(),
|
|
40
|
+
bridge: zod.z.any().optional(),
|
|
40
41
|
spanOutputProcessors: zod.z.array(zod.z.any()).optional(),
|
|
41
42
|
includeInternalSpans: zod.z.boolean().optional(),
|
|
42
43
|
requestContextKeys: zod.z.array(zod.z.string()).optional()
|
|
43
|
-
})
|
|
44
|
+
}).refine(
|
|
45
|
+
(data) => {
|
|
46
|
+
const hasExporters = data.exporters && data.exporters.length > 0;
|
|
47
|
+
const hasBridge = !!data.bridge;
|
|
48
|
+
return hasExporters || hasBridge;
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
message: "At least one exporter or a bridge is required"
|
|
52
|
+
}
|
|
53
|
+
);
|
|
44
54
|
var observabilityConfigValueSchema = zod.z.object({
|
|
45
55
|
serviceName: zod.z.string().min(1, "Service name is required"),
|
|
46
56
|
sampling: samplingStrategySchema.optional(),
|
|
47
57
|
exporters: zod.z.array(zod.z.any()).optional(),
|
|
58
|
+
bridge: zod.z.any().optional(),
|
|
48
59
|
spanOutputProcessors: zod.z.array(zod.z.any()).optional(),
|
|
49
60
|
includeInternalSpans: zod.z.boolean().optional(),
|
|
50
61
|
requestContextKeys: zod.z.array(zod.z.string()).optional()
|
|
51
|
-
})
|
|
62
|
+
}).refine(
|
|
63
|
+
(data) => {
|
|
64
|
+
const hasExporters = data.exporters && data.exporters.length > 0;
|
|
65
|
+
const hasBridge = !!data.bridge;
|
|
66
|
+
return hasExporters || hasBridge;
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
message: "At least one exporter or a bridge is required"
|
|
70
|
+
}
|
|
71
|
+
);
|
|
52
72
|
var observabilityRegistryConfigSchema = zod.z.object({
|
|
53
73
|
default: zod.z.object({
|
|
54
74
|
enabled: zod.z.boolean().optional()
|
|
@@ -75,6 +95,18 @@ var observabilityRegistryConfigSchema = zod.z.object({
|
|
|
75
95
|
{
|
|
76
96
|
message: 'A "configSelector" function is required when multiple configs are specified to determine which config to use.'
|
|
77
97
|
}
|
|
98
|
+
).refine(
|
|
99
|
+
(data) => {
|
|
100
|
+
if (data.configSelector) {
|
|
101
|
+
const isDefaultEnabled = data.default?.enabled === true;
|
|
102
|
+
const hasConfigs = data.configs && typeof data.configs === "object" && !Array.isArray(data.configs) ? Object.keys(data.configs).length > 0 : false;
|
|
103
|
+
return isDefaultEnabled || hasConfigs;
|
|
104
|
+
}
|
|
105
|
+
return true;
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
message: 'A "configSelector" requires at least one config or default observability to be configured.'
|
|
109
|
+
}
|
|
78
110
|
);
|
|
79
111
|
var BaseExporter = class {
|
|
80
112
|
/** Mastra logger instance */
|
|
@@ -895,6 +927,27 @@ var DefaultExporter = class extends BaseExporter {
|
|
|
895
927
|
this.logger.info("DefaultExporter shutdown complete");
|
|
896
928
|
}
|
|
897
929
|
};
|
|
930
|
+
|
|
931
|
+
// src/exporters/test.ts
|
|
932
|
+
var TestExporter = class extends BaseExporter {
|
|
933
|
+
name = "tracing-test-exporter";
|
|
934
|
+
#events = [];
|
|
935
|
+
constructor(config = {}) {
|
|
936
|
+
super(config);
|
|
937
|
+
}
|
|
938
|
+
async _exportTracingEvent(event) {
|
|
939
|
+
this.#events.push(event);
|
|
940
|
+
}
|
|
941
|
+
clearEvents() {
|
|
942
|
+
this.#events = [];
|
|
943
|
+
}
|
|
944
|
+
get events() {
|
|
945
|
+
return this.#events;
|
|
946
|
+
}
|
|
947
|
+
async shutdown() {
|
|
948
|
+
this.logger.info("TestExporter shutdown");
|
|
949
|
+
}
|
|
950
|
+
};
|
|
898
951
|
var ModelSpanTracker = class {
|
|
899
952
|
#modelSpan;
|
|
900
953
|
#currentStepSpan;
|
|
@@ -902,9 +955,30 @@ var ModelSpanTracker = class {
|
|
|
902
955
|
#accumulator = {};
|
|
903
956
|
#stepIndex = 0;
|
|
904
957
|
#chunkSequence = 0;
|
|
958
|
+
/** Tracks whether completionStartTime has been captured for this generation */
|
|
959
|
+
#completionStartTimeCaptured = false;
|
|
960
|
+
/** Tracks tool output accumulators by toolCallId for consolidating sub-agent streams */
|
|
961
|
+
#toolOutputAccumulators = /* @__PURE__ */ new Map();
|
|
962
|
+
/** Tracks toolCallIds that had streaming output (to skip redundant tool-result spans) */
|
|
963
|
+
#streamedToolCallIds = /* @__PURE__ */ new Set();
|
|
905
964
|
constructor(modelSpan) {
|
|
906
965
|
this.#modelSpan = modelSpan;
|
|
907
966
|
}
|
|
967
|
+
/**
|
|
968
|
+
* Capture the completion start time (time to first token) when the first content chunk arrives.
|
|
969
|
+
* This is used by observability providers like Langfuse to calculate TTFT metrics.
|
|
970
|
+
*/
|
|
971
|
+
#captureCompletionStartTime() {
|
|
972
|
+
if (this.#completionStartTimeCaptured || !this.#modelSpan) {
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
this.#completionStartTimeCaptured = true;
|
|
976
|
+
this.#modelSpan.update({
|
|
977
|
+
attributes: {
|
|
978
|
+
completionStartTime: /* @__PURE__ */ new Date()
|
|
979
|
+
}
|
|
980
|
+
});
|
|
981
|
+
}
|
|
908
982
|
/**
|
|
909
983
|
* Get the tracing context for creating child spans.
|
|
910
984
|
* Returns the current step span if active, otherwise the model span.
|
|
@@ -1129,6 +1203,77 @@ var ModelSpanTracker = class {
|
|
|
1129
1203
|
break;
|
|
1130
1204
|
}
|
|
1131
1205
|
}
|
|
1206
|
+
/**
|
|
1207
|
+
* Handle tool-output chunks from sub-agents.
|
|
1208
|
+
* Consolidates streaming text/reasoning deltas into a single span per tool call.
|
|
1209
|
+
*/
|
|
1210
|
+
#handleToolOutputChunk(chunk) {
|
|
1211
|
+
if (chunk.type !== "tool-output") return;
|
|
1212
|
+
const payload = chunk.payload;
|
|
1213
|
+
const { output, toolCallId, toolName } = payload;
|
|
1214
|
+
let acc = this.#toolOutputAccumulators.get(toolCallId);
|
|
1215
|
+
if (!acc) {
|
|
1216
|
+
if (!this.#currentStepSpan) {
|
|
1217
|
+
this.#startStepSpan();
|
|
1218
|
+
}
|
|
1219
|
+
acc = {
|
|
1220
|
+
toolName: toolName || "unknown",
|
|
1221
|
+
toolCallId,
|
|
1222
|
+
text: "",
|
|
1223
|
+
reasoning: "",
|
|
1224
|
+
sequenceNumber: this.#chunkSequence++,
|
|
1225
|
+
// Name the span 'tool-result' for consistency (tool-call → tool-result)
|
|
1226
|
+
span: this.#currentStepSpan?.createChildSpan({
|
|
1227
|
+
name: `chunk: 'tool-result'`,
|
|
1228
|
+
type: observability.SpanType.MODEL_CHUNK,
|
|
1229
|
+
attributes: {
|
|
1230
|
+
chunkType: "tool-result",
|
|
1231
|
+
sequenceNumber: this.#chunkSequence - 1
|
|
1232
|
+
}
|
|
1233
|
+
})
|
|
1234
|
+
};
|
|
1235
|
+
this.#toolOutputAccumulators.set(toolCallId, acc);
|
|
1236
|
+
}
|
|
1237
|
+
if (output && typeof output === "object" && "type" in output) {
|
|
1238
|
+
const innerType = output.type;
|
|
1239
|
+
switch (innerType) {
|
|
1240
|
+
case "text-delta":
|
|
1241
|
+
if (output.payload?.text) {
|
|
1242
|
+
acc.text += output.payload.text;
|
|
1243
|
+
}
|
|
1244
|
+
break;
|
|
1245
|
+
case "reasoning-delta":
|
|
1246
|
+
if (output.payload?.text) {
|
|
1247
|
+
acc.reasoning += output.payload.text;
|
|
1248
|
+
}
|
|
1249
|
+
break;
|
|
1250
|
+
case "finish":
|
|
1251
|
+
case "workflow-finish":
|
|
1252
|
+
this.#endToolOutputSpan(toolCallId);
|
|
1253
|
+
break;
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
/**
|
|
1258
|
+
* End a tool output span and clean up the accumulator
|
|
1259
|
+
*/
|
|
1260
|
+
#endToolOutputSpan(toolCallId) {
|
|
1261
|
+
const acc = this.#toolOutputAccumulators.get(toolCallId);
|
|
1262
|
+
if (!acc) return;
|
|
1263
|
+
const output = {
|
|
1264
|
+
toolCallId: acc.toolCallId,
|
|
1265
|
+
toolName: acc.toolName
|
|
1266
|
+
};
|
|
1267
|
+
if (acc.text) {
|
|
1268
|
+
output.text = acc.text;
|
|
1269
|
+
}
|
|
1270
|
+
if (acc.reasoning) {
|
|
1271
|
+
output.reasoning = acc.reasoning;
|
|
1272
|
+
}
|
|
1273
|
+
acc.span?.end({ output });
|
|
1274
|
+
this.#toolOutputAccumulators.delete(toolCallId);
|
|
1275
|
+
this.#streamedToolCallIds.add(toolCallId);
|
|
1276
|
+
}
|
|
1132
1277
|
/**
|
|
1133
1278
|
* Wraps a stream with model tracing transform to track MODEL_STEP and MODEL_CHUNK spans.
|
|
1134
1279
|
*
|
|
@@ -1136,9 +1281,14 @@ var ModelSpanTracker = class {
|
|
|
1136
1281
|
* create MODEL_STEP and MODEL_CHUNK spans for each semantic unit in the stream.
|
|
1137
1282
|
*/
|
|
1138
1283
|
wrapStream(stream) {
|
|
1284
|
+
let captureCompletionStartTime = false;
|
|
1139
1285
|
return stream.pipeThrough(
|
|
1140
1286
|
new web.TransformStream({
|
|
1141
1287
|
transform: (chunk, controller) => {
|
|
1288
|
+
if (!captureCompletionStartTime) {
|
|
1289
|
+
captureCompletionStartTime = true;
|
|
1290
|
+
this.#captureCompletionStartTime();
|
|
1291
|
+
}
|
|
1142
1292
|
controller.enqueue(chunk);
|
|
1143
1293
|
switch (chunk.type) {
|
|
1144
1294
|
case "text-start":
|
|
@@ -1172,6 +1322,19 @@ var ModelSpanTracker = class {
|
|
|
1172
1322
|
case "start":
|
|
1173
1323
|
case "finish":
|
|
1174
1324
|
break;
|
|
1325
|
+
case "tool-output":
|
|
1326
|
+
this.#handleToolOutputChunk(chunk);
|
|
1327
|
+
break;
|
|
1328
|
+
case "tool-result": {
|
|
1329
|
+
const toolCallId = chunk.payload?.toolCallId;
|
|
1330
|
+
if (toolCallId && this.#streamedToolCallIds.has(toolCallId)) {
|
|
1331
|
+
this.#streamedToolCallIds.delete(toolCallId);
|
|
1332
|
+
break;
|
|
1333
|
+
}
|
|
1334
|
+
const { args, ...cleanPayload } = chunk.payload || {};
|
|
1335
|
+
this.#createEventSpan(chunk.type, cleanPayload);
|
|
1336
|
+
break;
|
|
1337
|
+
}
|
|
1175
1338
|
// Default: auto-create event span for all other chunk types
|
|
1176
1339
|
default: {
|
|
1177
1340
|
let outputPayload = chunk.payload;
|
|
@@ -1226,6 +1389,16 @@ function isSpanInternal(spanType, flags) {
|
|
|
1226
1389
|
return false;
|
|
1227
1390
|
}
|
|
1228
1391
|
}
|
|
1392
|
+
function getExternalParentId(options) {
|
|
1393
|
+
if (!options.parent) {
|
|
1394
|
+
return void 0;
|
|
1395
|
+
}
|
|
1396
|
+
if (options.parent.isInternal) {
|
|
1397
|
+
return options.parent.getParentSpanId(false);
|
|
1398
|
+
} else {
|
|
1399
|
+
return options.parent.id;
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1229
1402
|
var BaseSpan = class {
|
|
1230
1403
|
name;
|
|
1231
1404
|
type;
|
|
@@ -1240,6 +1413,7 @@ var BaseSpan = class {
|
|
|
1240
1413
|
output;
|
|
1241
1414
|
errorInfo;
|
|
1242
1415
|
metadata;
|
|
1416
|
+
tags;
|
|
1243
1417
|
traceState;
|
|
1244
1418
|
/** Parent span ID (for root spans that are children of external spans) */
|
|
1245
1419
|
parentSpanId;
|
|
@@ -1254,6 +1428,7 @@ var BaseSpan = class {
|
|
|
1254
1428
|
this.isEvent = options.isEvent ?? false;
|
|
1255
1429
|
this.isInternal = isSpanInternal(this.type, options.tracingPolicy?.internal);
|
|
1256
1430
|
this.traceState = options.traceState;
|
|
1431
|
+
this.tags = !options.parent && options.tags?.length ? options.tags : void 0;
|
|
1257
1432
|
if (this.isEvent) {
|
|
1258
1433
|
this.output = deepClean(options.output);
|
|
1259
1434
|
} else {
|
|
@@ -1316,12 +1491,36 @@ var BaseSpan = class {
|
|
|
1316
1491
|
errorInfo: this.errorInfo,
|
|
1317
1492
|
isEvent: this.isEvent,
|
|
1318
1493
|
isRootSpan: this.isRootSpan,
|
|
1319
|
-
parentSpanId: this.getParentSpanId(includeInternalSpans)
|
|
1494
|
+
parentSpanId: this.getParentSpanId(includeInternalSpans),
|
|
1495
|
+
// Tags are only included for root spans
|
|
1496
|
+
...this.isRootSpan && this.tags?.length ? { tags: this.tags } : {}
|
|
1320
1497
|
};
|
|
1321
1498
|
}
|
|
1322
1499
|
get externalTraceId() {
|
|
1323
1500
|
return this.isValid ? this.traceId : void 0;
|
|
1324
1501
|
}
|
|
1502
|
+
/**
|
|
1503
|
+
* Execute an async function within this span's tracing context.
|
|
1504
|
+
* Delegates to the bridge if available.
|
|
1505
|
+
*/
|
|
1506
|
+
async executeInContext(fn) {
|
|
1507
|
+
const bridge = this.observabilityInstance.getBridge();
|
|
1508
|
+
if (bridge?.executeInContext) {
|
|
1509
|
+
return bridge.executeInContext(this.id, fn);
|
|
1510
|
+
}
|
|
1511
|
+
return fn();
|
|
1512
|
+
}
|
|
1513
|
+
/**
|
|
1514
|
+
* Execute a synchronous function within this span's tracing context.
|
|
1515
|
+
* Delegates to the bridge if available.
|
|
1516
|
+
*/
|
|
1517
|
+
executeInContextSync(fn) {
|
|
1518
|
+
const bridge = this.observabilityInstance.getBridge();
|
|
1519
|
+
if (bridge?.executeInContextSync) {
|
|
1520
|
+
return bridge.executeInContextSync(this.id, fn);
|
|
1521
|
+
}
|
|
1522
|
+
return fn();
|
|
1523
|
+
}
|
|
1325
1524
|
};
|
|
1326
1525
|
var DEFAULT_KEYS_TO_STRIP = /* @__PURE__ */ new Set([
|
|
1327
1526
|
"logger",
|
|
@@ -1368,27 +1567,30 @@ var DefaultSpan = class extends BaseSpan {
|
|
|
1368
1567
|
traceId;
|
|
1369
1568
|
constructor(options, observabilityInstance) {
|
|
1370
1569
|
super(options, observabilityInstance);
|
|
1371
|
-
|
|
1570
|
+
const bridge = observabilityInstance.getBridge();
|
|
1571
|
+
if (bridge && !this.isInternal) {
|
|
1572
|
+
const bridgeIds = bridge.createSpan(options);
|
|
1573
|
+
if (bridgeIds) {
|
|
1574
|
+
this.id = bridgeIds.spanId;
|
|
1575
|
+
this.traceId = bridgeIds.traceId;
|
|
1576
|
+
this.parentSpanId = bridgeIds.parentSpanId;
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1372
1580
|
if (options.parent) {
|
|
1373
1581
|
this.traceId = options.parent.traceId;
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
} else {
|
|
1378
|
-
console.error(
|
|
1379
|
-
`[Mastra Tracing] Invalid traceId: must be 1-32 hexadecimal characters, got "${options.traceId}". Generating new trace ID.`
|
|
1380
|
-
);
|
|
1381
|
-
this.traceId = generateTraceId();
|
|
1382
|
-
}
|
|
1383
|
-
} else {
|
|
1384
|
-
this.traceId = generateTraceId();
|
|
1582
|
+
this.parentSpanId = options.parent.id;
|
|
1583
|
+
this.id = generateSpanId();
|
|
1584
|
+
return;
|
|
1385
1585
|
}
|
|
1386
|
-
|
|
1586
|
+
this.traceId = getOrCreateTraceId(options);
|
|
1587
|
+
this.id = generateSpanId();
|
|
1588
|
+
if (options.parentSpanId) {
|
|
1387
1589
|
if (isValidSpanId(options.parentSpanId)) {
|
|
1388
1590
|
this.parentSpanId = options.parentSpanId;
|
|
1389
1591
|
} else {
|
|
1390
1592
|
console.error(
|
|
1391
|
-
`[Mastra Tracing] Invalid parentSpanId: must be 1-16 hexadecimal characters, got "${options.parentSpanId}". Ignoring
|
|
1593
|
+
`[Mastra Tracing] Invalid parentSpanId: must be 1-16 hexadecimal characters, got "${options.parentSpanId}". Ignoring.`
|
|
1392
1594
|
);
|
|
1393
1595
|
}
|
|
1394
1596
|
}
|
|
@@ -1493,6 +1695,18 @@ function isValidTraceId(traceId) {
|
|
|
1493
1695
|
function isValidSpanId(spanId) {
|
|
1494
1696
|
return /^[0-9a-f]{1,16}$/i.test(spanId);
|
|
1495
1697
|
}
|
|
1698
|
+
function getOrCreateTraceId(options) {
|
|
1699
|
+
if (options.traceId) {
|
|
1700
|
+
if (isValidTraceId(options.traceId)) {
|
|
1701
|
+
return options.traceId;
|
|
1702
|
+
} else {
|
|
1703
|
+
console.error(
|
|
1704
|
+
`[Mastra Tracing] Invalid traceId: must be 1-32 hexadecimal characters, got "${options.traceId}". Generating new trace ID.`
|
|
1705
|
+
);
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
return generateTraceId();
|
|
1709
|
+
}
|
|
1496
1710
|
|
|
1497
1711
|
// src/spans/no-op.ts
|
|
1498
1712
|
var NoOpSpan = class extends BaseSpan {
|
|
@@ -1525,13 +1739,17 @@ var BaseObservabilityInstance = class extends base.MastraBase {
|
|
|
1525
1739
|
sampling: config.sampling ?? { type: "always" /* ALWAYS */ },
|
|
1526
1740
|
exporters: config.exporters ?? [],
|
|
1527
1741
|
spanOutputProcessors: config.spanOutputProcessors ?? [],
|
|
1742
|
+
bridge: config.bridge ?? void 0,
|
|
1528
1743
|
includeInternalSpans: config.includeInternalSpans ?? false,
|
|
1529
1744
|
requestContextKeys: config.requestContextKeys ?? []
|
|
1530
1745
|
};
|
|
1746
|
+
if (this.config.bridge?.init) {
|
|
1747
|
+
this.config.bridge.init({ config: this.config });
|
|
1748
|
+
}
|
|
1531
1749
|
}
|
|
1532
1750
|
/**
|
|
1533
1751
|
* Override setLogger to add Observability specific initialization log
|
|
1534
|
-
* and propagate logger to exporters
|
|
1752
|
+
* and propagate logger to exporters and bridge
|
|
1535
1753
|
*/
|
|
1536
1754
|
__setLogger(logger) {
|
|
1537
1755
|
super.__setLogger(logger);
|
|
@@ -1540,8 +1758,11 @@ var BaseObservabilityInstance = class extends base.MastraBase {
|
|
|
1540
1758
|
exporter.__setLogger(logger);
|
|
1541
1759
|
}
|
|
1542
1760
|
});
|
|
1761
|
+
if (this.config.bridge?.__setLogger) {
|
|
1762
|
+
this.config.bridge.__setLogger(logger);
|
|
1763
|
+
}
|
|
1543
1764
|
this.logger.debug(
|
|
1544
|
-
`[Observability] Initialized [service=${this.config.serviceName}] [instance=${this.config.name}] [sampling=${this.config.sampling
|
|
1765
|
+
`[Observability] Initialized [service=${this.config.serviceName}] [instance=${this.config.name}] [sampling=${this.config.sampling?.type}] [bridge=${!!this.config.bridge}]`
|
|
1545
1766
|
);
|
|
1546
1767
|
}
|
|
1547
1768
|
// ============================================================================
|
|
@@ -1570,11 +1791,15 @@ var BaseObservabilityInstance = class extends base.MastraBase {
|
|
|
1570
1791
|
} else {
|
|
1571
1792
|
traceState = this.computeTraceState(tracingOptions);
|
|
1572
1793
|
}
|
|
1573
|
-
const
|
|
1794
|
+
const tracingMetadata = !options.parent ? tracingOptions?.metadata : void 0;
|
|
1795
|
+
const mergedMetadata = metadata || tracingMetadata ? { ...metadata, ...tracingMetadata } : void 0;
|
|
1796
|
+
const enrichedMetadata = this.extractMetadataFromRequestContext(requestContext, mergedMetadata, traceState);
|
|
1797
|
+
const tags = !options.parent ? tracingOptions?.tags : void 0;
|
|
1574
1798
|
const span = this.createSpan({
|
|
1575
1799
|
...rest,
|
|
1576
1800
|
metadata: enrichedMetadata,
|
|
1577
|
-
traceState
|
|
1801
|
+
traceState,
|
|
1802
|
+
tags
|
|
1578
1803
|
});
|
|
1579
1804
|
if (span.isEvent) {
|
|
1580
1805
|
this.emitSpanEnded(span);
|
|
@@ -1608,6 +1833,12 @@ var BaseObservabilityInstance = class extends base.MastraBase {
|
|
|
1608
1833
|
getSpanOutputProcessors() {
|
|
1609
1834
|
return [...this.spanOutputProcessors];
|
|
1610
1835
|
}
|
|
1836
|
+
/**
|
|
1837
|
+
* Get the bridge instance if configured
|
|
1838
|
+
*/
|
|
1839
|
+
getBridge() {
|
|
1840
|
+
return this.config.bridge;
|
|
1841
|
+
}
|
|
1611
1842
|
/**
|
|
1612
1843
|
* Get the logger instance (for exporters and other components)
|
|
1613
1844
|
*/
|
|
@@ -1652,7 +1883,9 @@ var BaseObservabilityInstance = class extends base.MastraBase {
|
|
|
1652
1883
|
*/
|
|
1653
1884
|
shouldSample(options) {
|
|
1654
1885
|
const { sampling } = this.config;
|
|
1655
|
-
switch (sampling
|
|
1886
|
+
switch (sampling?.type) {
|
|
1887
|
+
case void 0:
|
|
1888
|
+
return true;
|
|
1656
1889
|
case "always" /* ALWAYS */:
|
|
1657
1890
|
return true;
|
|
1658
1891
|
case "never" /* NEVER */:
|
|
@@ -1784,17 +2017,21 @@ var BaseObservabilityInstance = class extends base.MastraBase {
|
|
|
1784
2017
|
}
|
|
1785
2018
|
}
|
|
1786
2019
|
/**
|
|
1787
|
-
* Export tracing event through all exporters (realtime mode)
|
|
2020
|
+
* Export tracing event through all exporters and bridge (realtime mode)
|
|
1788
2021
|
*/
|
|
1789
2022
|
async exportTracingEvent(event) {
|
|
1790
|
-
const
|
|
2023
|
+
const targets = [
|
|
2024
|
+
...this.exporters
|
|
2025
|
+
];
|
|
2026
|
+
if (this.config.bridge) {
|
|
2027
|
+
targets.push(this.config.bridge);
|
|
2028
|
+
}
|
|
2029
|
+
const exportPromises = targets.map(async (target) => {
|
|
1791
2030
|
try {
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
this.logger.debug(`[Observability] Event exported [exporter=${exporter.name}] [type=${event.type}]`);
|
|
1795
|
-
}
|
|
2031
|
+
await target.exportTracingEvent(event);
|
|
2032
|
+
this.logger.debug(`[Observability] Event exported [target=${target.name}] [type=${event.type}]`);
|
|
1796
2033
|
} catch (error) {
|
|
1797
|
-
this.logger.error(`[Observability] Export error [
|
|
2034
|
+
this.logger.error(`[Observability] Export error [target=${target.name}]`, error);
|
|
1798
2035
|
}
|
|
1799
2036
|
});
|
|
1800
2037
|
await Promise.allSettled(exportPromises);
|
|
@@ -1818,6 +2055,9 @@ var BaseObservabilityInstance = class extends base.MastraBase {
|
|
|
1818
2055
|
...this.exporters.map((e) => e.shutdown()),
|
|
1819
2056
|
...this.spanOutputProcessors.map((p) => p.shutdown())
|
|
1820
2057
|
];
|
|
2058
|
+
if (this.config.bridge) {
|
|
2059
|
+
shutdownPromises.push(this.config.bridge.shutdown());
|
|
2060
|
+
}
|
|
1821
2061
|
await Promise.allSettled(shutdownPromises);
|
|
1822
2062
|
this.logger.info(`[Observability] Shutdown completed [name=${this.name}]`);
|
|
1823
2063
|
}
|
|
@@ -1964,9 +2204,16 @@ var SensitiveDataFilter = class {
|
|
|
1964
2204
|
/**
|
|
1965
2205
|
* Recursively filter objects/arrays for sensitive keys.
|
|
1966
2206
|
* Handles circular references by replacing with a marker.
|
|
2207
|
+
* Also attempts to parse and redact JSON strings.
|
|
1967
2208
|
*/
|
|
1968
2209
|
deepFilter(obj, seen = /* @__PURE__ */ new WeakSet()) {
|
|
1969
2210
|
if (obj === null || typeof obj !== "object") {
|
|
2211
|
+
if (typeof obj === "string") {
|
|
2212
|
+
const trimmed = obj.trim();
|
|
2213
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
2214
|
+
return this.redactJsonString(obj);
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
1970
2217
|
return obj;
|
|
1971
2218
|
}
|
|
1972
2219
|
if (seen.has(obj)) {
|
|
@@ -2019,6 +2266,22 @@ var SensitiveDataFilter = class {
|
|
|
2019
2266
|
return normalizedKey === sensitiveField;
|
|
2020
2267
|
});
|
|
2021
2268
|
}
|
|
2269
|
+
/**
|
|
2270
|
+
* Attempt to parse a string as JSON and redact sensitive fields within it.
|
|
2271
|
+
* If parsing fails or no sensitive data is found, returns the original string.
|
|
2272
|
+
*/
|
|
2273
|
+
redactJsonString(str) {
|
|
2274
|
+
try {
|
|
2275
|
+
const parsed = JSON.parse(str);
|
|
2276
|
+
if (parsed && typeof parsed === "object") {
|
|
2277
|
+
const filtered = this.deepFilter(parsed, /* @__PURE__ */ new WeakSet());
|
|
2278
|
+
return JSON.stringify(filtered);
|
|
2279
|
+
}
|
|
2280
|
+
return str;
|
|
2281
|
+
} catch {
|
|
2282
|
+
return str;
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2022
2285
|
/**
|
|
2023
2286
|
* Redact a sensitive value.
|
|
2024
2287
|
* - Full style: replaces with a fixed token.
|
|
@@ -2171,6 +2434,11 @@ var Observability = class extends base.MastraBase {
|
|
|
2171
2434
|
}
|
|
2172
2435
|
};
|
|
2173
2436
|
|
|
2437
|
+
// src/tracing-options.ts
|
|
2438
|
+
function buildTracingOptions(...updaters) {
|
|
2439
|
+
return updaters.reduce((opts, updater) => updater(opts), {});
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2174
2442
|
exports.BaseExporter = BaseExporter;
|
|
2175
2443
|
exports.BaseObservabilityInstance = BaseObservabilityInstance;
|
|
2176
2444
|
exports.BaseSpan = BaseSpan;
|
|
@@ -2184,7 +2452,10 @@ exports.NoOpSpan = NoOpSpan;
|
|
|
2184
2452
|
exports.Observability = Observability;
|
|
2185
2453
|
exports.SamplingStrategyType = SamplingStrategyType;
|
|
2186
2454
|
exports.SensitiveDataFilter = SensitiveDataFilter;
|
|
2455
|
+
exports.TestExporter = TestExporter;
|
|
2456
|
+
exports.buildTracingOptions = buildTracingOptions;
|
|
2187
2457
|
exports.deepClean = deepClean;
|
|
2458
|
+
exports.getExternalParentId = getExternalParentId;
|
|
2188
2459
|
exports.observabilityConfigValueSchema = observabilityConfigValueSchema;
|
|
2189
2460
|
exports.observabilityInstanceConfigSchema = observabilityInstanceConfigSchema;
|
|
2190
2461
|
exports.observabilityRegistryConfigSchema = observabilityRegistryConfigSchema;
|