@frontmcp/observability 1.9.1 → 1.9.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/esm/index.mjs +396 -219
- package/esm/package.json +3 -3
- package/index.js +466 -290
- package/otel/otel.types.d.ts +1 -1
- package/package.json +3 -3
- package/plugin/observability.hooks.d.ts +28 -0
- package/plugin/observability.plugin.d.ts +10 -2
- package/process-stats/process-stats.collector.d.ts +1 -1
- package/request-log/request-log.collector.d.ts +4 -0
- package/request-log/request-log.hooks.d.ts +35 -0
- package/request-log/request-log.types.d.ts +1 -1
- package/telemetry/telemetry.context-extension.d.ts +3 -3
package/index.js
CHANGED
|
@@ -399,8 +399,8 @@ __export(index_exports, {
|
|
|
399
399
|
module.exports = __toCommonJS(index_exports);
|
|
400
400
|
|
|
401
401
|
// libs/observability/src/plugin/observability.plugin.ts
|
|
402
|
-
var
|
|
403
|
-
var
|
|
402
|
+
var import_api17 = require("@opentelemetry/api");
|
|
403
|
+
var import_sdk4 = require("@frontmcp/sdk");
|
|
404
404
|
|
|
405
405
|
// libs/observability/src/logging/sinks/stdout.sink.ts
|
|
406
406
|
function defaultStream() {
|
|
@@ -763,6 +763,13 @@ var RequestLogCollector = class {
|
|
|
763
763
|
this.status = status;
|
|
764
764
|
this.statusCode = statusCode;
|
|
765
765
|
}
|
|
766
|
+
/**
|
|
767
|
+
* Set the HTTP status the request was answered with; one of 400 or more marks it failed.
|
|
768
|
+
*/
|
|
769
|
+
setStatusCode(statusCode) {
|
|
770
|
+
this.statusCode = statusCode;
|
|
771
|
+
if (statusCode >= 400) this.status = "error";
|
|
772
|
+
}
|
|
766
773
|
/**
|
|
767
774
|
* Set error details.
|
|
768
775
|
*/
|
|
@@ -831,11 +838,13 @@ var RequestLogCollector = class {
|
|
|
831
838
|
}
|
|
832
839
|
};
|
|
833
840
|
|
|
834
|
-
// libs/observability/src/request-log/request-log.
|
|
835
|
-
var
|
|
841
|
+
// libs/observability/src/request-log/request-log.hooks.ts
|
|
842
|
+
var import_sdk3 = require("@frontmcp/sdk");
|
|
836
843
|
|
|
837
|
-
// libs/observability/src/
|
|
838
|
-
var
|
|
844
|
+
// libs/observability/src/plugin/observability.hooks.ts
|
|
845
|
+
var import_api13 = require("@opentelemetry/api");
|
|
846
|
+
var import_sdk2 = require("@frontmcp/sdk");
|
|
847
|
+
var import_utils = require("@frontmcp/utils");
|
|
839
848
|
|
|
840
849
|
// libs/observability/src/otel/otel.types.ts
|
|
841
850
|
var McpAttributes = {
|
|
@@ -950,60 +959,31 @@ var EnduserAttributes = {
|
|
|
950
959
|
SCOPE: "enduser.scope"
|
|
951
960
|
};
|
|
952
961
|
|
|
953
|
-
// libs/observability/src/otel/trace-context-bridge.ts
|
|
954
|
-
var import_api = require("@opentelemetry/api");
|
|
955
|
-
function frontmcpToOTelSpanContext(tc) {
|
|
956
|
-
return {
|
|
957
|
-
traceId: tc.traceId,
|
|
958
|
-
spanId: tc.parentId,
|
|
959
|
-
traceFlags: tc.traceFlags & import_api.TraceFlags.SAMPLED ? import_api.TraceFlags.SAMPLED : import_api.TraceFlags.NONE,
|
|
960
|
-
isRemote: true
|
|
961
|
-
};
|
|
962
|
-
}
|
|
963
|
-
function otelToFrontmcpContext(sc) {
|
|
964
|
-
const flags = sc.traceFlags.toString(16).padStart(2, "0");
|
|
965
|
-
return {
|
|
966
|
-
traceId: sc.traceId,
|
|
967
|
-
parentId: sc.spanId,
|
|
968
|
-
traceFlags: sc.traceFlags,
|
|
969
|
-
raw: `00-${sc.traceId}-${sc.spanId}-${flags}`
|
|
970
|
-
};
|
|
971
|
-
}
|
|
972
|
-
function createOTelContextFromTrace(tc) {
|
|
973
|
-
const spanContext = frontmcpToOTelSpanContext(tc);
|
|
974
|
-
const span = import_api.trace.wrapSpanContext(spanContext);
|
|
975
|
-
return import_api.trace.setSpan(import_api.context.active(), span);
|
|
976
|
-
}
|
|
977
|
-
|
|
978
|
-
// libs/observability/src/plugin/observability.hooks.ts
|
|
979
|
-
var import_api12 = require("@opentelemetry/api");
|
|
980
|
-
var import_utils = require("@frontmcp/utils");
|
|
981
|
-
|
|
982
962
|
// libs/observability/src/otel/spans/auth.span.ts
|
|
983
|
-
var
|
|
963
|
+
var import_api2 = require("@opentelemetry/api");
|
|
984
964
|
|
|
985
965
|
// libs/observability/src/otel/spans/span.utils.ts
|
|
986
|
-
var
|
|
966
|
+
var import_api = require("@opentelemetry/api");
|
|
987
967
|
function startSpan(tracer, options) {
|
|
988
|
-
const parentCtx = options.parentContext ??
|
|
968
|
+
const parentCtx = options.parentContext ?? import_api.context.active();
|
|
989
969
|
const span = tracer.startSpan(
|
|
990
970
|
options.name,
|
|
991
971
|
{
|
|
992
|
-
kind: options.kind ??
|
|
972
|
+
kind: options.kind ?? import_api.SpanKind.INTERNAL,
|
|
993
973
|
attributes: options.attributes
|
|
994
974
|
},
|
|
995
975
|
parentCtx
|
|
996
976
|
);
|
|
997
|
-
const spanContext =
|
|
977
|
+
const spanContext = import_api.trace.setSpan(parentCtx, span);
|
|
998
978
|
return { span, context: spanContext };
|
|
999
979
|
}
|
|
1000
980
|
function endSpanOk(span) {
|
|
1001
|
-
span.setStatus({ code:
|
|
981
|
+
span.setStatus({ code: import_api.SpanStatusCode.OK });
|
|
1002
982
|
span.end();
|
|
1003
983
|
}
|
|
1004
984
|
function endSpanError(span, error) {
|
|
1005
985
|
const message = typeof error === "string" ? error : error.message;
|
|
1006
|
-
span.setStatus({ code:
|
|
986
|
+
span.setStatus({ code: import_api.SpanStatusCode.ERROR, message });
|
|
1007
987
|
if (error instanceof Error) {
|
|
1008
988
|
span.recordException(error);
|
|
1009
989
|
}
|
|
@@ -1011,7 +991,7 @@ function endSpanError(span, error) {
|
|
|
1011
991
|
}
|
|
1012
992
|
async function withSpan(tracer, options, fn) {
|
|
1013
993
|
const { span, context: spanContext } = startSpan(tracer, options);
|
|
1014
|
-
return
|
|
994
|
+
return import_api.context.with(spanContext, async () => {
|
|
1015
995
|
try {
|
|
1016
996
|
const result = await fn(span);
|
|
1017
997
|
endSpanOk(span);
|
|
@@ -1027,7 +1007,7 @@ async function withSpan(tracer, options, fn) {
|
|
|
1027
1007
|
function startAuthSpan(tracer, options) {
|
|
1028
1008
|
return startSpan(tracer, {
|
|
1029
1009
|
name: `auth ${options.flowName}`,
|
|
1030
|
-
kind:
|
|
1010
|
+
kind: import_api2.SpanKind.INTERNAL,
|
|
1031
1011
|
attributes: {
|
|
1032
1012
|
[FrontMcpAttributes.FLOW_NAME]: options.flowName
|
|
1033
1013
|
},
|
|
@@ -1042,11 +1022,11 @@ function setAuthResult(span, result) {
|
|
|
1042
1022
|
}
|
|
1043
1023
|
|
|
1044
1024
|
// libs/observability/src/otel/spans/fetch.span.ts
|
|
1045
|
-
var
|
|
1025
|
+
var import_api3 = require("@opentelemetry/api");
|
|
1046
1026
|
function startFetchSpan(tracer, options) {
|
|
1047
1027
|
return startSpan(tracer, {
|
|
1048
1028
|
name: options.method.toUpperCase(),
|
|
1049
|
-
kind:
|
|
1029
|
+
kind: import_api3.SpanKind.CLIENT,
|
|
1050
1030
|
attributes: {
|
|
1051
1031
|
[HttpAttributes.METHOD]: options.method.toUpperCase(),
|
|
1052
1032
|
[HttpAttributes.URL_FULL]: options.url
|
|
@@ -1058,6 +1038,33 @@ function setFetchResponseStatus(span, statusCode) {
|
|
|
1058
1038
|
span.setAttribute(HttpAttributes.STATUS_CODE, statusCode);
|
|
1059
1039
|
}
|
|
1060
1040
|
|
|
1041
|
+
// libs/observability/src/otel/spans/hook.span.ts
|
|
1042
|
+
var import_api4 = require("@opentelemetry/api");
|
|
1043
|
+
function recordHookEvent(parentSpan, stage, owner) {
|
|
1044
|
+
const attributes = {};
|
|
1045
|
+
if (owner) {
|
|
1046
|
+
attributes[FrontMcpAttributes.HOOK_OWNER] = owner;
|
|
1047
|
+
}
|
|
1048
|
+
parentSpan.addEvent(`hook.${stage}`, attributes);
|
|
1049
|
+
}
|
|
1050
|
+
function startHookSpan(tracer, options) {
|
|
1051
|
+
const attributes = {
|
|
1052
|
+
[FrontMcpAttributes.HOOK_STAGE]: options.stage
|
|
1053
|
+
};
|
|
1054
|
+
if (options.owner) {
|
|
1055
|
+
attributes[FrontMcpAttributes.HOOK_OWNER] = options.owner;
|
|
1056
|
+
}
|
|
1057
|
+
if (options.flowName) {
|
|
1058
|
+
attributes[FrontMcpAttributes.FLOW_NAME] = options.flowName;
|
|
1059
|
+
}
|
|
1060
|
+
return startSpan(tracer, {
|
|
1061
|
+
name: `hook ${options.stage}`,
|
|
1062
|
+
kind: import_api4.SpanKind.INTERNAL,
|
|
1063
|
+
attributes,
|
|
1064
|
+
parentContext: options.parentContext
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1061
1068
|
// libs/observability/src/otel/spans/http-server.span.ts
|
|
1062
1069
|
var import_api5 = require("@opentelemetry/api");
|
|
1063
1070
|
function startHttpServerSpan(tracer, options) {
|
|
@@ -1226,6 +1233,31 @@ function setTransportRequestType(span, requestType) {
|
|
|
1226
1233
|
span.setAttribute(FrontMcpAttributes.TRANSPORT_REQUEST_TYPE, requestType);
|
|
1227
1234
|
}
|
|
1228
1235
|
|
|
1236
|
+
// libs/observability/src/otel/trace-context-bridge.ts
|
|
1237
|
+
var import_api12 = require("@opentelemetry/api");
|
|
1238
|
+
function frontmcpToOTelSpanContext(tc) {
|
|
1239
|
+
return {
|
|
1240
|
+
traceId: tc.traceId,
|
|
1241
|
+
spanId: tc.parentId,
|
|
1242
|
+
traceFlags: tc.traceFlags & import_api12.TraceFlags.SAMPLED ? import_api12.TraceFlags.SAMPLED : import_api12.TraceFlags.NONE,
|
|
1243
|
+
isRemote: true
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
function otelToFrontmcpContext(sc) {
|
|
1247
|
+
const flags = sc.traceFlags.toString(16).padStart(2, "0");
|
|
1248
|
+
return {
|
|
1249
|
+
traceId: sc.traceId,
|
|
1250
|
+
parentId: sc.spanId,
|
|
1251
|
+
traceFlags: sc.traceFlags,
|
|
1252
|
+
raw: `00-${sc.traceId}-${sc.spanId}-${flags}`
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
function createOTelContextFromTrace(tc) {
|
|
1256
|
+
const spanContext = frontmcpToOTelSpanContext(tc);
|
|
1257
|
+
const span = import_api12.trace.wrapSpanContext(spanContext);
|
|
1258
|
+
return import_api12.trace.setSpan(import_api12.context.active(), span);
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1229
1261
|
// libs/observability/src/plugin/observability.hooks.ts
|
|
1230
1262
|
var SPAN_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:span");
|
|
1231
1263
|
var SPAN_CTX_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:span-ctx");
|
|
@@ -1233,11 +1265,13 @@ var EXEC_SPAN_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:exec-span");
|
|
|
1233
1265
|
var ACTIVE_SPAN_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:active-span");
|
|
1234
1266
|
var ACTIVE_OTEL_CTX_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:active-otel-ctx");
|
|
1235
1267
|
var STAGE_TS_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:stage-ts");
|
|
1268
|
+
var STAGE_EVENTS_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:stage-events");
|
|
1269
|
+
var HTTP_SPAN_CTX_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:http-span-ctx");
|
|
1236
1270
|
function sessionTracingId(sessionId) {
|
|
1237
1271
|
return (0, import_utils.sha256Hex)(sessionId).slice(0, 16);
|
|
1238
1272
|
}
|
|
1239
1273
|
function getTracer() {
|
|
1240
|
-
return
|
|
1274
|
+
return import_api13.trace.getTracer("@frontmcp/observability");
|
|
1241
1275
|
}
|
|
1242
1276
|
function extractContext(flowCtx) {
|
|
1243
1277
|
try {
|
|
@@ -1267,7 +1301,44 @@ function clearActiveSpan(flowCtx) {
|
|
|
1267
1301
|
} catch {
|
|
1268
1302
|
}
|
|
1269
1303
|
}
|
|
1304
|
+
function beginFlowSpan(flowCtx, options, span, spanCtx) {
|
|
1305
|
+
flowCtx.state[SPAN_KEY] = span;
|
|
1306
|
+
flowCtx.state[SPAN_CTX_KEY] = spanCtx;
|
|
1307
|
+
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1308
|
+
flowCtx.state[STAGE_EVENTS_KEY] = options.flowStageEvents !== false;
|
|
1309
|
+
}
|
|
1310
|
+
function parentContextOf(ctx) {
|
|
1311
|
+
return ctx.get?.(HTTP_SPAN_CTX_KEY) ?? createOTelContextFromTrace(ctx.traceContext);
|
|
1312
|
+
}
|
|
1313
|
+
function flowFailureOf(flowError) {
|
|
1314
|
+
const failed = flowError?.originalError;
|
|
1315
|
+
const error = flowError instanceof import_sdk2.FlowControl ? failed instanceof Error ? failed : new import_sdk2.InternalMcpError(`Flow ended with: ${flowError.type}`) : flowError instanceof Error ? flowError : new Error(String(flowError));
|
|
1316
|
+
const reported = (0, import_sdk2.toMcpError)(error);
|
|
1317
|
+
return {
|
|
1318
|
+
error,
|
|
1319
|
+
type: reported.name,
|
|
1320
|
+
message: reported.getPublicMessage(),
|
|
1321
|
+
code: reported.code,
|
|
1322
|
+
errorId: reported.errorId
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
function endFailedSpan(span, flowError) {
|
|
1326
|
+
const failure = flowFailureOf(flowError);
|
|
1327
|
+
span.setStatus({ code: import_api13.SpanStatusCode.ERROR, message: failure.message });
|
|
1328
|
+
span.recordException({
|
|
1329
|
+
name: failure.type,
|
|
1330
|
+
message: failure.message,
|
|
1331
|
+
code: failure.code,
|
|
1332
|
+
stack: failure.error.stack
|
|
1333
|
+
});
|
|
1334
|
+
span.end();
|
|
1335
|
+
}
|
|
1336
|
+
function traceparentOf(span) {
|
|
1337
|
+
const { traceId, spanId, traceFlags } = span.spanContext();
|
|
1338
|
+
return `00-${traceId}-${spanId}-${traceFlags.toString(16).padStart(2, "0")}`;
|
|
1339
|
+
}
|
|
1270
1340
|
function recordStageEvent(span, stageName, state) {
|
|
1341
|
+
if (state[STAGE_EVENTS_KEY] === false) return;
|
|
1271
1342
|
const now = Date.now();
|
|
1272
1343
|
const prev = state[STAGE_TS_KEY];
|
|
1273
1344
|
const attributes = {};
|
|
@@ -1293,9 +1364,8 @@ function onHttpWillTrace(options, flowCtx) {
|
|
|
1293
1364
|
});
|
|
1294
1365
|
span.setAttribute(McpAttributes.SESSION_ID, sessionHash);
|
|
1295
1366
|
span.setAttribute(FrontMcpAttributes.SESSION_ID_HASH, sessionHash);
|
|
1296
|
-
|
|
1297
|
-
flowCtx
|
|
1298
|
-
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1367
|
+
ctx.set?.(HTTP_SPAN_CTX_KEY, spanCtx);
|
|
1368
|
+
beginFlowSpan(flowCtx, options, span, spanCtx);
|
|
1299
1369
|
recordStageEvent(span, "traceRequest", flowCtx.state);
|
|
1300
1370
|
}
|
|
1301
1371
|
function onHttpWillAcquireQuota(flowCtx) {
|
|
@@ -1339,7 +1409,7 @@ function onToolWillParse(options, flowCtx) {
|
|
|
1339
1409
|
const ctx = extractContext(flowCtx);
|
|
1340
1410
|
if (!ctx) return;
|
|
1341
1411
|
const tracer = getTracer();
|
|
1342
|
-
const parentOTelCtx =
|
|
1412
|
+
const parentOTelCtx = parentContextOf(ctx);
|
|
1343
1413
|
const sessionHash = sessionTracingId(ctx.sessionId);
|
|
1344
1414
|
const { span, context: spanCtx } = startRpcSpan(tracer, {
|
|
1345
1415
|
method: "tools/call",
|
|
@@ -1347,9 +1417,7 @@ function onToolWillParse(options, flowCtx) {
|
|
|
1347
1417
|
sessionIdHash: sessionHash,
|
|
1348
1418
|
parentContext: parentOTelCtx
|
|
1349
1419
|
});
|
|
1350
|
-
flowCtx
|
|
1351
|
-
flowCtx.state[SPAN_CTX_KEY] = spanCtx;
|
|
1352
|
-
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1420
|
+
beginFlowSpan(flowCtx, options, span, spanCtx);
|
|
1353
1421
|
recordStageEvent(span, "parseInput", flowCtx.state);
|
|
1354
1422
|
}
|
|
1355
1423
|
function onToolWillFindTool(flowCtx) {
|
|
@@ -1417,10 +1485,10 @@ function onToolWillApplyUI(flowCtx) {
|
|
|
1417
1485
|
function onToolDidFinalize(flowCtx) {
|
|
1418
1486
|
const rpcSpan = flowCtx.state?.[SPAN_KEY];
|
|
1419
1487
|
const toolSpan = flowCtx.state?.[EXEC_SPAN_KEY];
|
|
1420
|
-
const error = flowCtx.state?.
|
|
1488
|
+
const error = flowCtx.state?.flowError;
|
|
1421
1489
|
if (error) {
|
|
1422
|
-
if (toolSpan)
|
|
1423
|
-
if (rpcSpan)
|
|
1490
|
+
if (toolSpan) endFailedSpan(toolSpan, error);
|
|
1491
|
+
if (rpcSpan) endFailedSpan(rpcSpan, error);
|
|
1424
1492
|
} else if (rpcSpan) {
|
|
1425
1493
|
recordStageEvent(rpcSpan, "finalize", flowCtx.state);
|
|
1426
1494
|
endSpanOk(rpcSpan);
|
|
@@ -1431,7 +1499,7 @@ function onResourceWillParse(options, flowCtx) {
|
|
|
1431
1499
|
const ctx = extractContext(flowCtx);
|
|
1432
1500
|
if (!ctx) return;
|
|
1433
1501
|
const tracer = getTracer();
|
|
1434
|
-
const parentOTelCtx =
|
|
1502
|
+
const parentOTelCtx = parentContextOf(ctx);
|
|
1435
1503
|
const sessionHash = sessionTracingId(ctx.sessionId);
|
|
1436
1504
|
const { span, context: spanCtx } = startRpcSpan(tracer, {
|
|
1437
1505
|
method: "resources/read",
|
|
@@ -1439,9 +1507,7 @@ function onResourceWillParse(options, flowCtx) {
|
|
|
1439
1507
|
sessionIdHash: sessionHash,
|
|
1440
1508
|
parentContext: parentOTelCtx
|
|
1441
1509
|
});
|
|
1442
|
-
flowCtx
|
|
1443
|
-
flowCtx.state[SPAN_CTX_KEY] = spanCtx;
|
|
1444
|
-
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1510
|
+
beginFlowSpan(flowCtx, options, span, spanCtx);
|
|
1445
1511
|
recordStageEvent(span, "parseInput", flowCtx.state);
|
|
1446
1512
|
}
|
|
1447
1513
|
function onResourceWillFind(flowCtx) {
|
|
@@ -1470,10 +1536,10 @@ function onResourceDidExecute(flowCtx) {
|
|
|
1470
1536
|
function onResourceDidFinalize(flowCtx) {
|
|
1471
1537
|
const rpcSpan = flowCtx.state?.[SPAN_KEY];
|
|
1472
1538
|
const resSpan = flowCtx.state?.[EXEC_SPAN_KEY];
|
|
1473
|
-
const error = flowCtx.state?.
|
|
1539
|
+
const error = flowCtx.state?.flowError;
|
|
1474
1540
|
if (error) {
|
|
1475
|
-
if (resSpan)
|
|
1476
|
-
if (rpcSpan)
|
|
1541
|
+
if (resSpan) endFailedSpan(resSpan, error);
|
|
1542
|
+
if (rpcSpan) endFailedSpan(rpcSpan, error);
|
|
1477
1543
|
} else if (rpcSpan) {
|
|
1478
1544
|
recordStageEvent(rpcSpan, "finalize", flowCtx.state);
|
|
1479
1545
|
endSpanOk(rpcSpan);
|
|
@@ -1484,7 +1550,7 @@ function onPromptWillParse(options, flowCtx) {
|
|
|
1484
1550
|
const ctx = extractContext(flowCtx);
|
|
1485
1551
|
if (!ctx) return;
|
|
1486
1552
|
const tracer = getTracer();
|
|
1487
|
-
const parentOTelCtx =
|
|
1553
|
+
const parentOTelCtx = parentContextOf(ctx);
|
|
1488
1554
|
const sessionHash = sessionTracingId(ctx.sessionId);
|
|
1489
1555
|
const { span, context: spanCtx } = startRpcSpan(tracer, {
|
|
1490
1556
|
method: "prompts/get",
|
|
@@ -1492,9 +1558,7 @@ function onPromptWillParse(options, flowCtx) {
|
|
|
1492
1558
|
sessionIdHash: sessionHash,
|
|
1493
1559
|
parentContext: parentOTelCtx
|
|
1494
1560
|
});
|
|
1495
|
-
flowCtx
|
|
1496
|
-
flowCtx.state[SPAN_CTX_KEY] = spanCtx;
|
|
1497
|
-
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1561
|
+
beginFlowSpan(flowCtx, options, span, spanCtx);
|
|
1498
1562
|
recordStageEvent(span, "parseInput", flowCtx.state);
|
|
1499
1563
|
}
|
|
1500
1564
|
function onPromptWillFind(flowCtx) {
|
|
@@ -1526,10 +1590,10 @@ function onPromptDidExecute(flowCtx) {
|
|
|
1526
1590
|
function onPromptDidFinalize(flowCtx) {
|
|
1527
1591
|
const rpcSpan = flowCtx.state?.[SPAN_KEY];
|
|
1528
1592
|
const promptSpan = flowCtx.state?.[EXEC_SPAN_KEY];
|
|
1529
|
-
const error = flowCtx.state?.
|
|
1593
|
+
const error = flowCtx.state?.flowError;
|
|
1530
1594
|
if (error) {
|
|
1531
|
-
if (promptSpan)
|
|
1532
|
-
if (rpcSpan)
|
|
1595
|
+
if (promptSpan) endFailedSpan(promptSpan, error);
|
|
1596
|
+
if (rpcSpan) endFailedSpan(rpcSpan, error);
|
|
1533
1597
|
} else if (rpcSpan) {
|
|
1534
1598
|
recordStageEvent(rpcSpan, "finalize", flowCtx.state);
|
|
1535
1599
|
endSpanOk(rpcSpan);
|
|
@@ -1540,7 +1604,7 @@ function onAgentWillParse(options, flowCtx) {
|
|
|
1540
1604
|
const ctx = extractContext(flowCtx);
|
|
1541
1605
|
if (!ctx) return;
|
|
1542
1606
|
const tracer = getTracer();
|
|
1543
|
-
const parentOTelCtx =
|
|
1607
|
+
const parentOTelCtx = parentContextOf(ctx);
|
|
1544
1608
|
const sessionHash = sessionTracingId(ctx.sessionId);
|
|
1545
1609
|
const { span, context: spanCtx } = startRpcSpan(tracer, {
|
|
1546
1610
|
method: "agents/call",
|
|
@@ -1548,9 +1612,7 @@ function onAgentWillParse(options, flowCtx) {
|
|
|
1548
1612
|
sessionIdHash: sessionHash,
|
|
1549
1613
|
parentContext: parentOTelCtx
|
|
1550
1614
|
});
|
|
1551
|
-
flowCtx
|
|
1552
|
-
flowCtx.state[SPAN_CTX_KEY] = spanCtx;
|
|
1553
|
-
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1615
|
+
beginFlowSpan(flowCtx, options, span, spanCtx);
|
|
1554
1616
|
recordStageEvent(span, "parseInput", flowCtx.state);
|
|
1555
1617
|
}
|
|
1556
1618
|
function onAgentWillFind(flowCtx) {
|
|
@@ -1564,7 +1626,7 @@ function onAgentWillExecute(options, flowCtx) {
|
|
|
1564
1626
|
const agentName = flowCtx.state?.input?.name ?? "unknown";
|
|
1565
1627
|
const { span: agentSpan } = startSpan(tracer, {
|
|
1566
1628
|
name: `agent ${agentName}`,
|
|
1567
|
-
kind:
|
|
1629
|
+
kind: import_api13.SpanKind.INTERNAL,
|
|
1568
1630
|
attributes: {
|
|
1569
1631
|
[FrontMcpAttributes.FLOW_NAME]: "agents:call-agent",
|
|
1570
1632
|
[McpAttributes.COMPONENT_TYPE]: "agent",
|
|
@@ -1572,7 +1634,7 @@ function onAgentWillExecute(options, flowCtx) {
|
|
|
1572
1634
|
},
|
|
1573
1635
|
parentContext: rpcCtx
|
|
1574
1636
|
});
|
|
1575
|
-
const agentOTelCtx =
|
|
1637
|
+
const agentOTelCtx = import_api13.trace.setSpan(rpcCtx ?? import_api13.context.active(), agentSpan);
|
|
1576
1638
|
flowCtx.state[EXEC_SPAN_KEY] = agentSpan;
|
|
1577
1639
|
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1578
1640
|
recordStageEvent(agentSpan, "execute.start", flowCtx.state);
|
|
@@ -1589,10 +1651,10 @@ function onAgentDidExecute(flowCtx) {
|
|
|
1589
1651
|
function onAgentDidFinalize(flowCtx) {
|
|
1590
1652
|
const rpcSpan = flowCtx.state?.[SPAN_KEY];
|
|
1591
1653
|
const agentSpan = flowCtx.state?.[EXEC_SPAN_KEY];
|
|
1592
|
-
const error = flowCtx.state?.
|
|
1654
|
+
const error = flowCtx.state?.flowError;
|
|
1593
1655
|
if (error) {
|
|
1594
|
-
if (agentSpan)
|
|
1595
|
-
if (rpcSpan)
|
|
1656
|
+
if (agentSpan) endFailedSpan(agentSpan, error);
|
|
1657
|
+
if (rpcSpan) endFailedSpan(rpcSpan, error);
|
|
1596
1658
|
} else if (rpcSpan) {
|
|
1597
1659
|
recordStageEvent(rpcSpan, "finalize", flowCtx.state);
|
|
1598
1660
|
endSpanOk(rpcSpan);
|
|
@@ -1603,11 +1665,11 @@ function onGenericFlowWillStart(flowName, options, flowCtx) {
|
|
|
1603
1665
|
const ctx = extractContext(flowCtx);
|
|
1604
1666
|
if (!ctx) return;
|
|
1605
1667
|
const tracer = getTracer();
|
|
1606
|
-
const parentOTelCtx =
|
|
1668
|
+
const parentOTelCtx = parentContextOf(ctx);
|
|
1607
1669
|
const sessionHash = sessionTracingId(ctx.sessionId);
|
|
1608
1670
|
const { span, context: spanCtx } = startSpan(tracer, {
|
|
1609
1671
|
name: flowName,
|
|
1610
|
-
kind:
|
|
1672
|
+
kind: import_api13.SpanKind.INTERNAL,
|
|
1611
1673
|
attributes: {
|
|
1612
1674
|
[FrontMcpAttributes.FLOW_NAME]: flowName,
|
|
1613
1675
|
[McpAttributes.SESSION_ID]: sessionHash,
|
|
@@ -1617,9 +1679,7 @@ function onGenericFlowWillStart(flowName, options, flowCtx) {
|
|
|
1617
1679
|
},
|
|
1618
1680
|
parentContext: parentOTelCtx
|
|
1619
1681
|
});
|
|
1620
|
-
flowCtx
|
|
1621
|
-
flowCtx.state[SPAN_CTX_KEY] = spanCtx;
|
|
1622
|
-
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1682
|
+
beginFlowSpan(flowCtx, options, span, spanCtx);
|
|
1623
1683
|
}
|
|
1624
1684
|
function onGenericFlowStage(stageName, flowCtx) {
|
|
1625
1685
|
const span = flowCtx.state?.[SPAN_KEY];
|
|
@@ -1628,9 +1688,9 @@ function onGenericFlowStage(stageName, flowCtx) {
|
|
|
1628
1688
|
function onGenericFlowDidFinalize(flowCtx) {
|
|
1629
1689
|
const span = flowCtx.state?.[SPAN_KEY];
|
|
1630
1690
|
if (!span) return;
|
|
1631
|
-
const error = flowCtx.state?.
|
|
1691
|
+
const error = flowCtx.state?.flowError;
|
|
1632
1692
|
if (error) {
|
|
1633
|
-
|
|
1693
|
+
endFailedSpan(span, error);
|
|
1634
1694
|
} else {
|
|
1635
1695
|
endSpanOk(span);
|
|
1636
1696
|
}
|
|
@@ -1640,16 +1700,14 @@ function onTransportWillStart(transportType, options, flowCtx) {
|
|
|
1640
1700
|
const ctx = extractContext(flowCtx);
|
|
1641
1701
|
if (!ctx) return;
|
|
1642
1702
|
const tracer = getTracer();
|
|
1643
|
-
const parentOTelCtx =
|
|
1703
|
+
const parentOTelCtx = parentContextOf(ctx);
|
|
1644
1704
|
const sessionHash = sessionTracingId(ctx.sessionId);
|
|
1645
1705
|
const { span, context: spanCtx } = startTransportSpan(tracer, {
|
|
1646
1706
|
type: transportType,
|
|
1647
1707
|
sessionIdHash: sessionHash,
|
|
1648
1708
|
parentContext: parentOTelCtx
|
|
1649
1709
|
});
|
|
1650
|
-
flowCtx
|
|
1651
|
-
flowCtx.state[SPAN_CTX_KEY] = spanCtx;
|
|
1652
|
-
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1710
|
+
beginFlowSpan(flowCtx, options, span, spanCtx);
|
|
1653
1711
|
recordStageEvent(span, "parseInput", flowCtx.state);
|
|
1654
1712
|
}
|
|
1655
1713
|
function onTransportDidRoute(flowCtx) {
|
|
@@ -1667,9 +1725,9 @@ function onTransportDidFinalize(flowCtx) {
|
|
|
1667
1725
|
const span = flowCtx.state?.[SPAN_KEY];
|
|
1668
1726
|
if (!span) return;
|
|
1669
1727
|
recordStageEvent(span, "cleanup", flowCtx.state);
|
|
1670
|
-
const error = flowCtx.state?.
|
|
1728
|
+
const error = flowCtx.state?.flowError;
|
|
1671
1729
|
if (error) {
|
|
1672
|
-
|
|
1730
|
+
endFailedSpan(span, error);
|
|
1673
1731
|
} else {
|
|
1674
1732
|
endSpanOk(span);
|
|
1675
1733
|
}
|
|
@@ -1679,14 +1737,12 @@ function onAuthWillStart(flowName, options, flowCtx) {
|
|
|
1679
1737
|
const ctx = extractContext(flowCtx);
|
|
1680
1738
|
if (!ctx) return;
|
|
1681
1739
|
const tracer = getTracer();
|
|
1682
|
-
const parentOTelCtx =
|
|
1740
|
+
const parentOTelCtx = parentContextOf(ctx);
|
|
1683
1741
|
const { span, context: spanCtx } = startAuthSpan(tracer, {
|
|
1684
1742
|
flowName,
|
|
1685
1743
|
parentContext: parentOTelCtx
|
|
1686
1744
|
});
|
|
1687
|
-
flowCtx
|
|
1688
|
-
flowCtx.state[SPAN_CTX_KEY] = spanCtx;
|
|
1689
|
-
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1745
|
+
beginFlowSpan(flowCtx, options, span, spanCtx);
|
|
1690
1746
|
recordStageEvent(span, "parseInput", flowCtx.state);
|
|
1691
1747
|
}
|
|
1692
1748
|
function onAuthDidDetermineMode(flowCtx) {
|
|
@@ -1703,33 +1759,38 @@ function onAuthStage(stageName, flowCtx) {
|
|
|
1703
1759
|
function onAuthDidFinalize(flowCtx) {
|
|
1704
1760
|
const span = flowCtx.state?.[SPAN_KEY];
|
|
1705
1761
|
if (!span) return;
|
|
1706
|
-
const error = flowCtx.state?.
|
|
1762
|
+
const error = flowCtx.state?.flowError;
|
|
1707
1763
|
if (error) {
|
|
1708
1764
|
setAuthResult(span, "unauthorized");
|
|
1709
|
-
|
|
1765
|
+
endFailedSpan(span, error);
|
|
1710
1766
|
} else {
|
|
1711
1767
|
setAuthResult(span, "authorized");
|
|
1712
1768
|
endSpanOk(span);
|
|
1713
1769
|
}
|
|
1714
1770
|
}
|
|
1715
1771
|
function wrapContextFetch(options, flowCtx) {
|
|
1716
|
-
if (options.fetchSpans === false) return;
|
|
1717
1772
|
const toolCtx = flowCtx.state?.toolContext ?? flowCtx.state?.toolCallContext;
|
|
1718
1773
|
if (!toolCtx || typeof toolCtx.fetch !== "function") return;
|
|
1719
1774
|
const originalFetch = toolCtx.fetch.bind(toolCtx);
|
|
1720
1775
|
const parentOTelCtx = flowCtx.state?.[SPAN_CTX_KEY];
|
|
1721
1776
|
toolCtx.fetch = async (input, init) => {
|
|
1722
|
-
const
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1777
|
+
const fetchSpan = options.fetchSpans === false ? void 0 : startFetchSpan(getTracer(), {
|
|
1778
|
+
method: init?.method ?? (input instanceof Request ? input.method : "GET"),
|
|
1779
|
+
url: typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url,
|
|
1780
|
+
parentContext: parentOTelCtx
|
|
1781
|
+
}).span;
|
|
1782
|
+
const callingSpan = fetchSpan ?? flowCtx.state?.[EXEC_SPAN_KEY] ?? flowCtx.state?.[SPAN_KEY];
|
|
1783
|
+
const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : void 0));
|
|
1784
|
+
if (callingSpan && !headers.has("traceparent")) headers.set("traceparent", traceparentOf(callingSpan));
|
|
1726
1785
|
try {
|
|
1727
|
-
const response = await originalFetch(input, init);
|
|
1728
|
-
|
|
1729
|
-
|
|
1786
|
+
const response = await originalFetch(input, { ...init, headers });
|
|
1787
|
+
if (fetchSpan) {
|
|
1788
|
+
setFetchResponseStatus(fetchSpan, response.status);
|
|
1789
|
+
endSpanOk(fetchSpan);
|
|
1790
|
+
}
|
|
1730
1791
|
return response;
|
|
1731
1792
|
} catch (err) {
|
|
1732
|
-
endSpanError(
|
|
1793
|
+
if (fetchSpan) endSpanError(fetchSpan, err instanceof Error ? err : String(err));
|
|
1733
1794
|
throw err;
|
|
1734
1795
|
}
|
|
1735
1796
|
};
|
|
@@ -1747,13 +1808,94 @@ function onAgentDidExecuteEnrich(flowCtx) {
|
|
|
1747
1808
|
}
|
|
1748
1809
|
}
|
|
1749
1810
|
}
|
|
1811
|
+
var HOOK_OBSERVER_KEY = /* @__PURE__ */ Symbol.for("frontmcp:hook-observer");
|
|
1812
|
+
function installHookObserver(flowCtx, observer) {
|
|
1813
|
+
const ctx = extractContext(flowCtx);
|
|
1814
|
+
if (ctx && !ctx.get?.(HOOK_OBSERVER_KEY)) ctx.set?.(HOOK_OBSERVER_KEY, observer);
|
|
1815
|
+
}
|
|
1816
|
+
async function runInHookSpan(flowCtx, hook, run) {
|
|
1817
|
+
const ctx = extractContext(flowCtx);
|
|
1818
|
+
const { span } = startHookSpan(getTracer(), {
|
|
1819
|
+
...hook,
|
|
1820
|
+
parentContext: flowCtx.state?.[SPAN_CTX_KEY] ?? (ctx && parentContextOf(ctx))
|
|
1821
|
+
});
|
|
1822
|
+
try {
|
|
1823
|
+
await run();
|
|
1824
|
+
endSpanOk(span);
|
|
1825
|
+
} catch (error) {
|
|
1826
|
+
if (error instanceof import_sdk2.FlowControl && error.type !== "fail" && error.type !== "abort") endSpanOk(span);
|
|
1827
|
+
else endFailedSpan(span, error);
|
|
1828
|
+
throw error;
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1750
1831
|
function reportStartup(data) {
|
|
1751
1832
|
const tracer = getTracer();
|
|
1752
1833
|
emitStartupReport(tracer, data);
|
|
1753
1834
|
}
|
|
1754
1835
|
|
|
1836
|
+
// libs/observability/src/request-log/request-log.tokens.ts
|
|
1837
|
+
var REQUEST_LOG_COLLECTOR = /* @__PURE__ */ Symbol.for("frontmcp:observability:request-log-collector");
|
|
1838
|
+
|
|
1839
|
+
// libs/observability/src/request-log/request-log.hooks.ts
|
|
1840
|
+
var FRONTMCP_CONTEXT = /* @__PURE__ */ Symbol.for("frontmcp:CONTEXT");
|
|
1841
|
+
function resolve(flowCtx, token) {
|
|
1842
|
+
try {
|
|
1843
|
+
return flowCtx.get?.(token);
|
|
1844
|
+
} catch {
|
|
1845
|
+
return void 0;
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
function currentRequestLog(flowCtx) {
|
|
1849
|
+
return resolve(flowCtx, FRONTMCP_CONTEXT)?.get(REQUEST_LOG_COLLECTOR);
|
|
1850
|
+
}
|
|
1851
|
+
function startRequestLog(flowCtx, options) {
|
|
1852
|
+
const context = resolve(flowCtx, FRONTMCP_CONTEXT);
|
|
1853
|
+
if (!context) return;
|
|
1854
|
+
const collector = new RequestLogCollector(
|
|
1855
|
+
{
|
|
1856
|
+
requestId: context.requestId,
|
|
1857
|
+
traceId: context.traceContext.traceId,
|
|
1858
|
+
sessionIdHash: sessionTracingId(context.sessionId).slice(0, 12),
|
|
1859
|
+
scopeId: context.scopeId
|
|
1860
|
+
},
|
|
1861
|
+
options
|
|
1862
|
+
);
|
|
1863
|
+
context.set(REQUEST_LOG_COLLECTOR, collector);
|
|
1864
|
+
const request = flowCtx.rawInput?.request;
|
|
1865
|
+
if (request?.method && request.path) collector.setHttpInfo(request.method, request.path);
|
|
1866
|
+
const rpcMethod = request?.body?.method;
|
|
1867
|
+
if (typeof rpcMethod === "string") collector.setRpcMethod(rpcMethod);
|
|
1868
|
+
}
|
|
1869
|
+
function recordRequestLogFailure(flowCtx) {
|
|
1870
|
+
const flowError = flowCtx.state?.["flowError"];
|
|
1871
|
+
if (!flowError) return;
|
|
1872
|
+
const { type, message, code, errorId } = flowFailureOf(flowError);
|
|
1873
|
+
currentRequestLog(flowCtx)?.setError({ type, message, code, error_id: errorId });
|
|
1874
|
+
}
|
|
1875
|
+
function recordRequestLogAuth(flowCtx) {
|
|
1876
|
+
const verifyResult = flowCtx.state?.["verifyResult"];
|
|
1877
|
+
const authorization = flowCtx.rawInput?.request?.headers?.["authorization"];
|
|
1878
|
+
const scheme = typeof authorization === "string" ? authorization.trim().split(/\s+/)[0].toLowerCase() : "";
|
|
1879
|
+
const sub = verifyResult?.authorization?.user?.sub;
|
|
1880
|
+
const anonymous = typeof sub !== "string" || (0, import_sdk3.isAnonymousSubject)(sub);
|
|
1881
|
+
currentRequestLog(flowCtx)?.setAuthInfo(
|
|
1882
|
+
anonymous || !scheme ? "anonymous" : scheme,
|
|
1883
|
+
verifyResult?.kind === "authorized" && !anonymous
|
|
1884
|
+
);
|
|
1885
|
+
}
|
|
1886
|
+
async function completeRequestLog(flowCtx) {
|
|
1887
|
+
const collector = currentRequestLog(flowCtx);
|
|
1888
|
+
if (!collector || collector.isFinalized()) return;
|
|
1889
|
+
const statusCode = flowCtx.state?.["statusCode"] ?? flowCtx.rawInput?.response?.statusCode;
|
|
1890
|
+
if (typeof statusCode === "number") collector.setStatusCode(statusCode);
|
|
1891
|
+
await collector.finalize();
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
// libs/observability/src/telemetry/telemetry.accessor.ts
|
|
1895
|
+
var import_api15 = require("@opentelemetry/api");
|
|
1896
|
+
|
|
1755
1897
|
// libs/observability/src/telemetry/telemetry.counters.ts
|
|
1756
|
-
var
|
|
1898
|
+
var import_api14 = require("@opentelemetry/api");
|
|
1757
1899
|
function snapshotKey(name, attributes) {
|
|
1758
1900
|
const keys = Object.keys(attributes).sort();
|
|
1759
1901
|
if (keys.length === 0) return name;
|
|
@@ -1788,7 +1930,7 @@ var counterCache = /* @__PURE__ */ new Map();
|
|
|
1788
1930
|
function createCounter(name, description) {
|
|
1789
1931
|
const existing = counterCache.get(name);
|
|
1790
1932
|
if (existing) return existing;
|
|
1791
|
-
const meter =
|
|
1933
|
+
const meter = import_api14.metrics.getMeter(METER_NAME);
|
|
1792
1934
|
const otelCounter = meter.createCounter(name, description ? { description } : void 0);
|
|
1793
1935
|
const counter = new TelemetryCounterImpl(name, otelCounter);
|
|
1794
1936
|
counterCache.set(name, counter);
|
|
@@ -1867,14 +2009,14 @@ var TelemetrySpan = class {
|
|
|
1867
2009
|
/** Record an error on this span */
|
|
1868
2010
|
recordError(error) {
|
|
1869
2011
|
this.span.recordException(error);
|
|
1870
|
-
this.span.setStatus({ code:
|
|
2012
|
+
this.span.setStatus({ code: import_api15.SpanStatusCode.ERROR, message: error.message });
|
|
1871
2013
|
this.hasError = true;
|
|
1872
2014
|
return this;
|
|
1873
2015
|
}
|
|
1874
2016
|
/** End the span (preserves ERROR status if already set) */
|
|
1875
2017
|
end() {
|
|
1876
2018
|
if (!this.hasError) {
|
|
1877
|
-
this.span.setStatus({ code:
|
|
2019
|
+
this.span.setStatus({ code: import_api15.SpanStatusCode.OK });
|
|
1878
2020
|
}
|
|
1879
2021
|
this.span.end();
|
|
1880
2022
|
}
|
|
@@ -1882,7 +2024,7 @@ var TelemetrySpan = class {
|
|
|
1882
2024
|
endWithError(error) {
|
|
1883
2025
|
const msg = typeof error === "string" ? error : error.message;
|
|
1884
2026
|
if (error instanceof Error) this.span.recordException(error);
|
|
1885
|
-
this.span.setStatus({ code:
|
|
2027
|
+
this.span.setStatus({ code: import_api15.SpanStatusCode.ERROR, message: msg });
|
|
1886
2028
|
this.span.end();
|
|
1887
2029
|
}
|
|
1888
2030
|
/** Get the underlying OTel span (escape hatch) */
|
|
@@ -1893,7 +2035,7 @@ var TelemetrySpan = class {
|
|
|
1893
2035
|
var TelemetryAccessor = class {
|
|
1894
2036
|
constructor(ctx) {
|
|
1895
2037
|
this.ctx = ctx;
|
|
1896
|
-
this.tracer =
|
|
2038
|
+
this.tracer = import_api15.trace.getTracer("@frontmcp/observability");
|
|
1897
2039
|
this.fallbackContext = createOTelContextFromTrace(ctx.traceContext);
|
|
1898
2040
|
this.sessionHash = sessionTracingId(ctx.sessionId);
|
|
1899
2041
|
this.baseAttributes = {
|
|
@@ -1929,7 +2071,7 @@ var TelemetryAccessor = class {
|
|
|
1929
2071
|
const span = this.tracer.startSpan(
|
|
1930
2072
|
name,
|
|
1931
2073
|
{
|
|
1932
|
-
kind:
|
|
2074
|
+
kind: import_api15.SpanKind.INTERNAL,
|
|
1933
2075
|
attributes: { ...this.baseAttributes, ...attributes }
|
|
1934
2076
|
},
|
|
1935
2077
|
this.getActiveContext()
|
|
@@ -1978,11 +2120,11 @@ var TelemetryAccessor = class {
|
|
|
1978
2120
|
} else {
|
|
1979
2121
|
const span = this.tracer.startSpan(
|
|
1980
2122
|
name,
|
|
1981
|
-
{ kind:
|
|
2123
|
+
{ kind: import_api15.SpanKind.INTERNAL, attributes: this.baseAttributes },
|
|
1982
2124
|
this.fallbackContext
|
|
1983
2125
|
);
|
|
1984
2126
|
if (attributes) span.addEvent(name, attributes);
|
|
1985
|
-
span.setStatus({ code:
|
|
2127
|
+
span.setStatus({ code: import_api15.SpanStatusCode.OK });
|
|
1986
2128
|
span.end();
|
|
1987
2129
|
}
|
|
1988
2130
|
}
|
|
@@ -2019,7 +2161,7 @@ var TelemetryAccessor = class {
|
|
|
2019
2161
|
* Useful for including in external API calls or logs.
|
|
2020
2162
|
*/
|
|
2021
2163
|
get traceId() {
|
|
2022
|
-
return
|
|
2164
|
+
return import_api15.trace.getSpan(this.fallbackContext)?.spanContext().traceId ?? "";
|
|
2023
2165
|
}
|
|
2024
2166
|
/**
|
|
2025
2167
|
* Get the session tracing ID (privacy-safe hash).
|
|
@@ -2030,10 +2172,10 @@ var TelemetryAccessor = class {
|
|
|
2030
2172
|
};
|
|
2031
2173
|
|
|
2032
2174
|
// libs/observability/src/telemetry/telemetry.factory.ts
|
|
2033
|
-
var
|
|
2175
|
+
var import_api16 = require("@opentelemetry/api");
|
|
2034
2176
|
var TelemetryFactory = class {
|
|
2035
2177
|
constructor(tracerName = "@frontmcp/observability") {
|
|
2036
|
-
this.tracer =
|
|
2178
|
+
this.tracer = import_api16.trace.getTracer(tracerName);
|
|
2037
2179
|
}
|
|
2038
2180
|
/**
|
|
2039
2181
|
* Create (or retrieve cached) a named counter. Increments propagate to
|
|
@@ -2080,32 +2222,32 @@ var TELEMETRY_ACCESSOR = /* @__PURE__ */ Symbol.for("frontmcp:observability:tele
|
|
|
2080
2222
|
var TELEMETRY_FACTORY = /* @__PURE__ */ Symbol.for("frontmcp:observability:telemetry-factory");
|
|
2081
2223
|
|
|
2082
2224
|
// libs/observability/src/plugin/observability.plugin.ts
|
|
2083
|
-
var PromptHook = (0,
|
|
2084
|
-
var ListPromptsHook = (0,
|
|
2085
|
-
var SkillSearchHook = (0,
|
|
2086
|
-
var SkillLoadHook = (0,
|
|
2087
|
-
var CompletionHook = (0,
|
|
2088
|
-
var LegacySseHook = (0,
|
|
2089
|
-
var StreamableHttpHook = (0,
|
|
2090
|
-
var StatelessHttpHook = (0,
|
|
2091
|
-
var AuthVerifyHook = (0,
|
|
2092
|
-
var SessionVerifyHook = (0,
|
|
2093
|
-
var OAuthTokenHook = (0,
|
|
2094
|
-
var OAuthAuthorizeHook = (0,
|
|
2095
|
-
var OAuthCallbackHook = (0,
|
|
2096
|
-
var OAuthProviderCallbackHook = (0,
|
|
2097
|
-
var OAuthRegisterHook = (0,
|
|
2098
|
-
var ElicitRequestHook = (0,
|
|
2099
|
-
var ElicitResultHook = (0,
|
|
2100
|
-
var SubscribeResourceHook = (0,
|
|
2101
|
-
var UnsubscribeResourceHook = (0,
|
|
2102
|
-
var SkillsHttpLlmTxtHook = (0,
|
|
2103
|
-
var SkillsHttpLlmFullTxtHook = (0,
|
|
2104
|
-
var SkillsHttpApiHook = (0,
|
|
2105
|
-
var WellKnownJwksHook = (0,
|
|
2106
|
-
var WellKnownOAuthServerHook = (0,
|
|
2107
|
-
var WellKnownPrmHook = (0,
|
|
2108
|
-
var LoggingSetLevelHook = (0,
|
|
2225
|
+
var PromptHook = (0, import_sdk4.FlowHooksOf)("prompts:get-prompt");
|
|
2226
|
+
var ListPromptsHook = (0, import_sdk4.FlowHooksOf)("prompts:list-prompts");
|
|
2227
|
+
var SkillSearchHook = (0, import_sdk4.FlowHooksOf)("skills:search");
|
|
2228
|
+
var SkillLoadHook = (0, import_sdk4.FlowHooksOf)("skills:load");
|
|
2229
|
+
var CompletionHook = (0, import_sdk4.FlowHooksOf)("completion:complete");
|
|
2230
|
+
var LegacySseHook = (0, import_sdk4.FlowHooksOf)("handle:legacy-sse");
|
|
2231
|
+
var StreamableHttpHook = (0, import_sdk4.FlowHooksOf)("handle:streamable-http");
|
|
2232
|
+
var StatelessHttpHook = (0, import_sdk4.FlowHooksOf)("handle:stateless-http");
|
|
2233
|
+
var AuthVerifyHook = (0, import_sdk4.FlowHooksOf)("auth:verify");
|
|
2234
|
+
var SessionVerifyHook = (0, import_sdk4.FlowHooksOf)("session:verify");
|
|
2235
|
+
var OAuthTokenHook = (0, import_sdk4.FlowHooksOf)("oauth:token");
|
|
2236
|
+
var OAuthAuthorizeHook = (0, import_sdk4.FlowHooksOf)("oauth:authorize");
|
|
2237
|
+
var OAuthCallbackHook = (0, import_sdk4.FlowHooksOf)("oauth:callback");
|
|
2238
|
+
var OAuthProviderCallbackHook = (0, import_sdk4.FlowHooksOf)("oauth:provider-callback");
|
|
2239
|
+
var OAuthRegisterHook = (0, import_sdk4.FlowHooksOf)("oauth:register");
|
|
2240
|
+
var ElicitRequestHook = (0, import_sdk4.FlowHooksOf)("elicitation:request");
|
|
2241
|
+
var ElicitResultHook = (0, import_sdk4.FlowHooksOf)("elicitation:result");
|
|
2242
|
+
var SubscribeResourceHook = (0, import_sdk4.FlowHooksOf)("resources:subscribe");
|
|
2243
|
+
var UnsubscribeResourceHook = (0, import_sdk4.FlowHooksOf)("resources:unsubscribe");
|
|
2244
|
+
var SkillsHttpLlmTxtHook = (0, import_sdk4.FlowHooksOf)("skills-http:llm-txt");
|
|
2245
|
+
var SkillsHttpLlmFullTxtHook = (0, import_sdk4.FlowHooksOf)("skills-http:llm-full-txt");
|
|
2246
|
+
var SkillsHttpApiHook = (0, import_sdk4.FlowHooksOf)("skills-http:api");
|
|
2247
|
+
var WellKnownJwksHook = (0, import_sdk4.FlowHooksOf)("well-known.jwks");
|
|
2248
|
+
var WellKnownOAuthServerHook = (0, import_sdk4.FlowHooksOf)("well-known.oauth-authorization-server");
|
|
2249
|
+
var WellKnownPrmHook = (0, import_sdk4.FlowHooksOf)("well-known.prm");
|
|
2250
|
+
var LoggingSetLevelHook = (0, import_sdk4.FlowHooksOf)("logging:set-level");
|
|
2109
2251
|
var DEFAULT_TRACING = {
|
|
2110
2252
|
httpSpans: true,
|
|
2111
2253
|
executionSpans: true,
|
|
@@ -2118,17 +2260,46 @@ var DEFAULT_TRACING = {
|
|
|
2118
2260
|
elicitationSpans: true,
|
|
2119
2261
|
startupReport: true
|
|
2120
2262
|
};
|
|
2121
|
-
var ObservabilityPlugin = class extends
|
|
2263
|
+
var ObservabilityPlugin = class extends import_sdk4.DynamicPlugin {
|
|
2122
2264
|
constructor(options = {}) {
|
|
2123
2265
|
super();
|
|
2266
|
+
/** Wraps each other hook the request runs: names it on the request's log, and gives it a span with `hookSpans`. */
|
|
2267
|
+
this.observeHook = async ({ flowName, stage, target, flowContext }, run) => {
|
|
2268
|
+
if (target === this) return run();
|
|
2269
|
+
if (this.requestLogsEnabled) currentRequestLog(flowContext)?.addHook(`${flowName}:${stage}`);
|
|
2270
|
+
if (!this.traces("hookSpans")) return run();
|
|
2271
|
+
const owner = target?.constructor?.name;
|
|
2272
|
+
return runInHookSpan(flowContext, { flowName, stage, owner }, run);
|
|
2273
|
+
};
|
|
2124
2274
|
this.options = resolveOptions(options);
|
|
2125
2275
|
this.tracingOpts = this.options.tracing !== false ? this.options.tracing : DEFAULT_TRACING;
|
|
2126
2276
|
}
|
|
2127
2277
|
get tracingEnabled() {
|
|
2128
2278
|
return this.options.tracing !== false;
|
|
2129
2279
|
}
|
|
2280
|
+
get requestLogsEnabled() {
|
|
2281
|
+
return this.options.requestLogs !== false;
|
|
2282
|
+
}
|
|
2283
|
+
/** Whether tracing is on and its `kind` option isn't off. */
|
|
2284
|
+
traces(kind) {
|
|
2285
|
+
return this.tracingEnabled && this.tracingOpts[kind] !== false;
|
|
2286
|
+
}
|
|
2287
|
+
/** Watches the hooks of the request `ctx` serves, from the first flow of it that this plugin sees. */
|
|
2288
|
+
watchHooks(ctx) {
|
|
2289
|
+
if (this.requestLogsEnabled || this.traces("hookSpans"))
|
|
2290
|
+
installHookObserver(ctx, this.observeHook);
|
|
2291
|
+
}
|
|
2292
|
+
/** Names the entry a request serves on its request log, and records the entry flow's failure. */
|
|
2293
|
+
annotateRequestLog(ctx, set) {
|
|
2294
|
+
if (!this.requestLogsEnabled) return;
|
|
2295
|
+
const flowCtx = ctx;
|
|
2296
|
+
const log = currentRequestLog(ctx);
|
|
2297
|
+
if (log && flowCtx.state?.input) set(log, flowCtx.state.input);
|
|
2298
|
+
}
|
|
2130
2299
|
_httpWillTrace(ctx) {
|
|
2131
2300
|
if (this.tracingEnabled) onHttpWillTrace(this.tracingOpts, ctx);
|
|
2301
|
+
if (this.options.requestLogs !== false) startRequestLog(ctx, this.options.requestLogs);
|
|
2302
|
+
this.watchHooks(ctx);
|
|
2132
2303
|
}
|
|
2133
2304
|
_httpWillQuota(ctx) {
|
|
2134
2305
|
if (this.tracingEnabled) onHttpWillAcquireQuota(ctx);
|
|
@@ -2141,6 +2312,7 @@ var ObservabilityPlugin = class extends import_sdk2.DynamicPlugin {
|
|
|
2141
2312
|
}
|
|
2142
2313
|
_httpDidAuth(ctx) {
|
|
2143
2314
|
if (this.tracingEnabled) onHttpDidCheckAuth(ctx);
|
|
2315
|
+
if (this.requestLogsEnabled) recordRequestLogAuth(ctx);
|
|
2144
2316
|
}
|
|
2145
2317
|
_httpWillRoute(ctx) {
|
|
2146
2318
|
if (this.tracingEnabled) onHttpWillRoute(ctx);
|
|
@@ -2150,12 +2322,15 @@ var ObservabilityPlugin = class extends import_sdk2.DynamicPlugin {
|
|
|
2150
2322
|
}
|
|
2151
2323
|
_httpDidFinalize(ctx) {
|
|
2152
2324
|
if (this.tracingEnabled) onHttpDidFinalize(ctx);
|
|
2325
|
+
if (this.requestLogsEnabled) void completeRequestLog(ctx);
|
|
2153
2326
|
}
|
|
2154
2327
|
_toolWillParse(ctx) {
|
|
2328
|
+
this.watchHooks(ctx);
|
|
2155
2329
|
if (this.tracingEnabled) onToolWillParse(this.tracingOpts, ctx);
|
|
2156
2330
|
}
|
|
2157
2331
|
_toolWillFind(ctx) {
|
|
2158
2332
|
if (this.tracingEnabled) onToolWillFindTool(ctx);
|
|
2333
|
+
this.annotateRequestLog(ctx, (log, input) => log.setToolName(String(input["name"])));
|
|
2159
2334
|
}
|
|
2160
2335
|
_toolWillCheckAuth(ctx) {
|
|
2161
2336
|
if (this.tracingEnabled) onToolWillCheckAuth(ctx);
|
|
@@ -2186,12 +2361,15 @@ var ObservabilityPlugin = class extends import_sdk2.DynamicPlugin {
|
|
|
2186
2361
|
}
|
|
2187
2362
|
_toolDidFinalize(ctx) {
|
|
2188
2363
|
if (this.tracingEnabled) onToolDidFinalize(ctx);
|
|
2364
|
+
if (this.requestLogsEnabled) recordRequestLogFailure(ctx);
|
|
2189
2365
|
}
|
|
2190
2366
|
_resourceWillParse(ctx) {
|
|
2367
|
+
this.watchHooks(ctx);
|
|
2191
2368
|
if (this.tracingEnabled) onResourceWillParse(this.tracingOpts, ctx);
|
|
2192
2369
|
}
|
|
2193
2370
|
_resourceWillFind(ctx) {
|
|
2194
2371
|
if (this.tracingEnabled) onResourceWillFind(ctx);
|
|
2372
|
+
this.annotateRequestLog(ctx, (log, input) => log.setResourceUri(String(input["uri"])));
|
|
2195
2373
|
}
|
|
2196
2374
|
_resourceWillCheckAuthorities(ctx) {
|
|
2197
2375
|
if (this.tracingEnabled) onEntryWillCheckAuthorities(ctx);
|
|
@@ -2207,12 +2385,15 @@ var ObservabilityPlugin = class extends import_sdk2.DynamicPlugin {
|
|
|
2207
2385
|
}
|
|
2208
2386
|
_resourceDidFinalize(ctx) {
|
|
2209
2387
|
if (this.tracingEnabled) onResourceDidFinalize(ctx);
|
|
2388
|
+
if (this.requestLogsEnabled) recordRequestLogFailure(ctx);
|
|
2210
2389
|
}
|
|
2211
2390
|
_promptWillParse(ctx) {
|
|
2391
|
+
this.watchHooks(ctx);
|
|
2212
2392
|
if (this.tracingEnabled) onPromptWillParse(this.tracingOpts, ctx);
|
|
2213
2393
|
}
|
|
2214
2394
|
_promptWillFind(ctx) {
|
|
2215
2395
|
if (this.tracingEnabled) onPromptWillFind(ctx);
|
|
2396
|
+
this.annotateRequestLog(ctx, (log, input) => log.setPromptName(String(input["name"])));
|
|
2216
2397
|
}
|
|
2217
2398
|
_promptWillCheckAuthorities(ctx) {
|
|
2218
2399
|
if (this.tracingEnabled) onEntryWillCheckAuthorities(ctx);
|
|
@@ -2228,8 +2409,10 @@ var ObservabilityPlugin = class extends import_sdk2.DynamicPlugin {
|
|
|
2228
2409
|
}
|
|
2229
2410
|
_promptDidFinalize(ctx) {
|
|
2230
2411
|
if (this.tracingEnabled) onPromptDidFinalize(ctx);
|
|
2412
|
+
if (this.requestLogsEnabled) recordRequestLogFailure(ctx);
|
|
2231
2413
|
}
|
|
2232
2414
|
_agentWillParse(ctx) {
|
|
2415
|
+
this.watchHooks(ctx);
|
|
2233
2416
|
if (this.tracingEnabled) onAgentWillParse(this.tracingOpts, ctx);
|
|
2234
2417
|
}
|
|
2235
2418
|
_agentWillFind(ctx) {
|
|
@@ -2383,46 +2566,46 @@ var ObservabilityPlugin = class extends import_sdk2.DynamicPlugin {
|
|
|
2383
2566
|
if (this.tracingEnabled) onAuthDidFinalize(ctx);
|
|
2384
2567
|
}
|
|
2385
2568
|
_oauthTokenWill(ctx) {
|
|
2386
|
-
if (this.
|
|
2569
|
+
if (this.traces("oauthSpans")) onGenericFlowWillStart("oauth/token", this.tracingOpts, ctx);
|
|
2387
2570
|
}
|
|
2388
2571
|
_oauthTokenDone(ctx) {
|
|
2389
|
-
if (this.
|
|
2572
|
+
if (this.traces("oauthSpans")) onGenericFlowDidFinalize(ctx);
|
|
2390
2573
|
}
|
|
2391
2574
|
_oauthAuthzWill(ctx) {
|
|
2392
|
-
if (this.
|
|
2575
|
+
if (this.traces("oauthSpans")) onGenericFlowWillStart("oauth/authorize", this.tracingOpts, ctx);
|
|
2393
2576
|
}
|
|
2394
2577
|
_oauthAuthzDone(ctx) {
|
|
2395
|
-
if (this.
|
|
2578
|
+
if (this.traces("oauthSpans")) onGenericFlowDidFinalize(ctx);
|
|
2396
2579
|
}
|
|
2397
2580
|
_oauthCallbackWill(ctx) {
|
|
2398
|
-
if (this.
|
|
2581
|
+
if (this.traces("oauthSpans")) onGenericFlowWillStart("oauth/callback", this.tracingOpts, ctx);
|
|
2399
2582
|
}
|
|
2400
2583
|
_oauthCallbackDone(ctx) {
|
|
2401
|
-
if (this.
|
|
2584
|
+
if (this.traces("oauthSpans")) onGenericFlowDidFinalize(ctx);
|
|
2402
2585
|
}
|
|
2403
2586
|
_oauthProviderWill(ctx) {
|
|
2404
|
-
if (this.
|
|
2587
|
+
if (this.traces("oauthSpans")) onGenericFlowWillStart("oauth/provider-callback", this.tracingOpts, ctx);
|
|
2405
2588
|
}
|
|
2406
2589
|
_oauthProviderDone(ctx) {
|
|
2407
|
-
if (this.
|
|
2590
|
+
if (this.traces("oauthSpans")) onGenericFlowDidFinalize(ctx);
|
|
2408
2591
|
}
|
|
2409
2592
|
_oauthRegisterWill(ctx) {
|
|
2410
|
-
if (this.
|
|
2593
|
+
if (this.traces("oauthSpans")) onGenericFlowWillStart("oauth/register", this.tracingOpts, ctx);
|
|
2411
2594
|
}
|
|
2412
2595
|
_oauthRegisterDone(ctx) {
|
|
2413
|
-
if (this.
|
|
2596
|
+
if (this.traces("oauthSpans")) onGenericFlowDidFinalize(ctx);
|
|
2414
2597
|
}
|
|
2415
2598
|
_elicitReqWill(ctx) {
|
|
2416
|
-
if (this.
|
|
2599
|
+
if (this.traces("elicitationSpans")) onGenericFlowWillStart("elicitation/request", this.tracingOpts, ctx);
|
|
2417
2600
|
}
|
|
2418
2601
|
_elicitReqDone(ctx) {
|
|
2419
|
-
if (this.
|
|
2602
|
+
if (this.traces("elicitationSpans")) onGenericFlowDidFinalize(ctx);
|
|
2420
2603
|
}
|
|
2421
2604
|
_elicitResWill(ctx) {
|
|
2422
|
-
if (this.
|
|
2605
|
+
if (this.traces("elicitationSpans")) onGenericFlowWillStart("elicitation/result", this.tracingOpts, ctx);
|
|
2423
2606
|
}
|
|
2424
2607
|
_elicitResDone(ctx) {
|
|
2425
|
-
if (this.
|
|
2608
|
+
if (this.traces("elicitationSpans")) onGenericFlowDidFinalize(ctx);
|
|
2426
2609
|
}
|
|
2427
2610
|
_subscribeWill(ctx) {
|
|
2428
2611
|
if (this.tracingEnabled) onGenericFlowWillStart("resources/subscribe", this.tracingOpts, ctx);
|
|
@@ -2488,12 +2671,10 @@ var ObservabilityPlugin = class extends import_sdk2.DynamicPlugin {
|
|
|
2488
2671
|
// Startup Report (public method)
|
|
2489
2672
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
2490
2673
|
/**
|
|
2491
|
-
* Emit startup
|
|
2492
|
-
* Call after scope.initialize() completes with component counts.
|
|
2674
|
+
* Emit the `frontmcp.startup` span (`tracing.startupReport`). The scope calls it once it is ready.
|
|
2493
2675
|
*/
|
|
2494
2676
|
reportStartupTelemetry(data) {
|
|
2495
|
-
if (this.
|
|
2496
|
-
reportStartup(data);
|
|
2677
|
+
if (this.traces("startupReport")) reportStartup(data);
|
|
2497
2678
|
}
|
|
2498
2679
|
};
|
|
2499
2680
|
ObservabilityPlugin.defaultOptions = {
|
|
@@ -2511,7 +2692,7 @@ ObservabilityPlugin.dynamicProviders = (input) => {
|
|
|
2511
2692
|
providers.push({
|
|
2512
2693
|
name: "observability:tracer",
|
|
2513
2694
|
provide: OTEL_TRACER,
|
|
2514
|
-
useValue:
|
|
2695
|
+
useValue: import_api17.trace.getTracer("@frontmcp/observability")
|
|
2515
2696
|
});
|
|
2516
2697
|
providers.push({
|
|
2517
2698
|
name: "observability:config",
|
|
@@ -2521,8 +2702,8 @@ ObservabilityPlugin.dynamicProviders = (input) => {
|
|
|
2521
2702
|
providers.push({
|
|
2522
2703
|
name: "observability:telemetry-accessor",
|
|
2523
2704
|
provide: TELEMETRY_ACCESSOR,
|
|
2524
|
-
scope:
|
|
2525
|
-
inject: () => [
|
|
2705
|
+
scope: import_sdk4.ProviderScope.CONTEXT,
|
|
2706
|
+
inject: () => [import_sdk4.FRONTMCP_CONTEXT],
|
|
2526
2707
|
useFactory: (ctx) => new TelemetryAccessor(ctx)
|
|
2527
2708
|
});
|
|
2528
2709
|
providers.push({
|
|
@@ -2554,8 +2735,8 @@ ObservabilityPlugin.dynamicProviders = (input) => {
|
|
|
2554
2735
|
providers.push({
|
|
2555
2736
|
name: "observability:request-log-collector",
|
|
2556
2737
|
provide: REQUEST_LOG_COLLECTOR,
|
|
2557
|
-
scope:
|
|
2558
|
-
inject: () => [
|
|
2738
|
+
scope: import_sdk4.ProviderScope.CONTEXT,
|
|
2739
|
+
inject: () => [import_sdk4.FRONTMCP_CONTEXT],
|
|
2559
2740
|
useFactory: (ctx) => {
|
|
2560
2741
|
return new RequestLogCollector(
|
|
2561
2742
|
{
|
|
@@ -2572,85 +2753,85 @@ ObservabilityPlugin.dynamicProviders = (input) => {
|
|
|
2572
2753
|
return providers;
|
|
2573
2754
|
};
|
|
2574
2755
|
__decorateClass([
|
|
2575
|
-
|
|
2756
|
+
import_sdk4.HttpHook.Will("traceRequest", { priority: -1e3 })
|
|
2576
2757
|
], ObservabilityPlugin.prototype, "_httpWillTrace", 1);
|
|
2577
2758
|
__decorateClass([
|
|
2578
|
-
|
|
2759
|
+
import_sdk4.HttpHook.Will("acquireQuota", { priority: -1e3 })
|
|
2579
2760
|
], ObservabilityPlugin.prototype, "_httpWillQuota", 1);
|
|
2580
2761
|
__decorateClass([
|
|
2581
|
-
|
|
2762
|
+
import_sdk4.HttpHook.Did("acquireSemaphore", { priority: 1e3 })
|
|
2582
2763
|
], ObservabilityPlugin.prototype, "_httpDidSemaphore", 1);
|
|
2583
2764
|
__decorateClass([
|
|
2584
|
-
|
|
2765
|
+
import_sdk4.HttpHook.Will("checkAuthorization", { priority: -1e3 })
|
|
2585
2766
|
], ObservabilityPlugin.prototype, "_httpWillAuth", 1);
|
|
2586
2767
|
__decorateClass([
|
|
2587
|
-
|
|
2768
|
+
import_sdk4.HttpHook.Did("checkAuthorization", { priority: 1e3 })
|
|
2588
2769
|
], ObservabilityPlugin.prototype, "_httpDidAuth", 1);
|
|
2589
2770
|
__decorateClass([
|
|
2590
|
-
|
|
2771
|
+
import_sdk4.HttpHook.Will("router", { priority: -1e3 })
|
|
2591
2772
|
], ObservabilityPlugin.prototype, "_httpWillRoute", 1);
|
|
2592
2773
|
__decorateClass([
|
|
2593
|
-
|
|
2774
|
+
import_sdk4.HttpHook.Did("router", { priority: 1e3 })
|
|
2594
2775
|
], ObservabilityPlugin.prototype, "_httpDidRoute", 1);
|
|
2595
2776
|
__decorateClass([
|
|
2596
|
-
|
|
2777
|
+
import_sdk4.HttpHook.Did("finalize", { priority: 1e3 })
|
|
2597
2778
|
], ObservabilityPlugin.prototype, "_httpDidFinalize", 1);
|
|
2598
2779
|
__decorateClass([
|
|
2599
|
-
|
|
2780
|
+
import_sdk4.ToolHook.Will("parseInput", { priority: -1e3 })
|
|
2600
2781
|
], ObservabilityPlugin.prototype, "_toolWillParse", 1);
|
|
2601
2782
|
__decorateClass([
|
|
2602
|
-
|
|
2783
|
+
import_sdk4.ToolHook.Will("findTool", { priority: -1e3 })
|
|
2603
2784
|
], ObservabilityPlugin.prototype, "_toolWillFind", 1);
|
|
2604
2785
|
__decorateClass([
|
|
2605
|
-
|
|
2786
|
+
import_sdk4.ToolHook.Will("checkToolAuthorization", { priority: -1e3 })
|
|
2606
2787
|
], ObservabilityPlugin.prototype, "_toolWillCheckAuth", 1);
|
|
2607
2788
|
__decorateClass([
|
|
2608
|
-
|
|
2789
|
+
import_sdk4.ToolHook.Will("checkEntryAuthorities", { priority: -1e3 })
|
|
2609
2790
|
], ObservabilityPlugin.prototype, "_toolWillCheckAuthorities", 1);
|
|
2610
2791
|
__decorateClass([
|
|
2611
|
-
|
|
2792
|
+
import_sdk4.ToolHook.Did("checkEntryAuthorities", { priority: 1e3 })
|
|
2612
2793
|
], ObservabilityPlugin.prototype, "_toolDidCheckAuthorities", 1);
|
|
2613
2794
|
__decorateClass([
|
|
2614
|
-
|
|
2795
|
+
import_sdk4.ToolHook.Will("createToolCallContext", { priority: -1e3 })
|
|
2615
2796
|
], ObservabilityPlugin.prototype, "_toolWillCreateCtx", 1);
|
|
2616
2797
|
__decorateClass([
|
|
2617
|
-
|
|
2798
|
+
import_sdk4.ToolHook.Will("validateInput", { priority: -1e3 })
|
|
2618
2799
|
], ObservabilityPlugin.prototype, "_toolWillValidate", 1);
|
|
2619
2800
|
__decorateClass([
|
|
2620
|
-
|
|
2801
|
+
import_sdk4.ToolHook.Will("execute", { priority: -1e3 })
|
|
2621
2802
|
], ObservabilityPlugin.prototype, "_toolWillExecute", 1);
|
|
2622
2803
|
__decorateClass([
|
|
2623
|
-
|
|
2804
|
+
import_sdk4.ToolHook.Did("execute", { priority: 1e3 })
|
|
2624
2805
|
], ObservabilityPlugin.prototype, "_toolDidExecute", 1);
|
|
2625
2806
|
__decorateClass([
|
|
2626
|
-
|
|
2807
|
+
import_sdk4.ToolHook.Will("validateOutput", { priority: -1e3 })
|
|
2627
2808
|
], ObservabilityPlugin.prototype, "_toolWillValidateOut", 1);
|
|
2628
2809
|
__decorateClass([
|
|
2629
|
-
|
|
2810
|
+
import_sdk4.ToolHook.Will("applyUI", { priority: -1e3 })
|
|
2630
2811
|
], ObservabilityPlugin.prototype, "_toolWillApplyUI", 1);
|
|
2631
2812
|
__decorateClass([
|
|
2632
|
-
|
|
2813
|
+
import_sdk4.ToolHook.Did("finalize", { priority: 1e3 })
|
|
2633
2814
|
], ObservabilityPlugin.prototype, "_toolDidFinalize", 1);
|
|
2634
2815
|
__decorateClass([
|
|
2635
|
-
|
|
2816
|
+
import_sdk4.ResourceHook.Will("parseInput", { priority: -1e3 })
|
|
2636
2817
|
], ObservabilityPlugin.prototype, "_resourceWillParse", 1);
|
|
2637
2818
|
__decorateClass([
|
|
2638
|
-
|
|
2819
|
+
import_sdk4.ResourceHook.Will("findResource", { priority: -1e3 })
|
|
2639
2820
|
], ObservabilityPlugin.prototype, "_resourceWillFind", 1);
|
|
2640
2821
|
__decorateClass([
|
|
2641
|
-
|
|
2822
|
+
import_sdk4.ResourceHook.Will("checkEntryAuthorities", { priority: -1e3 })
|
|
2642
2823
|
], ObservabilityPlugin.prototype, "_resourceWillCheckAuthorities", 1);
|
|
2643
2824
|
__decorateClass([
|
|
2644
|
-
|
|
2825
|
+
import_sdk4.ResourceHook.Did("checkEntryAuthorities", { priority: 1e3 })
|
|
2645
2826
|
], ObservabilityPlugin.prototype, "_resourceDidCheckAuthorities", 1);
|
|
2646
2827
|
__decorateClass([
|
|
2647
|
-
|
|
2828
|
+
import_sdk4.ResourceHook.Will("execute", { priority: -1e3 })
|
|
2648
2829
|
], ObservabilityPlugin.prototype, "_resourceWillExecute", 1);
|
|
2649
2830
|
__decorateClass([
|
|
2650
|
-
|
|
2831
|
+
import_sdk4.ResourceHook.Did("execute", { priority: 1e3 })
|
|
2651
2832
|
], ObservabilityPlugin.prototype, "_resourceDidExecute", 1);
|
|
2652
2833
|
__decorateClass([
|
|
2653
|
-
|
|
2834
|
+
import_sdk4.ResourceHook.Did("finalize", { priority: 1e3 })
|
|
2654
2835
|
], ObservabilityPlugin.prototype, "_resourceDidFinalize", 1);
|
|
2655
2836
|
__decorateClass([
|
|
2656
2837
|
PromptHook.Will("parseInput", { priority: -1e3 })
|
|
@@ -2674,55 +2855,55 @@ __decorateClass([
|
|
|
2674
2855
|
PromptHook.Did("finalize", { priority: 1e3 })
|
|
2675
2856
|
], ObservabilityPlugin.prototype, "_promptDidFinalize", 1);
|
|
2676
2857
|
__decorateClass([
|
|
2677
|
-
|
|
2858
|
+
import_sdk4.AgentCallHook.Will("parseInput", { priority: -1e3 })
|
|
2678
2859
|
], ObservabilityPlugin.prototype, "_agentWillParse", 1);
|
|
2679
2860
|
__decorateClass([
|
|
2680
|
-
|
|
2861
|
+
import_sdk4.AgentCallHook.Will("findAgent", { priority: -1e3 })
|
|
2681
2862
|
], ObservabilityPlugin.prototype, "_agentWillFind", 1);
|
|
2682
2863
|
__decorateClass([
|
|
2683
|
-
|
|
2864
|
+
import_sdk4.AgentCallHook.Will("checkEntryAuthorities", { priority: -1e3 })
|
|
2684
2865
|
], ObservabilityPlugin.prototype, "_agentWillCheckAuthorities", 1);
|
|
2685
2866
|
__decorateClass([
|
|
2686
|
-
|
|
2867
|
+
import_sdk4.AgentCallHook.Did("checkEntryAuthorities", { priority: 1e3 })
|
|
2687
2868
|
], ObservabilityPlugin.prototype, "_agentDidCheckAuthorities", 1);
|
|
2688
2869
|
__decorateClass([
|
|
2689
|
-
|
|
2870
|
+
import_sdk4.AgentCallHook.Will("execute", { priority: -1e3 })
|
|
2690
2871
|
], ObservabilityPlugin.prototype, "_agentWillExecute", 1);
|
|
2691
2872
|
__decorateClass([
|
|
2692
|
-
|
|
2873
|
+
import_sdk4.AgentCallHook.Did("execute", { priority: 1e3 })
|
|
2693
2874
|
], ObservabilityPlugin.prototype, "_agentDidExecute", 1);
|
|
2694
2875
|
__decorateClass([
|
|
2695
|
-
|
|
2876
|
+
import_sdk4.AgentCallHook.Did("finalize", { priority: 1e3 })
|
|
2696
2877
|
], ObservabilityPlugin.prototype, "_agentDidFinalize", 1);
|
|
2697
2878
|
__decorateClass([
|
|
2698
|
-
|
|
2879
|
+
import_sdk4.ListToolsHook.Will("parseInput", { priority: -1e3 })
|
|
2699
2880
|
], ObservabilityPlugin.prototype, "_listToolsWill", 1);
|
|
2700
2881
|
__decorateClass([
|
|
2701
|
-
|
|
2882
|
+
import_sdk4.ListToolsHook.Did("findTools", { priority: 1e3 })
|
|
2702
2883
|
], ObservabilityPlugin.prototype, "_listToolsDidFind", 1);
|
|
2703
2884
|
__decorateClass([
|
|
2704
|
-
|
|
2885
|
+
import_sdk4.ListToolsHook.Did("filterByAuthorities", { priority: 1e3 })
|
|
2705
2886
|
], ObservabilityPlugin.prototype, "_listToolsDidFilter", 1);
|
|
2706
2887
|
__decorateClass([
|
|
2707
|
-
|
|
2888
|
+
import_sdk4.ListToolsHook.Did("parseTools", { priority: 1e3 })
|
|
2708
2889
|
], ObservabilityPlugin.prototype, "_listToolsDone", 1);
|
|
2709
2890
|
__decorateClass([
|
|
2710
|
-
|
|
2891
|
+
import_sdk4.ListResourcesHook.Will("parseInput", { priority: -1e3 })
|
|
2711
2892
|
], ObservabilityPlugin.prototype, "_listResourcesWill", 1);
|
|
2712
2893
|
__decorateClass([
|
|
2713
|
-
|
|
2894
|
+
import_sdk4.ListResourcesHook.Did("filterByAuthorities", { priority: 1e3 })
|
|
2714
2895
|
], ObservabilityPlugin.prototype, "_listResourcesDidFilter", 1);
|
|
2715
2896
|
__decorateClass([
|
|
2716
|
-
|
|
2897
|
+
import_sdk4.ListResourcesHook.Did("parseResources", { priority: 1e3 })
|
|
2717
2898
|
], ObservabilityPlugin.prototype, "_listResourcesDone", 1);
|
|
2718
2899
|
__decorateClass([
|
|
2719
|
-
|
|
2900
|
+
import_sdk4.ListResourceTemplatesHook.Will("parseInput", { priority: -1e3 })
|
|
2720
2901
|
], ObservabilityPlugin.prototype, "_listTemplatesWill", 1);
|
|
2721
2902
|
__decorateClass([
|
|
2722
|
-
|
|
2903
|
+
import_sdk4.ListResourceTemplatesHook.Did("filterByAuthorities", { priority: 1e3 })
|
|
2723
2904
|
], ObservabilityPlugin.prototype, "_listTemplatesDidFilter", 1);
|
|
2724
2905
|
__decorateClass([
|
|
2725
|
-
|
|
2906
|
+
import_sdk4.ListResourceTemplatesHook.Did("parseTemplates", { priority: 1e3 })
|
|
2726
2907
|
], ObservabilityPlugin.prototype, "_listTemplatesDone", 1);
|
|
2727
2908
|
__decorateClass([
|
|
2728
2909
|
ListPromptsHook.Will("parseInput", { priority: -1e3 })
|
|
@@ -2923,13 +3104,13 @@ __decorateClass([
|
|
|
2923
3104
|
LoggingSetLevelHook.Did("finalize", { priority: 1e3 })
|
|
2924
3105
|
], ObservabilityPlugin.prototype, "_setLevelDone", 1);
|
|
2925
3106
|
__decorateClass([
|
|
2926
|
-
|
|
3107
|
+
import_sdk4.ToolHook.Did("createToolCallContext", { priority: 999 })
|
|
2927
3108
|
], ObservabilityPlugin.prototype, "_toolDidCreateCtxFetch", 1);
|
|
2928
3109
|
__decorateClass([
|
|
2929
|
-
|
|
3110
|
+
import_sdk4.AgentCallHook.Did("execute", { priority: 999 })
|
|
2930
3111
|
], ObservabilityPlugin.prototype, "_agentDidExecuteMeta", 1);
|
|
2931
3112
|
ObservabilityPlugin = __decorateClass([
|
|
2932
|
-
(0,
|
|
3113
|
+
(0, import_sdk4.Plugin)({
|
|
2933
3114
|
name: "observability",
|
|
2934
3115
|
description: "Full-system OpenTelemetry instrumentation, structured logging, and request logs",
|
|
2935
3116
|
providers: [],
|
|
@@ -2966,11 +3147,11 @@ function resolveRequestLogOptions(input) {
|
|
|
2966
3147
|
}
|
|
2967
3148
|
|
|
2968
3149
|
// libs/observability/src/otel/context-propagator.ts
|
|
2969
|
-
var
|
|
3150
|
+
var import_api18 = require("@opentelemetry/api");
|
|
2970
3151
|
var TRACEPARENT_HEADER = "traceparent";
|
|
2971
3152
|
var FrontMcpPropagator = class {
|
|
2972
3153
|
inject(context, carrier, setter) {
|
|
2973
|
-
const span =
|
|
3154
|
+
const span = import_api18.trace.getSpan(context);
|
|
2974
3155
|
if (!span) return;
|
|
2975
3156
|
const sc = span.spanContext();
|
|
2976
3157
|
if (!sc || !isValidSpanContext(sc)) return;
|
|
@@ -2990,8 +3171,8 @@ var FrontMcpPropagator = class {
|
|
|
2990
3171
|
traceFlags: parsed.traceFlags,
|
|
2991
3172
|
isRemote: true
|
|
2992
3173
|
};
|
|
2993
|
-
const span =
|
|
2994
|
-
return
|
|
3174
|
+
const span = import_api18.trace.wrapSpanContext(spanContext);
|
|
3175
|
+
return import_api18.trace.setSpan(context, span);
|
|
2995
3176
|
}
|
|
2996
3177
|
fields() {
|
|
2997
3178
|
return [TRACEPARENT_HEADER];
|
|
@@ -3058,33 +3239,6 @@ function setupOTel(options) {
|
|
|
3058
3239
|
}
|
|
3059
3240
|
}
|
|
3060
3241
|
|
|
3061
|
-
// libs/observability/src/otel/spans/hook.span.ts
|
|
3062
|
-
var import_api18 = require("@opentelemetry/api");
|
|
3063
|
-
function recordHookEvent(parentSpan, stage, owner) {
|
|
3064
|
-
const attributes = {};
|
|
3065
|
-
if (owner) {
|
|
3066
|
-
attributes[FrontMcpAttributes.HOOK_OWNER] = owner;
|
|
3067
|
-
}
|
|
3068
|
-
parentSpan.addEvent(`hook.${stage}`, attributes);
|
|
3069
|
-
}
|
|
3070
|
-
function startHookSpan(tracer, options) {
|
|
3071
|
-
const attributes = {
|
|
3072
|
-
[FrontMcpAttributes.HOOK_STAGE]: options.stage
|
|
3073
|
-
};
|
|
3074
|
-
if (options.owner) {
|
|
3075
|
-
attributes[FrontMcpAttributes.HOOK_OWNER] = options.owner;
|
|
3076
|
-
}
|
|
3077
|
-
if (options.flowName) {
|
|
3078
|
-
attributes[FrontMcpAttributes.FLOW_NAME] = options.flowName;
|
|
3079
|
-
}
|
|
3080
|
-
return startSpan(tracer, {
|
|
3081
|
-
name: `hook ${options.stage}`,
|
|
3082
|
-
kind: import_api18.SpanKind.INTERNAL,
|
|
3083
|
-
attributes,
|
|
3084
|
-
parentContext: options.parentContext
|
|
3085
|
-
});
|
|
3086
|
-
}
|
|
3087
|
-
|
|
3088
3242
|
// libs/observability/src/otel/spans/pretty-span-exporter.ts
|
|
3089
3243
|
var import_api19 = require("@opentelemetry/api");
|
|
3090
3244
|
var RESET = "\x1B[0m";
|
|
@@ -3252,6 +3406,13 @@ function renderJsonExposition(counters, gauges = []) {
|
|
|
3252
3406
|
var import_utils2 = require("@frontmcp/utils");
|
|
3253
3407
|
var NS_PER_SECOND = 1e9;
|
|
3254
3408
|
var MICROS_PER_SECOND = 1e6;
|
|
3409
|
+
function probeSafely(probe) {
|
|
3410
|
+
try {
|
|
3411
|
+
return probe();
|
|
3412
|
+
} catch {
|
|
3413
|
+
return void 0;
|
|
3414
|
+
}
|
|
3415
|
+
}
|
|
3255
3416
|
function defaultMonitorEventLoopDelay() {
|
|
3256
3417
|
try {
|
|
3257
3418
|
const { monitorEventLoopDelay } = require("node:perf_hooks");
|
|
@@ -3297,54 +3458,70 @@ var ProcessStatsCollector = class {
|
|
|
3297
3458
|
this.getActiveHandles = init.getActiveHandles ?? defaultGetActiveHandles;
|
|
3298
3459
|
this.getActiveRequests = init.getActiveRequests ?? defaultGetActiveRequests;
|
|
3299
3460
|
this.readFdCount = init.readFdCount ?? defaultReadFdCount;
|
|
3300
|
-
this.cpuStart = this.cpuUsage();
|
|
3461
|
+
this.cpuStart = probeSafely(() => this.cpuUsage());
|
|
3301
3462
|
if (this.options.eventLoopLag !== false) {
|
|
3302
3463
|
this.histogram = init.monitorEventLoopDelay ? init.monitorEventLoopDelay() : defaultMonitorEventLoopDelay();
|
|
3303
3464
|
}
|
|
3304
3465
|
}
|
|
3305
3466
|
collect() {
|
|
3306
3467
|
const entries = [];
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3468
|
+
this.cpuStart ??= probeSafely(() => this.cpuUsage());
|
|
3469
|
+
const cpu = this.cpuStart && probeSafely(() => this.cpuUsage(this.cpuStart));
|
|
3470
|
+
if (cpu) {
|
|
3471
|
+
entries.push({
|
|
3472
|
+
name: "frontmcp_process_cpu_seconds_total",
|
|
3473
|
+
value: cpu.user / MICROS_PER_SECOND,
|
|
3474
|
+
attributes: { mode: "user" },
|
|
3475
|
+
help: "CPU time consumed since collector start, by mode (seconds)"
|
|
3476
|
+
});
|
|
3477
|
+
entries.push({
|
|
3478
|
+
name: "frontmcp_process_cpu_seconds_total",
|
|
3479
|
+
value: cpu.system / MICROS_PER_SECOND,
|
|
3480
|
+
attributes: { mode: "system" }
|
|
3481
|
+
});
|
|
3482
|
+
}
|
|
3483
|
+
const mem = probeSafely(() => this.memoryUsage());
|
|
3484
|
+
if (mem && mem.rss > 0) {
|
|
3485
|
+
entries.push({
|
|
3486
|
+
name: "frontmcp_process_resident_memory_bytes",
|
|
3487
|
+
value: mem.rss,
|
|
3488
|
+
help: "Resident memory size in bytes"
|
|
3489
|
+
});
|
|
3490
|
+
entries.push({
|
|
3491
|
+
name: "frontmcp_process_heap_bytes",
|
|
3492
|
+
value: mem.heapTotal,
|
|
3493
|
+
help: "Total V8 heap size in bytes"
|
|
3494
|
+
});
|
|
3495
|
+
entries.push({
|
|
3496
|
+
name: "frontmcp_process_heap_used_bytes",
|
|
3497
|
+
value: mem.heapUsed,
|
|
3498
|
+
help: "Used V8 heap size in bytes"
|
|
3499
|
+
});
|
|
3500
|
+
entries.push({
|
|
3501
|
+
name: "frontmcp_process_external_bytes",
|
|
3502
|
+
value: mem.external,
|
|
3503
|
+
help: "Memory used by C++ objects bound to JS in bytes"
|
|
3504
|
+
});
|
|
3505
|
+
}
|
|
3506
|
+
const uptime = probeSafely(() => this.uptime());
|
|
3507
|
+
if (uptime !== void 0 && uptime > 0) {
|
|
3508
|
+
entries.push({
|
|
3509
|
+
name: "frontmcp_process_uptime_seconds",
|
|
3510
|
+
value: uptime,
|
|
3511
|
+
help: "Time since process start in seconds"
|
|
3512
|
+
});
|
|
3513
|
+
}
|
|
3514
|
+
const histogram = this.options.eventLoopLag !== false ? this.histogram : void 0;
|
|
3515
|
+
const lag = histogram && probeSafely(() => {
|
|
3516
|
+
const sample = {
|
|
3517
|
+
meanSeconds: histogram.mean / NS_PER_SECOND,
|
|
3518
|
+
p99Seconds: histogram.percentile(99) / NS_PER_SECOND
|
|
3519
|
+
};
|
|
3520
|
+
histogram.reset();
|
|
3521
|
+
return sample;
|
|
3344
3522
|
});
|
|
3345
|
-
if (
|
|
3346
|
-
const meanSeconds
|
|
3347
|
-
const p99Seconds = this.histogram.percentile(99) / NS_PER_SECOND;
|
|
3523
|
+
if (lag) {
|
|
3524
|
+
const { meanSeconds, p99Seconds } = lag;
|
|
3348
3525
|
if (Number.isFinite(meanSeconds)) {
|
|
3349
3526
|
entries.push({
|
|
3350
3527
|
name: "frontmcp_nodejs_eventloop_lag_seconds",
|
|
@@ -3360,7 +3537,6 @@ var ProcessStatsCollector = class {
|
|
|
3360
3537
|
attributes: { quantile: "p99" }
|
|
3361
3538
|
});
|
|
3362
3539
|
}
|
|
3363
|
-
this.histogram.reset();
|
|
3364
3540
|
}
|
|
3365
3541
|
if (this.options.activeHandles !== false) {
|
|
3366
3542
|
const handles = this.getActiveHandles?.();
|