@frontmcp/observability 0.0.1 → 1.0.0-rc.1
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 +2986 -0
- package/esm/package.json +86 -0
- package/index.d.ts +11 -0
- package/logging/index.d.ts +9 -0
- package/logging/log-sink.interface.d.ts +81 -0
- package/logging/redaction.d.ts +17 -0
- package/logging/sink.factory.d.ts +15 -0
- package/logging/sinks/callback.sink.d.ts +12 -0
- package/logging/sinks/console.sink.d.ts +16 -0
- package/logging/sinks/index.d.ts +7 -0
- package/logging/sinks/otlp.sink.d.ts +67 -0
- package/logging/sinks/pino.sink.d.ts +13 -0
- package/logging/sinks/stdout.sink.d.ts +17 -0
- package/logging/sinks/winston.sink.d.ts +13 -0
- package/logging/structured-log-transport.d.ts +52 -0
- package/logging/structured-log.types.d.ts +71 -0
- package/otel/context-propagator.d.ts +17 -0
- package/otel/index.d.ts +8 -0
- package/otel/otel.setup.d.ts +32 -0
- package/otel/otel.tokens.d.ts +7 -0
- package/otel/otel.types.d.ts +151 -0
- package/otel/spans/auth.span.d.ts +27 -0
- package/otel/spans/fetch.span.d.ts +28 -0
- package/otel/spans/hook.span.d.ts +33 -0
- package/otel/spans/http-server.span.d.ts +29 -0
- package/otel/spans/index.d.ts +23 -0
- package/otel/spans/pretty-span-exporter.d.ts +19 -0
- package/otel/spans/prompt.span.d.ts +19 -0
- package/otel/spans/resource.span.d.ts +21 -0
- package/otel/spans/rpc.span.d.ts +33 -0
- package/otel/spans/span.utils.d.ts +38 -0
- package/otel/spans/startup.span.d.ts +28 -0
- package/otel/spans/tool.span.d.ts +25 -0
- package/otel/spans/transport.span.d.ts +30 -0
- package/otel/trace-context-bridge.d.ts +41 -0
- package/package.json +1 -1
- package/plugin/index.d.ts +3 -0
- package/plugin/observability.hooks.d.ts +92 -0
- package/plugin/observability.plugin.d.ts +141 -0
- package/plugin/observability.plugin.types.d.ts +38 -0
- package/request-log/index.d.ts +3 -0
- package/request-log/request-log.collector.d.ts +97 -0
- package/request-log/request-log.tokens.d.ts +7 -0
- package/request-log/request-log.types.d.ts +82 -0
- package/telemetry/index.d.ts +3 -0
- package/telemetry/telemetry.accessor.d.ts +151 -0
- package/telemetry/telemetry.context-extension.d.ts +35 -0
- package/telemetry/telemetry.tokens.d.ts +7 -0
- package/testing/index.d.ts +76 -0
package/esm/index.mjs
ADDED
|
@@ -0,0 +1,2986 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
6
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
7
|
+
}) : x)(function(x) {
|
|
8
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
9
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
10
|
+
});
|
|
11
|
+
var __esm = (fn, res) => function __init() {
|
|
12
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
13
|
+
};
|
|
14
|
+
var __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
28
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
29
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
30
|
+
if (decorator = decorators[i])
|
|
31
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
32
|
+
if (kind && result) __defProp(target, key, result);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// libs/observability/src/logging/sinks/winston.sink.ts
|
|
37
|
+
var winston_sink_exports = {};
|
|
38
|
+
__export(winston_sink_exports, {
|
|
39
|
+
WinstonSink: () => WinstonSink
|
|
40
|
+
});
|
|
41
|
+
function mapToWinstonLevel(level) {
|
|
42
|
+
switch (level) {
|
|
43
|
+
case "debug":
|
|
44
|
+
case "verbose":
|
|
45
|
+
return "debug";
|
|
46
|
+
case "info":
|
|
47
|
+
return "info";
|
|
48
|
+
case "warn":
|
|
49
|
+
return "warn";
|
|
50
|
+
case "error":
|
|
51
|
+
return "error";
|
|
52
|
+
default:
|
|
53
|
+
return "info";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
var WinstonSink;
|
|
57
|
+
var init_winston_sink = __esm({
|
|
58
|
+
"libs/observability/src/logging/sinks/winston.sink.ts"() {
|
|
59
|
+
"use strict";
|
|
60
|
+
WinstonSink = class {
|
|
61
|
+
constructor(logger) {
|
|
62
|
+
this.logger = logger;
|
|
63
|
+
}
|
|
64
|
+
write(entry) {
|
|
65
|
+
const { message, level, ...meta } = entry;
|
|
66
|
+
const winstonLevel = mapToWinstonLevel(level);
|
|
67
|
+
switch (winstonLevel) {
|
|
68
|
+
case "debug":
|
|
69
|
+
this.logger.debug(message, meta);
|
|
70
|
+
break;
|
|
71
|
+
case "info":
|
|
72
|
+
this.logger.info(message, meta);
|
|
73
|
+
break;
|
|
74
|
+
case "warn":
|
|
75
|
+
this.logger.warn(message, meta);
|
|
76
|
+
break;
|
|
77
|
+
case "error":
|
|
78
|
+
this.logger.error(message, meta);
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// libs/observability/src/logging/sinks/pino.sink.ts
|
|
87
|
+
var pino_sink_exports = {};
|
|
88
|
+
__export(pino_sink_exports, {
|
|
89
|
+
PinoSink: () => PinoSink
|
|
90
|
+
});
|
|
91
|
+
function mapToPinoLevel(level) {
|
|
92
|
+
switch (level) {
|
|
93
|
+
case "debug":
|
|
94
|
+
case "verbose":
|
|
95
|
+
return "debug";
|
|
96
|
+
case "info":
|
|
97
|
+
return "info";
|
|
98
|
+
case "warn":
|
|
99
|
+
return "warn";
|
|
100
|
+
case "error":
|
|
101
|
+
return "error";
|
|
102
|
+
default:
|
|
103
|
+
return "info";
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
var PinoSink;
|
|
107
|
+
var init_pino_sink = __esm({
|
|
108
|
+
"libs/observability/src/logging/sinks/pino.sink.ts"() {
|
|
109
|
+
"use strict";
|
|
110
|
+
PinoSink = class {
|
|
111
|
+
constructor(logger) {
|
|
112
|
+
this.logger = logger;
|
|
113
|
+
}
|
|
114
|
+
write(entry) {
|
|
115
|
+
const { message, level, ...obj } = entry;
|
|
116
|
+
const pinoLevel = mapToPinoLevel(level);
|
|
117
|
+
switch (pinoLevel) {
|
|
118
|
+
case "debug":
|
|
119
|
+
this.logger.debug(obj, message);
|
|
120
|
+
break;
|
|
121
|
+
case "info":
|
|
122
|
+
this.logger.info(obj, message);
|
|
123
|
+
break;
|
|
124
|
+
case "warn":
|
|
125
|
+
this.logger.warn(obj, message);
|
|
126
|
+
break;
|
|
127
|
+
case "error":
|
|
128
|
+
this.logger.error(obj, message);
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// libs/observability/src/logging/sinks/otlp.sink.ts
|
|
137
|
+
var otlp_sink_exports = {};
|
|
138
|
+
__export(otlp_sink_exports, {
|
|
139
|
+
OtlpSink: () => OtlpSink
|
|
140
|
+
});
|
|
141
|
+
var OtlpSink;
|
|
142
|
+
var init_otlp_sink = __esm({
|
|
143
|
+
"libs/observability/src/logging/sinks/otlp.sink.ts"() {
|
|
144
|
+
"use strict";
|
|
145
|
+
OtlpSink = class {
|
|
146
|
+
constructor(options) {
|
|
147
|
+
this.batch = [];
|
|
148
|
+
let base = options.endpoint;
|
|
149
|
+
while (base.endsWith("/")) {
|
|
150
|
+
base = base.slice(0, -1);
|
|
151
|
+
}
|
|
152
|
+
this.endpoint = `${base}/v1/logs`;
|
|
153
|
+
this.headers = {
|
|
154
|
+
"Content-Type": "application/json",
|
|
155
|
+
...options.headers ?? {}
|
|
156
|
+
};
|
|
157
|
+
this.batchSize = options.batchSize ?? 100;
|
|
158
|
+
this.maxQueueSize = options.maxQueueSize ?? 5e3;
|
|
159
|
+
this.serviceName = options.serviceName ?? (typeof process !== "undefined" ? process.env?.["OTEL_SERVICE_NAME"] : void 0) ?? "frontmcp-server";
|
|
160
|
+
const flushMs = options.flushIntervalMs ?? 5e3;
|
|
161
|
+
if (flushMs > 0) {
|
|
162
|
+
this.flushTimer = setInterval(() => {
|
|
163
|
+
void this.flush();
|
|
164
|
+
}, flushMs);
|
|
165
|
+
if (this.flushTimer && typeof this.flushTimer === "object" && "unref" in this.flushTimer) {
|
|
166
|
+
this.flushTimer.unref();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
write(entry) {
|
|
171
|
+
this.batch.push(entry);
|
|
172
|
+
this.enforceCapacity();
|
|
173
|
+
if (this.batch.length >= this.batchSize) {
|
|
174
|
+
void this.flush();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async flush() {
|
|
178
|
+
if (this.batch.length === 0) return;
|
|
179
|
+
const entries = this.batch.splice(0);
|
|
180
|
+
const payload = this.buildOtlpPayload(entries);
|
|
181
|
+
try {
|
|
182
|
+
const controller = new AbortController();
|
|
183
|
+
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
184
|
+
try {
|
|
185
|
+
const response = await fetch(this.endpoint, {
|
|
186
|
+
method: "POST",
|
|
187
|
+
headers: this.headers,
|
|
188
|
+
body: JSON.stringify(payload),
|
|
189
|
+
signal: controller.signal
|
|
190
|
+
});
|
|
191
|
+
clearTimeout(timeout);
|
|
192
|
+
if (!response.ok) {
|
|
193
|
+
const body = await response.text().catch(() => "");
|
|
194
|
+
console.error(`[OtlpSink] Export failed: HTTP ${response.status} \u2014 ${body.slice(0, 200)}`);
|
|
195
|
+
this.requeue(entries);
|
|
196
|
+
}
|
|
197
|
+
} catch (err) {
|
|
198
|
+
clearTimeout(timeout);
|
|
199
|
+
console.debug(
|
|
200
|
+
`[OtlpSink] Export error (${entries.length} entries): ${err instanceof Error ? err.message : err}`
|
|
201
|
+
);
|
|
202
|
+
this.requeue(entries);
|
|
203
|
+
}
|
|
204
|
+
} catch {
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
requeue(entries) {
|
|
208
|
+
this.batch.unshift(...entries);
|
|
209
|
+
this.enforceCapacity();
|
|
210
|
+
}
|
|
211
|
+
enforceCapacity() {
|
|
212
|
+
if (this.batch.length > this.maxQueueSize) {
|
|
213
|
+
this.batch.splice(0, this.batch.length - this.maxQueueSize);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
async close() {
|
|
217
|
+
if (this.flushTimer) {
|
|
218
|
+
clearInterval(this.flushTimer);
|
|
219
|
+
this.flushTimer = void 0;
|
|
220
|
+
}
|
|
221
|
+
await this.flush();
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Build OTLP Logs JSON payload per the OTel spec.
|
|
225
|
+
*
|
|
226
|
+
* @see https://opentelemetry.io/docs/specs/otlp/#otlphttp-request
|
|
227
|
+
* @see https://opentelemetry.io/docs/specs/otel/logs/data-model/
|
|
228
|
+
*/
|
|
229
|
+
buildOtlpPayload(entries) {
|
|
230
|
+
return {
|
|
231
|
+
resourceLogs: [
|
|
232
|
+
{
|
|
233
|
+
resource: {
|
|
234
|
+
attributes: [{ key: "service.name", value: { stringValue: this.serviceName } }]
|
|
235
|
+
},
|
|
236
|
+
scopeLogs: [
|
|
237
|
+
{
|
|
238
|
+
scope: { name: "@frontmcp/observability" },
|
|
239
|
+
logRecords: entries.map((entry) => this.entryToLogRecord(entry))
|
|
240
|
+
}
|
|
241
|
+
]
|
|
242
|
+
}
|
|
243
|
+
]
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
entryToLogRecord(entry) {
|
|
247
|
+
const attrs = [];
|
|
248
|
+
const record = {
|
|
249
|
+
timeUnixNano: String(new Date(entry.timestamp).getTime() * 1e6),
|
|
250
|
+
severityNumber: entry.severity_number,
|
|
251
|
+
severityText: entry.level.toUpperCase(),
|
|
252
|
+
body: { stringValue: entry.message },
|
|
253
|
+
attributes: attrs
|
|
254
|
+
};
|
|
255
|
+
if (entry.trace_id) {
|
|
256
|
+
record.traceId = entry.trace_id;
|
|
257
|
+
}
|
|
258
|
+
if (entry.span_id) {
|
|
259
|
+
record.spanId = entry.span_id;
|
|
260
|
+
}
|
|
261
|
+
if (entry.trace_flags !== void 0) {
|
|
262
|
+
record.flags = entry.trace_flags;
|
|
263
|
+
}
|
|
264
|
+
if (entry.request_id) {
|
|
265
|
+
attrs.push({ key: "frontmcp.request.id", value: { stringValue: entry.request_id } });
|
|
266
|
+
}
|
|
267
|
+
if (entry.session_id_hash) {
|
|
268
|
+
attrs.push({ key: "mcp.session.id", value: { stringValue: entry.session_id_hash } });
|
|
269
|
+
}
|
|
270
|
+
if (entry.scope_id) {
|
|
271
|
+
attrs.push({ key: "frontmcp.scope.id", value: { stringValue: entry.scope_id } });
|
|
272
|
+
}
|
|
273
|
+
if (entry.flow_name) {
|
|
274
|
+
attrs.push({ key: "frontmcp.flow.name", value: { stringValue: entry.flow_name } });
|
|
275
|
+
}
|
|
276
|
+
if (entry.prefix) {
|
|
277
|
+
attrs.push({ key: "log.prefix", value: { stringValue: entry.prefix } });
|
|
278
|
+
}
|
|
279
|
+
if (entry.elapsed_ms !== void 0) {
|
|
280
|
+
attrs.push({
|
|
281
|
+
key: "elapsed_ms",
|
|
282
|
+
value: Number.isInteger(entry.elapsed_ms) ? { intValue: String(entry.elapsed_ms) } : { doubleValue: entry.elapsed_ms }
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
if (entry.error) {
|
|
286
|
+
attrs.push({ key: "error.type", value: { stringValue: entry.error.type } });
|
|
287
|
+
attrs.push({ key: "error.message", value: { stringValue: entry.error.message } });
|
|
288
|
+
if (entry.error.code) {
|
|
289
|
+
attrs.push({ key: "error.code", value: { stringValue: entry.error.code } });
|
|
290
|
+
}
|
|
291
|
+
if (entry.error.error_id) {
|
|
292
|
+
attrs.push({ key: "error.id", value: { stringValue: entry.error.error_id } });
|
|
293
|
+
}
|
|
294
|
+
if (entry.error.stack) {
|
|
295
|
+
attrs.push({ key: "error.stack", value: { stringValue: entry.error.stack } });
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (entry.attributes) {
|
|
299
|
+
for (const [key, value] of Object.entries(entry.attributes)) {
|
|
300
|
+
if (value == null) continue;
|
|
301
|
+
if (typeof value === "string") {
|
|
302
|
+
attrs.push({ key, value: { stringValue: value } });
|
|
303
|
+
} else if (typeof value === "number") {
|
|
304
|
+
attrs.push({
|
|
305
|
+
key,
|
|
306
|
+
value: Number.isInteger(value) ? { intValue: String(value) } : { doubleValue: value }
|
|
307
|
+
});
|
|
308
|
+
} else if (typeof value === "boolean") {
|
|
309
|
+
attrs.push({ key, value: { boolValue: value } });
|
|
310
|
+
} else {
|
|
311
|
+
attrs.push({ key, value: { stringValue: JSON.stringify(value) } });
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return record;
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// libs/observability/src/plugin/observability.plugin.ts
|
|
322
|
+
import {
|
|
323
|
+
DynamicPlugin,
|
|
324
|
+
Plugin,
|
|
325
|
+
ProviderScope,
|
|
326
|
+
FRONTMCP_CONTEXT,
|
|
327
|
+
ToolHook,
|
|
328
|
+
ResourceHook,
|
|
329
|
+
HttpHook,
|
|
330
|
+
ListToolsHook,
|
|
331
|
+
ListResourcesHook,
|
|
332
|
+
ListResourceTemplatesHook,
|
|
333
|
+
AgentCallHook,
|
|
334
|
+
FlowHooksOf
|
|
335
|
+
} from "@frontmcp/sdk";
|
|
336
|
+
import { trace as trace5 } from "@opentelemetry/api";
|
|
337
|
+
|
|
338
|
+
// libs/observability/src/otel/otel.tokens.ts
|
|
339
|
+
var OTEL_TRACER = /* @__PURE__ */ Symbol.for("frontmcp:observability:otel-tracer");
|
|
340
|
+
var OTEL_CONFIG = /* @__PURE__ */ Symbol.for("frontmcp:observability:otel-config");
|
|
341
|
+
|
|
342
|
+
// libs/observability/src/request-log/request-log.tokens.ts
|
|
343
|
+
var REQUEST_LOG_COLLECTOR = /* @__PURE__ */ Symbol.for("frontmcp:observability:request-log-collector");
|
|
344
|
+
|
|
345
|
+
// libs/observability/src/request-log/request-log.collector.ts
|
|
346
|
+
var RequestLogCollector = class {
|
|
347
|
+
constructor(context, options) {
|
|
348
|
+
this.entries = [];
|
|
349
|
+
this.hooksTriggered = /* @__PURE__ */ new Set();
|
|
350
|
+
this.authenticated = false;
|
|
351
|
+
this.status = "ok";
|
|
352
|
+
this.finalized = false;
|
|
353
|
+
this.requestId = context.requestId;
|
|
354
|
+
this.traceId = context.traceId;
|
|
355
|
+
this.sessionIdHash = context.sessionIdHash;
|
|
356
|
+
this.scopeId = context.scopeId;
|
|
357
|
+
this.startTime = /* @__PURE__ */ new Date();
|
|
358
|
+
this.maxEntries = options?.maxEntries ?? 500;
|
|
359
|
+
this.onComplete = options?.onRequestComplete;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Add a structured log entry to this request's log.
|
|
363
|
+
* Called by StructuredLogTransport for each log record that
|
|
364
|
+
* matches this request's requestId.
|
|
365
|
+
*/
|
|
366
|
+
addEntry(entry) {
|
|
367
|
+
if (this.finalized || this.entries.length >= this.maxEntries) return;
|
|
368
|
+
const logEntry = {
|
|
369
|
+
timestamp: entry.timestamp,
|
|
370
|
+
level: entry.level,
|
|
371
|
+
message: entry.message
|
|
372
|
+
};
|
|
373
|
+
if (entry.flow_name) {
|
|
374
|
+
logEntry.stage = entry.flow_name;
|
|
375
|
+
}
|
|
376
|
+
if (entry.elapsed_ms !== void 0) {
|
|
377
|
+
logEntry.elapsed_ms = entry.elapsed_ms;
|
|
378
|
+
}
|
|
379
|
+
if (entry.attributes && Object.keys(entry.attributes).length > 0) {
|
|
380
|
+
logEntry.attributes = entry.attributes;
|
|
381
|
+
}
|
|
382
|
+
this.entries.push(logEntry);
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Record a hook stage that was triggered during this request.
|
|
386
|
+
*/
|
|
387
|
+
addHook(stage) {
|
|
388
|
+
this.hooksTriggered.add(stage);
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Set HTTP request metadata.
|
|
392
|
+
*/
|
|
393
|
+
setHttpInfo(method, path) {
|
|
394
|
+
this.httpMethod = method;
|
|
395
|
+
this.httpPath = path;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Set the MCP JSON-RPC method being invoked.
|
|
399
|
+
*/
|
|
400
|
+
setRpcMethod(method) {
|
|
401
|
+
this.rpcMethod = method;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Set the tool name being invoked.
|
|
405
|
+
*/
|
|
406
|
+
setToolName(name) {
|
|
407
|
+
this.toolName = name;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Set the resource URI being read.
|
|
411
|
+
*/
|
|
412
|
+
setResourceUri(uri) {
|
|
413
|
+
this.resourceUri = uri;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Set the prompt name being invoked.
|
|
417
|
+
*/
|
|
418
|
+
setPromptName(name) {
|
|
419
|
+
this.promptName = name;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Set authentication info.
|
|
423
|
+
*/
|
|
424
|
+
setAuthInfo(type, authenticated) {
|
|
425
|
+
this.authType = type;
|
|
426
|
+
this.authenticated = authenticated;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Set request status.
|
|
430
|
+
*/
|
|
431
|
+
setStatus(status, statusCode) {
|
|
432
|
+
this.status = status;
|
|
433
|
+
this.statusCode = statusCode;
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Set error details.
|
|
437
|
+
*/
|
|
438
|
+
setError(error) {
|
|
439
|
+
this.error = error;
|
|
440
|
+
this.status = "error";
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Finalize and produce the complete RequestLog.
|
|
444
|
+
* Fires the onRequestComplete callback if configured.
|
|
445
|
+
*/
|
|
446
|
+
async finalize() {
|
|
447
|
+
if (this.finalized) {
|
|
448
|
+
return this.finalizedLog;
|
|
449
|
+
}
|
|
450
|
+
this.finalized = true;
|
|
451
|
+
const log = this.toRequestLog();
|
|
452
|
+
this.finalizedLog = log;
|
|
453
|
+
if (this.onComplete) {
|
|
454
|
+
try {
|
|
455
|
+
await this.onComplete(log);
|
|
456
|
+
} catch {
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
return log;
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Build the RequestLog object from accumulated state.
|
|
463
|
+
*/
|
|
464
|
+
toRequestLog() {
|
|
465
|
+
const endTime = /* @__PURE__ */ new Date();
|
|
466
|
+
return {
|
|
467
|
+
request_id: this.requestId,
|
|
468
|
+
trace_id: this.traceId,
|
|
469
|
+
session_id_hash: this.sessionIdHash,
|
|
470
|
+
scope_id: this.scopeId,
|
|
471
|
+
start_time: this.startTime.toISOString(),
|
|
472
|
+
end_time: endTime.toISOString(),
|
|
473
|
+
duration_ms: endTime.getTime() - this.startTime.getTime(),
|
|
474
|
+
http_method: this.httpMethod,
|
|
475
|
+
http_path: this.httpPath,
|
|
476
|
+
rpc_method: this.rpcMethod,
|
|
477
|
+
tool_name: this.toolName,
|
|
478
|
+
resource_uri: this.resourceUri,
|
|
479
|
+
prompt_name: this.promptName,
|
|
480
|
+
auth_type: this.authType,
|
|
481
|
+
authenticated: this.authenticated,
|
|
482
|
+
status: this.status,
|
|
483
|
+
status_code: this.statusCode,
|
|
484
|
+
error: this.error,
|
|
485
|
+
hooks_triggered: Array.from(this.hooksTriggered),
|
|
486
|
+
entries: [...this.entries]
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Check if the collector has been finalized.
|
|
491
|
+
*/
|
|
492
|
+
isFinalized() {
|
|
493
|
+
return this.finalized;
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Get the number of accumulated entries.
|
|
497
|
+
*/
|
|
498
|
+
getEntryCount() {
|
|
499
|
+
return this.entries.length;
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
// libs/observability/src/logging/structured-log-transport.ts
|
|
504
|
+
import { LogTransportInterface, LogLevelName, LogTransport } from "@frontmcp/sdk";
|
|
505
|
+
|
|
506
|
+
// libs/observability/src/logging/structured-log.types.ts
|
|
507
|
+
var LOG_LEVEL_TO_OTEL_SEVERITY = {
|
|
508
|
+
debug: 5,
|
|
509
|
+
// DEBUG
|
|
510
|
+
verbose: 6,
|
|
511
|
+
// DEBUG2
|
|
512
|
+
info: 9,
|
|
513
|
+
// INFO
|
|
514
|
+
warn: 13,
|
|
515
|
+
// WARN
|
|
516
|
+
error: 17
|
|
517
|
+
// ERROR
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
// libs/observability/src/logging/redaction.ts
|
|
521
|
+
var REDACTED = "[REDACTED]";
|
|
522
|
+
function redactFields(obj, fields, maxDepth = 5) {
|
|
523
|
+
if (fields.length === 0) return obj;
|
|
524
|
+
const lowerFields = new Set(fields.map((f) => f.toLowerCase()));
|
|
525
|
+
return redactRecursive(obj, lowerFields, 0, maxDepth);
|
|
526
|
+
}
|
|
527
|
+
function redactRecursive(obj, fields, depth, maxDepth) {
|
|
528
|
+
if (depth >= maxDepth) return obj;
|
|
529
|
+
const result = {};
|
|
530
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
531
|
+
if (fields.has(key.toLowerCase())) {
|
|
532
|
+
result[key] = REDACTED;
|
|
533
|
+
} else if (isPlainObject(value)) {
|
|
534
|
+
result[key] = redactRecursive(value, fields, depth + 1, maxDepth);
|
|
535
|
+
} else if (Array.isArray(value)) {
|
|
536
|
+
result[key] = value.map(
|
|
537
|
+
(item) => isPlainObject(item) ? redactRecursive(item, fields, depth + 1, maxDepth) : item
|
|
538
|
+
);
|
|
539
|
+
} else {
|
|
540
|
+
result[key] = value;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
return result;
|
|
544
|
+
}
|
|
545
|
+
function isPlainObject(value) {
|
|
546
|
+
if (typeof value !== "object" || value === null) return false;
|
|
547
|
+
const proto = Object.getPrototypeOf(value);
|
|
548
|
+
return proto === Object.prototype || proto === null;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// libs/observability/src/logging/structured-log-transport.ts
|
|
552
|
+
var StructuredLogTransport = class extends LogTransportInterface {
|
|
553
|
+
constructor(sinks, options, contextAccessor) {
|
|
554
|
+
super();
|
|
555
|
+
this.sinks = sinks;
|
|
556
|
+
this.redactFieldNames = options?.redactFields ?? [];
|
|
557
|
+
this.includeStacks = options?.includeStacks ?? true;
|
|
558
|
+
this.staticFields = options?.staticFields ?? {};
|
|
559
|
+
this.getContext = contextAccessor;
|
|
560
|
+
}
|
|
561
|
+
log(rec) {
|
|
562
|
+
const entry = this.buildEntry(rec);
|
|
563
|
+
if (this.onEntry) {
|
|
564
|
+
try {
|
|
565
|
+
this.onEntry(entry);
|
|
566
|
+
} catch {
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
for (const sink of this.sinks) {
|
|
570
|
+
try {
|
|
571
|
+
sink.write(entry);
|
|
572
|
+
} catch {
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
buildEntry(rec) {
|
|
577
|
+
const levelName = LogLevelName[rec.level] ?? "info";
|
|
578
|
+
const entry = {
|
|
579
|
+
...this.staticFields,
|
|
580
|
+
timestamp: rec.timestamp.toISOString(),
|
|
581
|
+
level: levelName,
|
|
582
|
+
severity_number: LOG_LEVEL_TO_OTEL_SEVERITY[levelName] ?? 9,
|
|
583
|
+
message: String(rec.message)
|
|
584
|
+
};
|
|
585
|
+
if (rec.prefix) {
|
|
586
|
+
entry.prefix = rec.prefix;
|
|
587
|
+
}
|
|
588
|
+
const ctx = this.getContext?.();
|
|
589
|
+
if (ctx) {
|
|
590
|
+
entry.trace_id = ctx.traceContext.traceId;
|
|
591
|
+
entry.span_id = ctx.traceContext.parentId;
|
|
592
|
+
entry.trace_flags = ctx.traceContext.traceFlags;
|
|
593
|
+
entry.request_id = ctx.requestId;
|
|
594
|
+
entry.session_id_hash = ctx.sessionIdHash;
|
|
595
|
+
entry.scope_id = ctx.scopeId;
|
|
596
|
+
if (ctx.flowName) {
|
|
597
|
+
entry.flow_name = ctx.flowName;
|
|
598
|
+
}
|
|
599
|
+
entry.elapsed_ms = ctx.elapsed;
|
|
600
|
+
}
|
|
601
|
+
this.processArgs(rec.args, entry);
|
|
602
|
+
return entry;
|
|
603
|
+
}
|
|
604
|
+
processArgs(args, entry) {
|
|
605
|
+
const attributes = {};
|
|
606
|
+
let hasAttributes = false;
|
|
607
|
+
for (const arg of args) {
|
|
608
|
+
if (arg instanceof Error) {
|
|
609
|
+
entry.error = this.buildError(arg);
|
|
610
|
+
} else if (typeof arg === "object" && arg !== null && !Array.isArray(arg)) {
|
|
611
|
+
const obj = arg;
|
|
612
|
+
const redacted = this.redactFieldNames.length > 0 ? redactFields(obj, this.redactFieldNames) : obj;
|
|
613
|
+
Object.assign(attributes, redacted);
|
|
614
|
+
hasAttributes = true;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
if (hasAttributes) {
|
|
618
|
+
entry.attributes = attributes;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
buildError(err) {
|
|
622
|
+
const result = {
|
|
623
|
+
type: err.constructor.name,
|
|
624
|
+
message: err.message
|
|
625
|
+
};
|
|
626
|
+
if ("code" in err && typeof err.code === "number") {
|
|
627
|
+
result.code = String(err.code);
|
|
628
|
+
}
|
|
629
|
+
if ("errorId" in err && typeof err.errorId === "string") {
|
|
630
|
+
result.error_id = err.errorId;
|
|
631
|
+
}
|
|
632
|
+
if (this.includeStacks && err.stack) {
|
|
633
|
+
result.stack = err.stack;
|
|
634
|
+
}
|
|
635
|
+
return result;
|
|
636
|
+
}
|
|
637
|
+
};
|
|
638
|
+
StructuredLogTransport = __decorateClass([
|
|
639
|
+
LogTransport({
|
|
640
|
+
name: "StructuredLogTransport",
|
|
641
|
+
description: "Produces structured log objects and forwards to configurable sinks"
|
|
642
|
+
})
|
|
643
|
+
], StructuredLogTransport);
|
|
644
|
+
|
|
645
|
+
// libs/observability/src/logging/sinks/stdout.sink.ts
|
|
646
|
+
var StdoutSink = class {
|
|
647
|
+
constructor(options) {
|
|
648
|
+
this.stream = options?.stream ?? process.stdout;
|
|
649
|
+
this.pretty = options?.pretty ?? false;
|
|
650
|
+
}
|
|
651
|
+
write(entry) {
|
|
652
|
+
const line = this.pretty ? JSON.stringify(entry, null, 2) : JSON.stringify(entry);
|
|
653
|
+
this.stream.write(line + "\n");
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
|
|
657
|
+
// libs/observability/src/logging/sinks/console.sink.ts
|
|
658
|
+
var ConsoleSink = class {
|
|
659
|
+
write(entry) {
|
|
660
|
+
const method = levelToConsoleMethod(entry.level);
|
|
661
|
+
const formatted = formatEntry(entry);
|
|
662
|
+
method(formatted);
|
|
663
|
+
}
|
|
664
|
+
};
|
|
665
|
+
function formatEntry(entry) {
|
|
666
|
+
const useAnsi = typeof process !== "undefined" && !!process.stdout?.isTTY;
|
|
667
|
+
const ts = entry.timestamp.slice(11, 23);
|
|
668
|
+
const level = entry.level.toUpperCase().padEnd(7);
|
|
669
|
+
const traceShort = entry.trace_id ? entry.trace_id.slice(0, 8) : "";
|
|
670
|
+
const reqShort = entry.request_id ? entry.request_id.slice(0, 8) : "";
|
|
671
|
+
const parts = [];
|
|
672
|
+
const DIM2 = useAnsi ? "\x1B[2m" : "";
|
|
673
|
+
const BOLD2 = useAnsi ? "\x1B[1m" : "";
|
|
674
|
+
const RESET2 = useAnsi ? "\x1B[0m" : "";
|
|
675
|
+
const levelColor = useAnsi ? LEVEL_COLORS[entry.level] ?? "" : "";
|
|
676
|
+
parts.push(`${DIM2}[${ts}]${RESET2}`);
|
|
677
|
+
parts.push(`${BOLD2}${levelColor}${level}${RESET2}`);
|
|
678
|
+
if (traceShort || reqShort) {
|
|
679
|
+
parts.push(`${DIM2}[${traceShort}${reqShort ? ":" + reqShort : ""}]${RESET2}`);
|
|
680
|
+
}
|
|
681
|
+
if (entry.prefix) parts.push(`${DIM2}[${entry.prefix}]${RESET2}`);
|
|
682
|
+
parts.push(entry.message);
|
|
683
|
+
if (entry.attributes && Object.keys(entry.attributes).length > 0) {
|
|
684
|
+
const attrs = Object.entries(entry.attributes).map(([k, v]) => `${k}=${typeof v === "string" ? v : JSON.stringify(v)}`).join(" ");
|
|
685
|
+
parts.push(`${DIM2}{ ${attrs} }${RESET2}`);
|
|
686
|
+
}
|
|
687
|
+
if (entry.error) {
|
|
688
|
+
parts.push(`[${entry.error.type}: ${entry.error.message}]`);
|
|
689
|
+
}
|
|
690
|
+
if (entry.elapsed_ms !== void 0) {
|
|
691
|
+
parts.push(`${DIM2}(${entry.elapsed_ms}ms)${RESET2}`);
|
|
692
|
+
}
|
|
693
|
+
return parts.join(" ");
|
|
694
|
+
}
|
|
695
|
+
var LEVEL_COLORS = {
|
|
696
|
+
debug: "\x1B[34m",
|
|
697
|
+
verbose: "\x1B[90m",
|
|
698
|
+
info: "\x1B[32m",
|
|
699
|
+
warn: "\x1B[33m",
|
|
700
|
+
error: "\x1B[31m"
|
|
701
|
+
};
|
|
702
|
+
function levelToConsoleMethod(level) {
|
|
703
|
+
switch (level) {
|
|
704
|
+
case "debug":
|
|
705
|
+
case "verbose":
|
|
706
|
+
return console.debug;
|
|
707
|
+
case "info":
|
|
708
|
+
return console.info;
|
|
709
|
+
case "warn":
|
|
710
|
+
return console.warn;
|
|
711
|
+
case "error":
|
|
712
|
+
return console.error;
|
|
713
|
+
default:
|
|
714
|
+
return console.log;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// libs/observability/src/logging/sinks/callback.sink.ts
|
|
719
|
+
var CallbackSink = class {
|
|
720
|
+
constructor(fn) {
|
|
721
|
+
this.fn = fn;
|
|
722
|
+
}
|
|
723
|
+
write(entry) {
|
|
724
|
+
this.fn(entry);
|
|
725
|
+
}
|
|
726
|
+
};
|
|
727
|
+
|
|
728
|
+
// libs/observability/src/logging/sink.factory.ts
|
|
729
|
+
function createSink(config) {
|
|
730
|
+
switch (config.type) {
|
|
731
|
+
case "stdout":
|
|
732
|
+
return new StdoutSink({ stream: config.stream, pretty: config.pretty });
|
|
733
|
+
case "console":
|
|
734
|
+
return new ConsoleSink();
|
|
735
|
+
case "winston": {
|
|
736
|
+
const { WinstonSink: WinstonSink2 } = (init_winston_sink(), __toCommonJS(winston_sink_exports));
|
|
737
|
+
return new WinstonSink2(config.logger);
|
|
738
|
+
}
|
|
739
|
+
case "pino": {
|
|
740
|
+
const { PinoSink: PinoSink2 } = (init_pino_sink(), __toCommonJS(pino_sink_exports));
|
|
741
|
+
return new PinoSink2(config.logger);
|
|
742
|
+
}
|
|
743
|
+
case "callback":
|
|
744
|
+
return new CallbackSink(config.fn);
|
|
745
|
+
case "otlp": {
|
|
746
|
+
const { OtlpSink: OtlpSink2 } = (init_otlp_sink(), __toCommonJS(otlp_sink_exports));
|
|
747
|
+
return new OtlpSink2({
|
|
748
|
+
endpoint: config.endpoint ?? (typeof process !== "undefined" ? process.env?.["OTEL_EXPORTER_OTLP_ENDPOINT"] : void 0) ?? "http://localhost:4318",
|
|
749
|
+
headers: config.headers,
|
|
750
|
+
batchSize: config.batchSize,
|
|
751
|
+
flushIntervalMs: config.flushIntervalMs,
|
|
752
|
+
serviceName: config.serviceName
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
default:
|
|
756
|
+
throw new Error(`Unknown sink type: ${config.type}`);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
function createSinks(configs) {
|
|
760
|
+
if (configs && configs.length > 0) {
|
|
761
|
+
return configs.map(createSink);
|
|
762
|
+
}
|
|
763
|
+
return [];
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// libs/observability/src/telemetry/telemetry.accessor.ts
|
|
767
|
+
import {
|
|
768
|
+
SpanKind as SpanKind12,
|
|
769
|
+
SpanStatusCode as SpanStatusCode2,
|
|
770
|
+
trace as trace4
|
|
771
|
+
} from "@opentelemetry/api";
|
|
772
|
+
|
|
773
|
+
// libs/observability/src/otel/trace-context-bridge.ts
|
|
774
|
+
import {
|
|
775
|
+
TraceFlags,
|
|
776
|
+
trace,
|
|
777
|
+
context as otelContext
|
|
778
|
+
} from "@opentelemetry/api";
|
|
779
|
+
function frontmcpToOTelSpanContext(tc) {
|
|
780
|
+
return {
|
|
781
|
+
traceId: tc.traceId,
|
|
782
|
+
spanId: tc.parentId,
|
|
783
|
+
traceFlags: tc.traceFlags & TraceFlags.SAMPLED ? TraceFlags.SAMPLED : TraceFlags.NONE,
|
|
784
|
+
isRemote: true
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
function otelToFrontmcpContext(sc) {
|
|
788
|
+
const flags = sc.traceFlags.toString(16).padStart(2, "0");
|
|
789
|
+
return {
|
|
790
|
+
traceId: sc.traceId,
|
|
791
|
+
parentId: sc.spanId,
|
|
792
|
+
traceFlags: sc.traceFlags,
|
|
793
|
+
raw: `00-${sc.traceId}-${sc.spanId}-${flags}`
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
function createOTelContextFromTrace(tc) {
|
|
797
|
+
const spanContext = frontmcpToOTelSpanContext(tc);
|
|
798
|
+
const span = trace.wrapSpanContext(spanContext);
|
|
799
|
+
return trace.setSpan(otelContext.active(), span);
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// libs/observability/src/plugin/observability.hooks.ts
|
|
803
|
+
import { sha256Hex } from "@frontmcp/utils";
|
|
804
|
+
import {
|
|
805
|
+
SpanKind as SpanKind11,
|
|
806
|
+
trace as trace3,
|
|
807
|
+
context as otelContext3
|
|
808
|
+
} from "@opentelemetry/api";
|
|
809
|
+
|
|
810
|
+
// libs/observability/src/otel/spans/http-server.span.ts
|
|
811
|
+
import { SpanKind as SpanKind2 } from "@opentelemetry/api";
|
|
812
|
+
|
|
813
|
+
// libs/observability/src/otel/otel.types.ts
|
|
814
|
+
var McpAttributes = {
|
|
815
|
+
/** MCP protocol method name (e.g., "tools/call", "resources/read") */
|
|
816
|
+
METHOD_NAME: "mcp.method.name",
|
|
817
|
+
/** MCP session identifier (hashed for privacy) */
|
|
818
|
+
SESSION_ID: "mcp.session.id",
|
|
819
|
+
/** MCP resource URI */
|
|
820
|
+
RESOURCE_URI: "mcp.resource.uri",
|
|
821
|
+
/** MCP component type: "tool" | "resource" | "prompt" | "resource_template" */
|
|
822
|
+
COMPONENT_TYPE: "mcp.component.type",
|
|
823
|
+
/** MCP component key (e.g., "tool:get_weather", "resource:config://db") */
|
|
824
|
+
COMPONENT_KEY: "mcp.component.key"
|
|
825
|
+
};
|
|
826
|
+
var FrontMcpAttributes = {
|
|
827
|
+
/** Scope identifier */
|
|
828
|
+
SCOPE_ID: "frontmcp.scope.id",
|
|
829
|
+
/** Server/scope name */
|
|
830
|
+
SERVER_NAME: "frontmcp.server.name",
|
|
831
|
+
/** Tool name being executed */
|
|
832
|
+
TOOL_NAME: "frontmcp.tool.name",
|
|
833
|
+
/** Tool owner class name */
|
|
834
|
+
TOOL_OWNER: "frontmcp.tool.owner",
|
|
835
|
+
/** Resource URI being read */
|
|
836
|
+
RESOURCE_URI: "frontmcp.resource.uri",
|
|
837
|
+
/** Resource name */
|
|
838
|
+
RESOURCE_NAME: "frontmcp.resource.name",
|
|
839
|
+
/** Prompt name being invoked */
|
|
840
|
+
PROMPT_NAME: "frontmcp.prompt.name",
|
|
841
|
+
/** Flow name (e.g., "tools:call-tool") */
|
|
842
|
+
FLOW_NAME: "frontmcp.flow.name",
|
|
843
|
+
/** Flow stage (e.g., "willExecute") */
|
|
844
|
+
FLOW_STAGE: "frontmcp.flow.stage",
|
|
845
|
+
/** Hook stage (e.g., "willValidateInput") */
|
|
846
|
+
HOOK_STAGE: "frontmcp.hook.stage",
|
|
847
|
+
/** Hook owner identifier */
|
|
848
|
+
HOOK_OWNER: "frontmcp.hook.owner",
|
|
849
|
+
/** Hashed session ID (for trace correlation, not the real session ID) */
|
|
850
|
+
SESSION_ID_HASH: "frontmcp.session.id_hash",
|
|
851
|
+
/** Authentication type */
|
|
852
|
+
AUTH_TYPE: "frontmcp.auth.type",
|
|
853
|
+
/** Request identifier */
|
|
854
|
+
REQUEST_ID: "frontmcp.request.id",
|
|
855
|
+
/** Provider type (e.g., "local", "adapter", "remote") */
|
|
856
|
+
PROVIDER_TYPE: "frontmcp.provider.type",
|
|
857
|
+
/** Delegation — original name before namespacing */
|
|
858
|
+
DELEGATE_ORIGINAL_NAME: "frontmcp.delegate.original_name",
|
|
859
|
+
// ── Transport ──
|
|
860
|
+
/** Transport type: "legacy-sse" | "streamable-http" | "stateless-http" */
|
|
861
|
+
TRANSPORT_TYPE: "frontmcp.transport.type",
|
|
862
|
+
/** Transport request type: "initialize" | "message" | "elicitResult" | "sseListener" | "extApps" */
|
|
863
|
+
TRANSPORT_REQUEST_TYPE: "frontmcp.transport.request_type",
|
|
864
|
+
/** Session protocol */
|
|
865
|
+
SESSION_PROTOCOL: "frontmcp.session.protocol",
|
|
866
|
+
/** Whether a new session was created */
|
|
867
|
+
SESSION_CREATED: "frontmcp.session.created",
|
|
868
|
+
// ── Auth ──
|
|
869
|
+
/** Auth mode: "public" | "transparent" | "orchestrated" */
|
|
870
|
+
AUTH_MODE: "frontmcp.auth.mode",
|
|
871
|
+
/** Auth result: "authorized" | "unauthorized" | "anonymous" */
|
|
872
|
+
AUTH_RESULT: "frontmcp.auth.result",
|
|
873
|
+
// ── OAuth ──
|
|
874
|
+
/** OAuth grant type: "authorization_code" | "refresh_token" | "anonymous" */
|
|
875
|
+
OAUTH_GRANT_TYPE: "frontmcp.oauth.grant_type",
|
|
876
|
+
// ── Elicitation ──
|
|
877
|
+
/** Elicitation request ID */
|
|
878
|
+
ELICITATION_ID: "frontmcp.elicitation.id",
|
|
879
|
+
// ── Agent ──
|
|
880
|
+
/** Agent name */
|
|
881
|
+
AGENT_NAME: "frontmcp.agent.name",
|
|
882
|
+
/** Agent execution loop iterations */
|
|
883
|
+
AGENT_ITERATIONS: "frontmcp.agent.iterations",
|
|
884
|
+
/** Agent execution duration in ms */
|
|
885
|
+
AGENT_EXECUTION_DURATION_MS: "frontmcp.agent.execution_duration_ms",
|
|
886
|
+
// ── Startup ──
|
|
887
|
+
/** Total tools registered at startup */
|
|
888
|
+
STARTUP_TOOLS_COUNT: "frontmcp.startup.tools_count",
|
|
889
|
+
/** Total resources registered at startup */
|
|
890
|
+
STARTUP_RESOURCES_COUNT: "frontmcp.startup.resources_count",
|
|
891
|
+
/** Total prompts registered at startup */
|
|
892
|
+
STARTUP_PROMPTS_COUNT: "frontmcp.startup.prompts_count",
|
|
893
|
+
/** Total plugins loaded at startup */
|
|
894
|
+
STARTUP_PLUGINS_COUNT: "frontmcp.startup.plugins_count",
|
|
895
|
+
/** Startup initialization duration in ms */
|
|
896
|
+
STARTUP_DURATION_MS: "frontmcp.startup.duration_ms"
|
|
897
|
+
};
|
|
898
|
+
var HttpAttributes = {
|
|
899
|
+
METHOD: "http.request.method",
|
|
900
|
+
STATUS_CODE: "http.response.status_code",
|
|
901
|
+
URL_PATH: "url.path",
|
|
902
|
+
URL_FULL: "url.full",
|
|
903
|
+
URL_SCHEME: "url.scheme",
|
|
904
|
+
SERVER_ADDRESS: "server.address",
|
|
905
|
+
SERVER_PORT: "server.port"
|
|
906
|
+
};
|
|
907
|
+
var RpcAttributes = {
|
|
908
|
+
/** RPC system — "mcp" for MCP protocol */
|
|
909
|
+
SYSTEM: "rpc.system",
|
|
910
|
+
/** RPC service name */
|
|
911
|
+
SERVICE: "rpc.service",
|
|
912
|
+
/** RPC method */
|
|
913
|
+
METHOD: "rpc.method",
|
|
914
|
+
/** JSON-RPC version */
|
|
915
|
+
JSONRPC_VERSION: "rpc.jsonrpc.version",
|
|
916
|
+
/** JSON-RPC request ID */
|
|
917
|
+
JSONRPC_REQUEST_ID: "rpc.jsonrpc.request_id"
|
|
918
|
+
};
|
|
919
|
+
var EnduserAttributes = {
|
|
920
|
+
/** Client/user ID from auth token */
|
|
921
|
+
ID: "enduser.id",
|
|
922
|
+
/** OAuth scopes (space-separated) */
|
|
923
|
+
SCOPE: "enduser.scope"
|
|
924
|
+
};
|
|
925
|
+
|
|
926
|
+
// libs/observability/src/otel/spans/span.utils.ts
|
|
927
|
+
import {
|
|
928
|
+
SpanKind,
|
|
929
|
+
SpanStatusCode,
|
|
930
|
+
context as otelContext2,
|
|
931
|
+
trace as trace2
|
|
932
|
+
} from "@opentelemetry/api";
|
|
933
|
+
function startSpan(tracer, options) {
|
|
934
|
+
const parentCtx = options.parentContext ?? otelContext2.active();
|
|
935
|
+
const span = tracer.startSpan(
|
|
936
|
+
options.name,
|
|
937
|
+
{
|
|
938
|
+
kind: options.kind ?? SpanKind.INTERNAL,
|
|
939
|
+
attributes: options.attributes
|
|
940
|
+
},
|
|
941
|
+
parentCtx
|
|
942
|
+
);
|
|
943
|
+
const spanContext = trace2.setSpan(parentCtx, span);
|
|
944
|
+
return { span, context: spanContext };
|
|
945
|
+
}
|
|
946
|
+
function endSpanOk(span) {
|
|
947
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
948
|
+
span.end();
|
|
949
|
+
}
|
|
950
|
+
function endSpanError(span, error) {
|
|
951
|
+
const message = typeof error === "string" ? error : error.message;
|
|
952
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
953
|
+
if (error instanceof Error) {
|
|
954
|
+
span.recordException(error);
|
|
955
|
+
}
|
|
956
|
+
span.end();
|
|
957
|
+
}
|
|
958
|
+
async function withSpan(tracer, options, fn) {
|
|
959
|
+
const { span, context: spanContext } = startSpan(tracer, options);
|
|
960
|
+
return otelContext2.with(spanContext, async () => {
|
|
961
|
+
try {
|
|
962
|
+
const result = await fn(span);
|
|
963
|
+
endSpanOk(span);
|
|
964
|
+
return result;
|
|
965
|
+
} catch (err) {
|
|
966
|
+
endSpanError(span, err instanceof Error ? err : String(err));
|
|
967
|
+
throw err;
|
|
968
|
+
}
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
// libs/observability/src/otel/spans/http-server.span.ts
|
|
973
|
+
function startHttpServerSpan(tracer, options) {
|
|
974
|
+
const attributes = {
|
|
975
|
+
[HttpAttributes.METHOD]: options.method.toUpperCase(),
|
|
976
|
+
[HttpAttributes.URL_PATH]: options.path
|
|
977
|
+
};
|
|
978
|
+
if (options.scheme) {
|
|
979
|
+
attributes[HttpAttributes.URL_SCHEME] = options.scheme;
|
|
980
|
+
}
|
|
981
|
+
if (options.serverAddress) {
|
|
982
|
+
attributes[HttpAttributes.SERVER_ADDRESS] = options.serverAddress;
|
|
983
|
+
}
|
|
984
|
+
if (options.serverPort) {
|
|
985
|
+
attributes[HttpAttributes.SERVER_PORT] = options.serverPort;
|
|
986
|
+
}
|
|
987
|
+
if (options.scopeId) {
|
|
988
|
+
attributes[FrontMcpAttributes.SCOPE_ID] = options.scopeId;
|
|
989
|
+
}
|
|
990
|
+
if (options.requestId) {
|
|
991
|
+
attributes[FrontMcpAttributes.REQUEST_ID] = options.requestId;
|
|
992
|
+
}
|
|
993
|
+
return startSpan(tracer, {
|
|
994
|
+
name: `${options.method.toUpperCase()} ${options.path}`,
|
|
995
|
+
kind: SpanKind2.SERVER,
|
|
996
|
+
attributes,
|
|
997
|
+
parentContext: options.parentContext
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
function setHttpResponseStatus(span, statusCode) {
|
|
1001
|
+
span.setAttribute(HttpAttributes.STATUS_CODE, statusCode);
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
// libs/observability/src/otel/spans/rpc.span.ts
|
|
1005
|
+
import { SpanKind as SpanKind3 } from "@opentelemetry/api";
|
|
1006
|
+
function startRpcSpan(tracer, options) {
|
|
1007
|
+
const attributes = {
|
|
1008
|
+
[RpcAttributes.SYSTEM]: "mcp",
|
|
1009
|
+
[RpcAttributes.METHOD]: options.method,
|
|
1010
|
+
[RpcAttributes.JSONRPC_VERSION]: "2.0",
|
|
1011
|
+
[McpAttributes.METHOD_NAME]: options.method
|
|
1012
|
+
};
|
|
1013
|
+
if (options.requestId !== void 0) {
|
|
1014
|
+
attributes[RpcAttributes.JSONRPC_REQUEST_ID] = String(options.requestId);
|
|
1015
|
+
}
|
|
1016
|
+
if (options.scopeId) {
|
|
1017
|
+
attributes[FrontMcpAttributes.SCOPE_ID] = options.scopeId;
|
|
1018
|
+
}
|
|
1019
|
+
if (options.serviceName) {
|
|
1020
|
+
attributes[RpcAttributes.SERVICE] = options.serviceName;
|
|
1021
|
+
attributes[FrontMcpAttributes.SERVER_NAME] = options.serviceName;
|
|
1022
|
+
}
|
|
1023
|
+
if (options.sessionIdHash) {
|
|
1024
|
+
attributes[McpAttributes.SESSION_ID] = options.sessionIdHash;
|
|
1025
|
+
attributes[FrontMcpAttributes.SESSION_ID_HASH] = options.sessionIdHash;
|
|
1026
|
+
}
|
|
1027
|
+
return startSpan(tracer, {
|
|
1028
|
+
name: options.method,
|
|
1029
|
+
kind: SpanKind3.SERVER,
|
|
1030
|
+
attributes,
|
|
1031
|
+
parentContext: options.parentContext
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
// libs/observability/src/otel/spans/tool.span.ts
|
|
1036
|
+
import { SpanKind as SpanKind4 } from "@opentelemetry/api";
|
|
1037
|
+
function startToolSpan(tracer, options) {
|
|
1038
|
+
const attributes = {
|
|
1039
|
+
[FrontMcpAttributes.TOOL_NAME]: options.name,
|
|
1040
|
+
[McpAttributes.COMPONENT_TYPE]: "tool",
|
|
1041
|
+
[McpAttributes.COMPONENT_KEY]: `tool:${options.name}`
|
|
1042
|
+
};
|
|
1043
|
+
if (options.owner) {
|
|
1044
|
+
attributes[FrontMcpAttributes.TOOL_OWNER] = options.owner;
|
|
1045
|
+
}
|
|
1046
|
+
if (options.enduserId) {
|
|
1047
|
+
attributes[EnduserAttributes.ID] = options.enduserId;
|
|
1048
|
+
}
|
|
1049
|
+
if (options.enduserScope) {
|
|
1050
|
+
attributes[EnduserAttributes.SCOPE] = options.enduserScope;
|
|
1051
|
+
}
|
|
1052
|
+
return startSpan(tracer, {
|
|
1053
|
+
name: `tool ${options.name}`,
|
|
1054
|
+
kind: SpanKind4.INTERNAL,
|
|
1055
|
+
attributes,
|
|
1056
|
+
parentContext: options.parentContext
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
// libs/observability/src/otel/spans/resource.span.ts
|
|
1061
|
+
import { SpanKind as SpanKind5 } from "@opentelemetry/api";
|
|
1062
|
+
function startResourceSpan(tracer, options) {
|
|
1063
|
+
const attributes = {
|
|
1064
|
+
[FrontMcpAttributes.RESOURCE_URI]: options.uri,
|
|
1065
|
+
[McpAttributes.RESOURCE_URI]: options.uri,
|
|
1066
|
+
[McpAttributes.COMPONENT_TYPE]: "resource",
|
|
1067
|
+
[McpAttributes.COMPONENT_KEY]: `resource:${options.uri}`
|
|
1068
|
+
};
|
|
1069
|
+
if (options.name) {
|
|
1070
|
+
attributes[FrontMcpAttributes.RESOURCE_NAME] = options.name;
|
|
1071
|
+
}
|
|
1072
|
+
return startSpan(tracer, {
|
|
1073
|
+
name: `resource ${options.uri}`,
|
|
1074
|
+
kind: SpanKind5.INTERNAL,
|
|
1075
|
+
attributes,
|
|
1076
|
+
parentContext: options.parentContext
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
// libs/observability/src/otel/spans/prompt.span.ts
|
|
1081
|
+
import { SpanKind as SpanKind6 } from "@opentelemetry/api";
|
|
1082
|
+
function startPromptSpan(tracer, options) {
|
|
1083
|
+
return startSpan(tracer, {
|
|
1084
|
+
name: `prompt ${options.name}`,
|
|
1085
|
+
kind: SpanKind6.INTERNAL,
|
|
1086
|
+
attributes: {
|
|
1087
|
+
[FrontMcpAttributes.PROMPT_NAME]: options.name,
|
|
1088
|
+
[McpAttributes.COMPONENT_TYPE]: "prompt",
|
|
1089
|
+
[McpAttributes.COMPONENT_KEY]: `prompt:${options.name}`
|
|
1090
|
+
},
|
|
1091
|
+
parentContext: options.parentContext
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// libs/observability/src/otel/spans/transport.span.ts
|
|
1096
|
+
import { SpanKind as SpanKind7 } from "@opentelemetry/api";
|
|
1097
|
+
function startTransportSpan(tracer, options) {
|
|
1098
|
+
const attributes = {
|
|
1099
|
+
[FrontMcpAttributes.TRANSPORT_TYPE]: options.type
|
|
1100
|
+
};
|
|
1101
|
+
if (options.sessionIdHash) {
|
|
1102
|
+
attributes[FrontMcpAttributes.SESSION_ID_HASH] = options.sessionIdHash;
|
|
1103
|
+
}
|
|
1104
|
+
if (options.sessionCreated !== void 0) {
|
|
1105
|
+
attributes[FrontMcpAttributes.SESSION_CREATED] = options.sessionCreated;
|
|
1106
|
+
}
|
|
1107
|
+
return startSpan(tracer, {
|
|
1108
|
+
name: `transport ${options.type}`,
|
|
1109
|
+
kind: SpanKind7.INTERNAL,
|
|
1110
|
+
attributes,
|
|
1111
|
+
parentContext: options.parentContext
|
|
1112
|
+
});
|
|
1113
|
+
}
|
|
1114
|
+
function setTransportRequestType(span, requestType) {
|
|
1115
|
+
span.setAttribute(FrontMcpAttributes.TRANSPORT_REQUEST_TYPE, requestType);
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
// libs/observability/src/otel/spans/auth.span.ts
|
|
1119
|
+
import { SpanKind as SpanKind8 } from "@opentelemetry/api";
|
|
1120
|
+
function startAuthSpan(tracer, options) {
|
|
1121
|
+
return startSpan(tracer, {
|
|
1122
|
+
name: `auth ${options.flowName}`,
|
|
1123
|
+
kind: SpanKind8.INTERNAL,
|
|
1124
|
+
attributes: {
|
|
1125
|
+
[FrontMcpAttributes.FLOW_NAME]: options.flowName
|
|
1126
|
+
},
|
|
1127
|
+
parentContext: options.parentContext
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
function setAuthMode(span, mode) {
|
|
1131
|
+
span.setAttribute(FrontMcpAttributes.AUTH_MODE, mode);
|
|
1132
|
+
}
|
|
1133
|
+
function setAuthResult(span, result) {
|
|
1134
|
+
span.setAttribute(FrontMcpAttributes.AUTH_RESULT, result);
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
// libs/observability/src/otel/spans/fetch.span.ts
|
|
1138
|
+
import { SpanKind as SpanKind9 } from "@opentelemetry/api";
|
|
1139
|
+
function startFetchSpan(tracer, options) {
|
|
1140
|
+
return startSpan(tracer, {
|
|
1141
|
+
name: options.method.toUpperCase(),
|
|
1142
|
+
kind: SpanKind9.CLIENT,
|
|
1143
|
+
attributes: {
|
|
1144
|
+
[HttpAttributes.METHOD]: options.method.toUpperCase(),
|
|
1145
|
+
[HttpAttributes.URL_FULL]: options.url
|
|
1146
|
+
},
|
|
1147
|
+
parentContext: options.parentContext
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
function setFetchResponseStatus(span, statusCode) {
|
|
1151
|
+
span.setAttribute(HttpAttributes.STATUS_CODE, statusCode);
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
// libs/observability/src/otel/spans/startup.span.ts
|
|
1155
|
+
import { SpanKind as SpanKind10 } from "@opentelemetry/api";
|
|
1156
|
+
function emitStartupReport(tracer, data) {
|
|
1157
|
+
const attributes = {
|
|
1158
|
+
[FrontMcpAttributes.STARTUP_TOOLS_COUNT]: data.toolsCount,
|
|
1159
|
+
[FrontMcpAttributes.STARTUP_RESOURCES_COUNT]: data.resourcesCount,
|
|
1160
|
+
[FrontMcpAttributes.STARTUP_PROMPTS_COUNT]: data.promptsCount,
|
|
1161
|
+
[FrontMcpAttributes.STARTUP_PLUGINS_COUNT]: data.pluginsCount,
|
|
1162
|
+
[FrontMcpAttributes.STARTUP_DURATION_MS]: data.durationMs
|
|
1163
|
+
};
|
|
1164
|
+
if (data.scopeId) {
|
|
1165
|
+
attributes[FrontMcpAttributes.SCOPE_ID] = data.scopeId;
|
|
1166
|
+
}
|
|
1167
|
+
const { span } = startSpan(tracer, {
|
|
1168
|
+
name: "frontmcp.startup",
|
|
1169
|
+
kind: SpanKind10.INTERNAL,
|
|
1170
|
+
attributes
|
|
1171
|
+
});
|
|
1172
|
+
endSpanOk(span);
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
// libs/observability/src/plugin/observability.hooks.ts
|
|
1176
|
+
var SPAN_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:span");
|
|
1177
|
+
var SPAN_CTX_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:span-ctx");
|
|
1178
|
+
var EXEC_SPAN_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:exec-span");
|
|
1179
|
+
var ACTIVE_SPAN_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:active-span");
|
|
1180
|
+
var ACTIVE_OTEL_CTX_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:active-otel-ctx");
|
|
1181
|
+
var STAGE_TS_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:stage-ts");
|
|
1182
|
+
function sessionTracingId(sessionId) {
|
|
1183
|
+
return sha256Hex(sessionId).slice(0, 16);
|
|
1184
|
+
}
|
|
1185
|
+
function getTracer() {
|
|
1186
|
+
return trace3.getTracer("@frontmcp/observability");
|
|
1187
|
+
}
|
|
1188
|
+
function extractContext(flowCtx) {
|
|
1189
|
+
try {
|
|
1190
|
+
const ctx = flowCtx.get?.(/* @__PURE__ */ Symbol.for("frontmcp:CONTEXT"));
|
|
1191
|
+
if (ctx) return ctx;
|
|
1192
|
+
} catch {
|
|
1193
|
+
}
|
|
1194
|
+
return flowCtx.state?.ctx ?? flowCtx.state?.frontmcpContext;
|
|
1195
|
+
}
|
|
1196
|
+
function storeActiveSpan(flowCtx, span, otelCtx) {
|
|
1197
|
+
try {
|
|
1198
|
+
const ctx = flowCtx.get?.(/* @__PURE__ */ Symbol.for("frontmcp:CONTEXT"));
|
|
1199
|
+
if (ctx && typeof ctx.set === "function") {
|
|
1200
|
+
ctx.set(ACTIVE_SPAN_KEY, span);
|
|
1201
|
+
ctx.set(ACTIVE_OTEL_CTX_KEY, otelCtx);
|
|
1202
|
+
}
|
|
1203
|
+
} catch {
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
function clearActiveSpan(flowCtx) {
|
|
1207
|
+
try {
|
|
1208
|
+
const ctx = flowCtx.get?.(/* @__PURE__ */ Symbol.for("frontmcp:CONTEXT"));
|
|
1209
|
+
if (ctx && typeof ctx.delete === "function") {
|
|
1210
|
+
ctx.delete(ACTIVE_SPAN_KEY);
|
|
1211
|
+
ctx.delete(ACTIVE_OTEL_CTX_KEY);
|
|
1212
|
+
}
|
|
1213
|
+
} catch {
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
function recordStageEvent(span, stageName, state) {
|
|
1217
|
+
const now = Date.now();
|
|
1218
|
+
const prev = state[STAGE_TS_KEY];
|
|
1219
|
+
const attributes = {};
|
|
1220
|
+
if (prev) {
|
|
1221
|
+
attributes["duration_ms"] = now - prev;
|
|
1222
|
+
}
|
|
1223
|
+
state[STAGE_TS_KEY] = now;
|
|
1224
|
+
span.addEvent(`stage.${stageName}`, attributes);
|
|
1225
|
+
}
|
|
1226
|
+
function onHttpWillTrace(options, flowCtx) {
|
|
1227
|
+
if (options.httpSpans === false) return;
|
|
1228
|
+
const ctx = extractContext(flowCtx);
|
|
1229
|
+
if (!ctx) return;
|
|
1230
|
+
const tracer = getTracer();
|
|
1231
|
+
const parentOTelCtx = createOTelContextFromTrace(ctx.traceContext);
|
|
1232
|
+
const sessionHash = sessionTracingId(ctx.sessionId);
|
|
1233
|
+
const { span, context: spanCtx } = startHttpServerSpan(tracer, {
|
|
1234
|
+
method: ctx.metadata?.customHeaders?.["x-http-method"] ?? "POST",
|
|
1235
|
+
path: ctx.metadata?.customHeaders?.["x-url-path"] ?? "/",
|
|
1236
|
+
scopeId: ctx.scopeId,
|
|
1237
|
+
requestId: ctx.requestId,
|
|
1238
|
+
parentContext: parentOTelCtx
|
|
1239
|
+
});
|
|
1240
|
+
span.setAttribute(McpAttributes.SESSION_ID, sessionHash);
|
|
1241
|
+
span.setAttribute(FrontMcpAttributes.SESSION_ID_HASH, sessionHash);
|
|
1242
|
+
flowCtx.state[SPAN_KEY] = span;
|
|
1243
|
+
flowCtx.state[SPAN_CTX_KEY] = spanCtx;
|
|
1244
|
+
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1245
|
+
recordStageEvent(span, "traceRequest", flowCtx.state);
|
|
1246
|
+
}
|
|
1247
|
+
function onHttpWillAcquireQuota(flowCtx) {
|
|
1248
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1249
|
+
if (span) recordStageEvent(span, "acquireQuota", flowCtx.state);
|
|
1250
|
+
}
|
|
1251
|
+
function onHttpDidAcquireQuota(flowCtx) {
|
|
1252
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1253
|
+
if (span) recordStageEvent(span, "acquireQuota.done", flowCtx.state);
|
|
1254
|
+
}
|
|
1255
|
+
function onHttpWillCheckAuth(flowCtx) {
|
|
1256
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1257
|
+
if (span) recordStageEvent(span, "checkAuthorization", flowCtx.state);
|
|
1258
|
+
}
|
|
1259
|
+
function onHttpDidCheckAuth(flowCtx) {
|
|
1260
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1261
|
+
if (span) recordStageEvent(span, "checkAuthorization.done", flowCtx.state);
|
|
1262
|
+
}
|
|
1263
|
+
function onHttpWillRoute(flowCtx) {
|
|
1264
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1265
|
+
if (span) recordStageEvent(span, "router", flowCtx.state);
|
|
1266
|
+
}
|
|
1267
|
+
function onHttpDidRoute(flowCtx) {
|
|
1268
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1269
|
+
if (span) recordStageEvent(span, "router.done", flowCtx.state);
|
|
1270
|
+
}
|
|
1271
|
+
function onHttpDidFinalize(flowCtx) {
|
|
1272
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1273
|
+
if (!span) return;
|
|
1274
|
+
recordStageEvent(span, "finalize", flowCtx.state);
|
|
1275
|
+
const statusCode = flowCtx.state?.statusCode ?? 200;
|
|
1276
|
+
setHttpResponseStatus(span, statusCode);
|
|
1277
|
+
if (statusCode >= 400) {
|
|
1278
|
+
endSpanError(span, `HTTP ${statusCode}`);
|
|
1279
|
+
} else {
|
|
1280
|
+
endSpanOk(span);
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
function onToolWillParse(options, flowCtx) {
|
|
1284
|
+
if (options.executionSpans === false) return;
|
|
1285
|
+
const ctx = extractContext(flowCtx);
|
|
1286
|
+
if (!ctx) return;
|
|
1287
|
+
const tracer = getTracer();
|
|
1288
|
+
const parentOTelCtx = createOTelContextFromTrace(ctx.traceContext);
|
|
1289
|
+
const sessionHash = sessionTracingId(ctx.sessionId);
|
|
1290
|
+
const { span, context: spanCtx } = startRpcSpan(tracer, {
|
|
1291
|
+
method: "tools/call",
|
|
1292
|
+
scopeId: ctx.scopeId,
|
|
1293
|
+
sessionIdHash: sessionHash,
|
|
1294
|
+
parentContext: parentOTelCtx
|
|
1295
|
+
});
|
|
1296
|
+
flowCtx.state[SPAN_KEY] = span;
|
|
1297
|
+
flowCtx.state[SPAN_CTX_KEY] = spanCtx;
|
|
1298
|
+
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1299
|
+
recordStageEvent(span, "parseInput", flowCtx.state);
|
|
1300
|
+
}
|
|
1301
|
+
function onToolWillFindTool(flowCtx) {
|
|
1302
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1303
|
+
if (span) recordStageEvent(span, "findTool", flowCtx.state);
|
|
1304
|
+
}
|
|
1305
|
+
function onToolWillCheckAuth(flowCtx) {
|
|
1306
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1307
|
+
if (span) recordStageEvent(span, "checkToolAuthorization", flowCtx.state);
|
|
1308
|
+
}
|
|
1309
|
+
function onToolWillCreateContext(flowCtx) {
|
|
1310
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1311
|
+
if (span) recordStageEvent(span, "createToolCallContext", flowCtx.state);
|
|
1312
|
+
}
|
|
1313
|
+
function onToolWillValidateInput(flowCtx) {
|
|
1314
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1315
|
+
if (span) recordStageEvent(span, "validateInput", flowCtx.state);
|
|
1316
|
+
}
|
|
1317
|
+
function onToolWillExecute(options, flowCtx) {
|
|
1318
|
+
if (options.executionSpans === false) return;
|
|
1319
|
+
const ctx = extractContext(flowCtx);
|
|
1320
|
+
const rpcCtx = flowCtx.state?.[SPAN_CTX_KEY];
|
|
1321
|
+
const tracer = getTracer();
|
|
1322
|
+
const toolName = flowCtx.state?.input?.name ?? "unknown";
|
|
1323
|
+
const toolOwner = flowCtx.state?._toolOwnerId;
|
|
1324
|
+
const enduser = ctx?.authInfo;
|
|
1325
|
+
const { span: toolSpan, context: toolOTelCtx } = startToolSpan(tracer, {
|
|
1326
|
+
name: toolName,
|
|
1327
|
+
owner: toolOwner,
|
|
1328
|
+
enduserId: enduser?.clientId ?? enduser?.extra?.sub,
|
|
1329
|
+
enduserScope: Array.isArray(enduser?.scopes) ? enduser.scopes.join(" ") : void 0,
|
|
1330
|
+
parentContext: rpcCtx
|
|
1331
|
+
});
|
|
1332
|
+
flowCtx.state[EXEC_SPAN_KEY] = toolSpan;
|
|
1333
|
+
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1334
|
+
recordStageEvent(toolSpan, "execute.start", flowCtx.state);
|
|
1335
|
+
storeActiveSpan(flowCtx, toolSpan, toolOTelCtx);
|
|
1336
|
+
}
|
|
1337
|
+
function onToolDidExecute(options, flowCtx) {
|
|
1338
|
+
const toolSpan = flowCtx.state?.[EXEC_SPAN_KEY];
|
|
1339
|
+
if (!toolSpan) return;
|
|
1340
|
+
recordStageEvent(toolSpan, "execute.done", flowCtx.state);
|
|
1341
|
+
endSpanOk(toolSpan);
|
|
1342
|
+
flowCtx.state[EXEC_SPAN_KEY] = void 0;
|
|
1343
|
+
clearActiveSpan(flowCtx);
|
|
1344
|
+
}
|
|
1345
|
+
function onToolWillValidateOutput(flowCtx) {
|
|
1346
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1347
|
+
if (span) recordStageEvent(span, "validateOutput", flowCtx.state);
|
|
1348
|
+
}
|
|
1349
|
+
function onToolWillApplyUI(flowCtx) {
|
|
1350
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1351
|
+
if (span) recordStageEvent(span, "applyUI", flowCtx.state);
|
|
1352
|
+
}
|
|
1353
|
+
function onToolDidFinalize(flowCtx) {
|
|
1354
|
+
const rpcSpan = flowCtx.state?.[SPAN_KEY];
|
|
1355
|
+
const toolSpan = flowCtx.state?.[EXEC_SPAN_KEY];
|
|
1356
|
+
const error = flowCtx.state?.error;
|
|
1357
|
+
if (error) {
|
|
1358
|
+
if (toolSpan) endSpanError(toolSpan, error instanceof Error ? error : String(error));
|
|
1359
|
+
if (rpcSpan) endSpanError(rpcSpan, error instanceof Error ? error : String(error));
|
|
1360
|
+
} else if (rpcSpan) {
|
|
1361
|
+
recordStageEvent(rpcSpan, "finalize", flowCtx.state);
|
|
1362
|
+
endSpanOk(rpcSpan);
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
function onResourceWillParse(options, flowCtx) {
|
|
1366
|
+
if (options.executionSpans === false) return;
|
|
1367
|
+
const ctx = extractContext(flowCtx);
|
|
1368
|
+
if (!ctx) return;
|
|
1369
|
+
const tracer = getTracer();
|
|
1370
|
+
const parentOTelCtx = createOTelContextFromTrace(ctx.traceContext);
|
|
1371
|
+
const sessionHash = sessionTracingId(ctx.sessionId);
|
|
1372
|
+
const { span, context: spanCtx } = startRpcSpan(tracer, {
|
|
1373
|
+
method: "resources/read",
|
|
1374
|
+
scopeId: ctx.scopeId,
|
|
1375
|
+
sessionIdHash: sessionHash,
|
|
1376
|
+
parentContext: parentOTelCtx
|
|
1377
|
+
});
|
|
1378
|
+
flowCtx.state[SPAN_KEY] = span;
|
|
1379
|
+
flowCtx.state[SPAN_CTX_KEY] = spanCtx;
|
|
1380
|
+
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1381
|
+
recordStageEvent(span, "parseInput", flowCtx.state);
|
|
1382
|
+
}
|
|
1383
|
+
function onResourceWillFind(flowCtx) {
|
|
1384
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1385
|
+
if (span) recordStageEvent(span, "findResource", flowCtx.state);
|
|
1386
|
+
}
|
|
1387
|
+
function onResourceWillExecute(options, flowCtx) {
|
|
1388
|
+
if (options.executionSpans === false) return;
|
|
1389
|
+
const rpcCtx = flowCtx.state?.[SPAN_CTX_KEY];
|
|
1390
|
+
const tracer = getTracer();
|
|
1391
|
+
const uri = flowCtx.state?.input?.uri ?? "unknown";
|
|
1392
|
+
const { span: resSpan, context: resOTelCtx } = startResourceSpan(tracer, { uri, parentContext: rpcCtx });
|
|
1393
|
+
flowCtx.state[EXEC_SPAN_KEY] = resSpan;
|
|
1394
|
+
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1395
|
+
recordStageEvent(resSpan, "execute.start", flowCtx.state);
|
|
1396
|
+
storeActiveSpan(flowCtx, resSpan, resOTelCtx);
|
|
1397
|
+
}
|
|
1398
|
+
function onResourceDidExecute(flowCtx) {
|
|
1399
|
+
const resSpan = flowCtx.state?.[EXEC_SPAN_KEY];
|
|
1400
|
+
if (!resSpan) return;
|
|
1401
|
+
recordStageEvent(resSpan, "execute.done", flowCtx.state);
|
|
1402
|
+
endSpanOk(resSpan);
|
|
1403
|
+
flowCtx.state[EXEC_SPAN_KEY] = void 0;
|
|
1404
|
+
clearActiveSpan(flowCtx);
|
|
1405
|
+
}
|
|
1406
|
+
function onResourceDidFinalize(flowCtx) {
|
|
1407
|
+
const rpcSpan = flowCtx.state?.[SPAN_KEY];
|
|
1408
|
+
const resSpan = flowCtx.state?.[EXEC_SPAN_KEY];
|
|
1409
|
+
const error = flowCtx.state?.error;
|
|
1410
|
+
if (error) {
|
|
1411
|
+
if (resSpan) endSpanError(resSpan, error instanceof Error ? error : String(error));
|
|
1412
|
+
if (rpcSpan) endSpanError(rpcSpan, error instanceof Error ? error : String(error));
|
|
1413
|
+
} else if (rpcSpan) {
|
|
1414
|
+
recordStageEvent(rpcSpan, "finalize", flowCtx.state);
|
|
1415
|
+
endSpanOk(rpcSpan);
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
function onPromptWillParse(options, flowCtx) {
|
|
1419
|
+
if (options.executionSpans === false) return;
|
|
1420
|
+
const ctx = extractContext(flowCtx);
|
|
1421
|
+
if (!ctx) return;
|
|
1422
|
+
const tracer = getTracer();
|
|
1423
|
+
const parentOTelCtx = createOTelContextFromTrace(ctx.traceContext);
|
|
1424
|
+
const sessionHash = sessionTracingId(ctx.sessionId);
|
|
1425
|
+
const { span, context: spanCtx } = startRpcSpan(tracer, {
|
|
1426
|
+
method: "prompts/get",
|
|
1427
|
+
scopeId: ctx.scopeId,
|
|
1428
|
+
sessionIdHash: sessionHash,
|
|
1429
|
+
parentContext: parentOTelCtx
|
|
1430
|
+
});
|
|
1431
|
+
flowCtx.state[SPAN_KEY] = span;
|
|
1432
|
+
flowCtx.state[SPAN_CTX_KEY] = spanCtx;
|
|
1433
|
+
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1434
|
+
recordStageEvent(span, "parseInput", flowCtx.state);
|
|
1435
|
+
}
|
|
1436
|
+
function onPromptWillFind(flowCtx) {
|
|
1437
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1438
|
+
if (span) recordStageEvent(span, "findPrompt", flowCtx.state);
|
|
1439
|
+
}
|
|
1440
|
+
function onPromptWillExecute(options, flowCtx) {
|
|
1441
|
+
if (options.executionSpans === false) return;
|
|
1442
|
+
const rpcCtx = flowCtx.state?.[SPAN_CTX_KEY];
|
|
1443
|
+
const tracer = getTracer();
|
|
1444
|
+
const promptName = flowCtx.state?.input?.name ?? "unknown";
|
|
1445
|
+
const { span: promptSpan, context: promptOTelCtx } = startPromptSpan(tracer, {
|
|
1446
|
+
name: promptName,
|
|
1447
|
+
parentContext: rpcCtx
|
|
1448
|
+
});
|
|
1449
|
+
flowCtx.state[EXEC_SPAN_KEY] = promptSpan;
|
|
1450
|
+
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1451
|
+
recordStageEvent(promptSpan, "execute.start", flowCtx.state);
|
|
1452
|
+
storeActiveSpan(flowCtx, promptSpan, promptOTelCtx);
|
|
1453
|
+
}
|
|
1454
|
+
function onPromptDidExecute(flowCtx) {
|
|
1455
|
+
const promptSpan = flowCtx.state?.[EXEC_SPAN_KEY];
|
|
1456
|
+
if (!promptSpan) return;
|
|
1457
|
+
recordStageEvent(promptSpan, "execute.done", flowCtx.state);
|
|
1458
|
+
endSpanOk(promptSpan);
|
|
1459
|
+
flowCtx.state[EXEC_SPAN_KEY] = void 0;
|
|
1460
|
+
clearActiveSpan(flowCtx);
|
|
1461
|
+
}
|
|
1462
|
+
function onPromptDidFinalize(flowCtx) {
|
|
1463
|
+
const rpcSpan = flowCtx.state?.[SPAN_KEY];
|
|
1464
|
+
const promptSpan = flowCtx.state?.[EXEC_SPAN_KEY];
|
|
1465
|
+
const error = flowCtx.state?.error;
|
|
1466
|
+
if (error) {
|
|
1467
|
+
if (promptSpan) endSpanError(promptSpan, error instanceof Error ? error : String(error));
|
|
1468
|
+
if (rpcSpan) endSpanError(rpcSpan, error instanceof Error ? error : String(error));
|
|
1469
|
+
} else if (rpcSpan) {
|
|
1470
|
+
recordStageEvent(rpcSpan, "finalize", flowCtx.state);
|
|
1471
|
+
endSpanOk(rpcSpan);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
function onAgentWillParse(options, flowCtx) {
|
|
1475
|
+
if (options.executionSpans === false) return;
|
|
1476
|
+
const ctx = extractContext(flowCtx);
|
|
1477
|
+
if (!ctx) return;
|
|
1478
|
+
const tracer = getTracer();
|
|
1479
|
+
const parentOTelCtx = createOTelContextFromTrace(ctx.traceContext);
|
|
1480
|
+
const sessionHash = sessionTracingId(ctx.sessionId);
|
|
1481
|
+
const { span, context: spanCtx } = startRpcSpan(tracer, {
|
|
1482
|
+
method: "agents/call",
|
|
1483
|
+
scopeId: ctx.scopeId,
|
|
1484
|
+
sessionIdHash: sessionHash,
|
|
1485
|
+
parentContext: parentOTelCtx
|
|
1486
|
+
});
|
|
1487
|
+
flowCtx.state[SPAN_KEY] = span;
|
|
1488
|
+
flowCtx.state[SPAN_CTX_KEY] = spanCtx;
|
|
1489
|
+
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1490
|
+
recordStageEvent(span, "parseInput", flowCtx.state);
|
|
1491
|
+
}
|
|
1492
|
+
function onAgentWillFind(flowCtx) {
|
|
1493
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1494
|
+
if (span) recordStageEvent(span, "findAgent", flowCtx.state);
|
|
1495
|
+
}
|
|
1496
|
+
function onAgentWillExecute(options, flowCtx) {
|
|
1497
|
+
if (options.executionSpans === false) return;
|
|
1498
|
+
const rpcCtx = flowCtx.state?.[SPAN_CTX_KEY];
|
|
1499
|
+
const tracer = getTracer();
|
|
1500
|
+
const agentName = flowCtx.state?.input?.name ?? "unknown";
|
|
1501
|
+
const { span: agentSpan } = startSpan(tracer, {
|
|
1502
|
+
name: `agent ${agentName}`,
|
|
1503
|
+
kind: SpanKind11.INTERNAL,
|
|
1504
|
+
attributes: {
|
|
1505
|
+
[FrontMcpAttributes.FLOW_NAME]: "agents:call-agent",
|
|
1506
|
+
[McpAttributes.COMPONENT_TYPE]: "agent",
|
|
1507
|
+
[McpAttributes.COMPONENT_KEY]: `agent:${agentName}`
|
|
1508
|
+
},
|
|
1509
|
+
parentContext: rpcCtx
|
|
1510
|
+
});
|
|
1511
|
+
const agentOTelCtx = trace3.setSpan(rpcCtx ?? otelContext3.active(), agentSpan);
|
|
1512
|
+
flowCtx.state[EXEC_SPAN_KEY] = agentSpan;
|
|
1513
|
+
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1514
|
+
recordStageEvent(agentSpan, "execute.start", flowCtx.state);
|
|
1515
|
+
storeActiveSpan(flowCtx, agentSpan, agentOTelCtx);
|
|
1516
|
+
}
|
|
1517
|
+
function onAgentDidExecute(flowCtx) {
|
|
1518
|
+
const agentSpan = flowCtx.state?.[EXEC_SPAN_KEY];
|
|
1519
|
+
if (!agentSpan) return;
|
|
1520
|
+
recordStageEvent(agentSpan, "execute.done", flowCtx.state);
|
|
1521
|
+
endSpanOk(agentSpan);
|
|
1522
|
+
flowCtx.state[EXEC_SPAN_KEY] = void 0;
|
|
1523
|
+
clearActiveSpan(flowCtx);
|
|
1524
|
+
}
|
|
1525
|
+
function onAgentDidFinalize(flowCtx) {
|
|
1526
|
+
const rpcSpan = flowCtx.state?.[SPAN_KEY];
|
|
1527
|
+
const agentSpan = flowCtx.state?.[EXEC_SPAN_KEY];
|
|
1528
|
+
const error = flowCtx.state?.error;
|
|
1529
|
+
if (error) {
|
|
1530
|
+
if (agentSpan) endSpanError(agentSpan, error instanceof Error ? error : String(error));
|
|
1531
|
+
if (rpcSpan) endSpanError(rpcSpan, error instanceof Error ? error : String(error));
|
|
1532
|
+
} else if (rpcSpan) {
|
|
1533
|
+
recordStageEvent(rpcSpan, "finalize", flowCtx.state);
|
|
1534
|
+
endSpanOk(rpcSpan);
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
function onGenericFlowWillStart(flowName, options, flowCtx) {
|
|
1538
|
+
if (options.executionSpans === false) return;
|
|
1539
|
+
const ctx = extractContext(flowCtx);
|
|
1540
|
+
if (!ctx) return;
|
|
1541
|
+
const tracer = getTracer();
|
|
1542
|
+
const parentOTelCtx = createOTelContextFromTrace(ctx.traceContext);
|
|
1543
|
+
const sessionHash = sessionTracingId(ctx.sessionId);
|
|
1544
|
+
const { span, context: spanCtx } = startSpan(tracer, {
|
|
1545
|
+
name: flowName,
|
|
1546
|
+
kind: SpanKind11.INTERNAL,
|
|
1547
|
+
attributes: {
|
|
1548
|
+
[FrontMcpAttributes.FLOW_NAME]: flowName,
|
|
1549
|
+
[McpAttributes.SESSION_ID]: sessionHash,
|
|
1550
|
+
[FrontMcpAttributes.SESSION_ID_HASH]: sessionHash,
|
|
1551
|
+
[FrontMcpAttributes.SCOPE_ID]: ctx.scopeId,
|
|
1552
|
+
[FrontMcpAttributes.REQUEST_ID]: ctx.requestId
|
|
1553
|
+
},
|
|
1554
|
+
parentContext: parentOTelCtx
|
|
1555
|
+
});
|
|
1556
|
+
flowCtx.state[SPAN_KEY] = span;
|
|
1557
|
+
flowCtx.state[SPAN_CTX_KEY] = spanCtx;
|
|
1558
|
+
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1559
|
+
}
|
|
1560
|
+
function onGenericFlowStage(stageName, flowCtx) {
|
|
1561
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1562
|
+
if (span) recordStageEvent(span, stageName, flowCtx.state);
|
|
1563
|
+
}
|
|
1564
|
+
function onGenericFlowDidFinalize(flowCtx) {
|
|
1565
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1566
|
+
if (!span) return;
|
|
1567
|
+
const error = flowCtx.state?.error;
|
|
1568
|
+
if (error) {
|
|
1569
|
+
endSpanError(span, error instanceof Error ? error : String(error));
|
|
1570
|
+
} else {
|
|
1571
|
+
endSpanOk(span);
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
function onTransportWillStart(transportType, options, flowCtx) {
|
|
1575
|
+
if (options.transportSpans === false) return;
|
|
1576
|
+
const ctx = extractContext(flowCtx);
|
|
1577
|
+
if (!ctx) return;
|
|
1578
|
+
const tracer = getTracer();
|
|
1579
|
+
const parentOTelCtx = createOTelContextFromTrace(ctx.traceContext);
|
|
1580
|
+
const sessionHash = sessionTracingId(ctx.sessionId);
|
|
1581
|
+
const { span, context: spanCtx } = startTransportSpan(tracer, {
|
|
1582
|
+
type: transportType,
|
|
1583
|
+
sessionIdHash: sessionHash,
|
|
1584
|
+
parentContext: parentOTelCtx
|
|
1585
|
+
});
|
|
1586
|
+
flowCtx.state[SPAN_KEY] = span;
|
|
1587
|
+
flowCtx.state[SPAN_CTX_KEY] = spanCtx;
|
|
1588
|
+
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1589
|
+
recordStageEvent(span, "parseInput", flowCtx.state);
|
|
1590
|
+
}
|
|
1591
|
+
function onTransportDidRoute(flowCtx) {
|
|
1592
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1593
|
+
if (!span) return;
|
|
1594
|
+
recordStageEvent(span, "router", flowCtx.state);
|
|
1595
|
+
const requestType = flowCtx.state?.requestType;
|
|
1596
|
+
if (requestType) setTransportRequestType(span, requestType);
|
|
1597
|
+
}
|
|
1598
|
+
function onTransportStage(stageName, flowCtx) {
|
|
1599
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1600
|
+
if (span) recordStageEvent(span, stageName, flowCtx.state);
|
|
1601
|
+
}
|
|
1602
|
+
function onTransportDidFinalize(flowCtx) {
|
|
1603
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1604
|
+
if (!span) return;
|
|
1605
|
+
recordStageEvent(span, "cleanup", flowCtx.state);
|
|
1606
|
+
const error = flowCtx.state?.error;
|
|
1607
|
+
if (error) {
|
|
1608
|
+
endSpanError(span, error instanceof Error ? error : String(error));
|
|
1609
|
+
} else {
|
|
1610
|
+
endSpanOk(span);
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
function onAuthWillStart(flowName, options, flowCtx) {
|
|
1614
|
+
if (options.authSpans === false) return;
|
|
1615
|
+
const ctx = extractContext(flowCtx);
|
|
1616
|
+
if (!ctx) return;
|
|
1617
|
+
const tracer = getTracer();
|
|
1618
|
+
const parentOTelCtx = createOTelContextFromTrace(ctx.traceContext);
|
|
1619
|
+
const { span, context: spanCtx } = startAuthSpan(tracer, {
|
|
1620
|
+
flowName,
|
|
1621
|
+
parentContext: parentOTelCtx
|
|
1622
|
+
});
|
|
1623
|
+
flowCtx.state[SPAN_KEY] = span;
|
|
1624
|
+
flowCtx.state[SPAN_CTX_KEY] = spanCtx;
|
|
1625
|
+
flowCtx.state[STAGE_TS_KEY] = Date.now();
|
|
1626
|
+
recordStageEvent(span, "parseInput", flowCtx.state);
|
|
1627
|
+
}
|
|
1628
|
+
function onAuthDidDetermineMode(flowCtx) {
|
|
1629
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1630
|
+
if (!span) return;
|
|
1631
|
+
recordStageEvent(span, "determineAuthMode", flowCtx.state);
|
|
1632
|
+
const mode = flowCtx.state?.authMode;
|
|
1633
|
+
if (mode) setAuthMode(span, mode);
|
|
1634
|
+
}
|
|
1635
|
+
function onAuthStage(stageName, flowCtx) {
|
|
1636
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1637
|
+
if (span) recordStageEvent(span, stageName, flowCtx.state);
|
|
1638
|
+
}
|
|
1639
|
+
function onAuthDidFinalize(flowCtx) {
|
|
1640
|
+
const span = flowCtx.state?.[SPAN_KEY];
|
|
1641
|
+
if (!span) return;
|
|
1642
|
+
const error = flowCtx.state?.error;
|
|
1643
|
+
if (error) {
|
|
1644
|
+
setAuthResult(span, "unauthorized");
|
|
1645
|
+
endSpanError(span, error instanceof Error ? error : String(error));
|
|
1646
|
+
} else {
|
|
1647
|
+
setAuthResult(span, "authorized");
|
|
1648
|
+
endSpanOk(span);
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
function wrapContextFetch(options, flowCtx) {
|
|
1652
|
+
if (options.fetchSpans === false) return;
|
|
1653
|
+
const toolCtx = flowCtx.state?.toolContext ?? flowCtx.state?.toolCallContext;
|
|
1654
|
+
if (!toolCtx || typeof toolCtx.fetch !== "function") return;
|
|
1655
|
+
const originalFetch = toolCtx.fetch.bind(toolCtx);
|
|
1656
|
+
const parentOTelCtx = flowCtx.state?.[SPAN_CTX_KEY];
|
|
1657
|
+
toolCtx.fetch = async (input, init) => {
|
|
1658
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
1659
|
+
const method = init?.method ?? "GET";
|
|
1660
|
+
const tracer = getTracer();
|
|
1661
|
+
const { span } = startFetchSpan(tracer, { method, url, parentContext: parentOTelCtx });
|
|
1662
|
+
try {
|
|
1663
|
+
const response = await originalFetch(input, init);
|
|
1664
|
+
setFetchResponseStatus(span, response.status);
|
|
1665
|
+
endSpanOk(span);
|
|
1666
|
+
return response;
|
|
1667
|
+
} catch (err) {
|
|
1668
|
+
endSpanError(span, err instanceof Error ? err : String(err));
|
|
1669
|
+
throw err;
|
|
1670
|
+
}
|
|
1671
|
+
};
|
|
1672
|
+
}
|
|
1673
|
+
function onAgentDidExecuteEnrich(flowCtx) {
|
|
1674
|
+
const agentSpan = flowCtx.state?.[EXEC_SPAN_KEY];
|
|
1675
|
+
if (!agentSpan) return;
|
|
1676
|
+
const meta = flowCtx.state?.executionMeta;
|
|
1677
|
+
if (meta) {
|
|
1678
|
+
if (typeof meta.iterations === "number") {
|
|
1679
|
+
agentSpan.setAttribute(FrontMcpAttributes.AGENT_ITERATIONS, meta.iterations);
|
|
1680
|
+
}
|
|
1681
|
+
if (typeof meta.durationMs === "number") {
|
|
1682
|
+
agentSpan.setAttribute(FrontMcpAttributes.AGENT_EXECUTION_DURATION_MS, meta.durationMs);
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
function reportStartup(data) {
|
|
1687
|
+
const tracer = getTracer();
|
|
1688
|
+
emitStartupReport(tracer, data);
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
// libs/observability/src/telemetry/telemetry.accessor.ts
|
|
1692
|
+
var TelemetrySpan = class {
|
|
1693
|
+
constructor(span) {
|
|
1694
|
+
this.span = span;
|
|
1695
|
+
this.hasError = false;
|
|
1696
|
+
}
|
|
1697
|
+
/** Set a string/number/boolean attribute */
|
|
1698
|
+
setAttribute(key, value) {
|
|
1699
|
+
this.span.setAttribute(key, value);
|
|
1700
|
+
return this;
|
|
1701
|
+
}
|
|
1702
|
+
/** Set multiple attributes at once */
|
|
1703
|
+
setAttributes(attrs) {
|
|
1704
|
+
this.span.setAttributes(attrs);
|
|
1705
|
+
return this;
|
|
1706
|
+
}
|
|
1707
|
+
/** Add a named event (with optional attributes) */
|
|
1708
|
+
addEvent(name, attributes) {
|
|
1709
|
+
this.span.addEvent(name, attributes);
|
|
1710
|
+
return this;
|
|
1711
|
+
}
|
|
1712
|
+
/** Record an error on this span */
|
|
1713
|
+
recordError(error) {
|
|
1714
|
+
this.span.recordException(error);
|
|
1715
|
+
this.span.setStatus({ code: SpanStatusCode2.ERROR, message: error.message });
|
|
1716
|
+
this.hasError = true;
|
|
1717
|
+
return this;
|
|
1718
|
+
}
|
|
1719
|
+
/** End the span (preserves ERROR status if already set) */
|
|
1720
|
+
end() {
|
|
1721
|
+
if (!this.hasError) {
|
|
1722
|
+
this.span.setStatus({ code: SpanStatusCode2.OK });
|
|
1723
|
+
}
|
|
1724
|
+
this.span.end();
|
|
1725
|
+
}
|
|
1726
|
+
/** End the span with error */
|
|
1727
|
+
endWithError(error) {
|
|
1728
|
+
const msg = typeof error === "string" ? error : error.message;
|
|
1729
|
+
if (error instanceof Error) this.span.recordException(error);
|
|
1730
|
+
this.span.setStatus({ code: SpanStatusCode2.ERROR, message: msg });
|
|
1731
|
+
this.span.end();
|
|
1732
|
+
}
|
|
1733
|
+
/** Get the underlying OTel span (escape hatch) */
|
|
1734
|
+
get raw() {
|
|
1735
|
+
return this.span;
|
|
1736
|
+
}
|
|
1737
|
+
};
|
|
1738
|
+
var TelemetryAccessor = class {
|
|
1739
|
+
constructor(ctx) {
|
|
1740
|
+
this.ctx = ctx;
|
|
1741
|
+
this.tracer = trace4.getTracer("@frontmcp/observability");
|
|
1742
|
+
this.fallbackContext = createOTelContextFromTrace(ctx.traceContext);
|
|
1743
|
+
this.sessionHash = sessionTracingId(ctx.sessionId);
|
|
1744
|
+
this.baseAttributes = {
|
|
1745
|
+
[FrontMcpAttributes.REQUEST_ID]: ctx.requestId,
|
|
1746
|
+
[FrontMcpAttributes.SCOPE_ID]: ctx.scopeId,
|
|
1747
|
+
[McpAttributes.SESSION_ID]: this.sessionHash
|
|
1748
|
+
};
|
|
1749
|
+
}
|
|
1750
|
+
/**
|
|
1751
|
+
* Get the active OTel context — prefers the execution span's context
|
|
1752
|
+
* (set by hooks during willExecute), falls back to the request-level trace.
|
|
1753
|
+
*/
|
|
1754
|
+
getActiveContext() {
|
|
1755
|
+
const otelCtx = this.ctx.get?.(ACTIVE_OTEL_CTX_KEY);
|
|
1756
|
+
return otelCtx ?? this.fallbackContext;
|
|
1757
|
+
}
|
|
1758
|
+
/**
|
|
1759
|
+
* Get the active execution span (set by auto-instrumentation hooks).
|
|
1760
|
+
* Returns undefined if not inside an instrumented execution stage.
|
|
1761
|
+
*/
|
|
1762
|
+
getActiveSpan() {
|
|
1763
|
+
return this.ctx.get?.(ACTIVE_SPAN_KEY);
|
|
1764
|
+
}
|
|
1765
|
+
/**
|
|
1766
|
+
* Start a new child span under the current execution span.
|
|
1767
|
+
*
|
|
1768
|
+
* If called inside a tool's execute(), the span is a child of
|
|
1769
|
+
* the tool execution span. Otherwise falls back to the request trace.
|
|
1770
|
+
*
|
|
1771
|
+
* You MUST call `span.end()` or `span.endWithError()` when done.
|
|
1772
|
+
*/
|
|
1773
|
+
startSpan(name, attributes) {
|
|
1774
|
+
const span = this.tracer.startSpan(
|
|
1775
|
+
name,
|
|
1776
|
+
{
|
|
1777
|
+
kind: SpanKind12.INTERNAL,
|
|
1778
|
+
attributes: { ...this.baseAttributes, ...attributes }
|
|
1779
|
+
},
|
|
1780
|
+
this.getActiveContext()
|
|
1781
|
+
);
|
|
1782
|
+
return new TelemetrySpan(span);
|
|
1783
|
+
}
|
|
1784
|
+
/**
|
|
1785
|
+
* Run a function within a child span. Automatically ended on
|
|
1786
|
+
* success (OK) or error (ERROR + exception recorded).
|
|
1787
|
+
*
|
|
1788
|
+
* @example
|
|
1789
|
+
* ```typescript
|
|
1790
|
+
* const data = await this.telemetry.withSpan('fetch-api', async (span) => {
|
|
1791
|
+
* span.addEvent('request-sent');
|
|
1792
|
+
* const res = await this.fetch(url);
|
|
1793
|
+
* span.setAttribute('status', res.status);
|
|
1794
|
+
* return res.json();
|
|
1795
|
+
* });
|
|
1796
|
+
* ```
|
|
1797
|
+
*/
|
|
1798
|
+
async withSpan(name, fn, attributes) {
|
|
1799
|
+
const telemetrySpan = this.startSpan(name, attributes);
|
|
1800
|
+
try {
|
|
1801
|
+
const result = await fn(telemetrySpan);
|
|
1802
|
+
telemetrySpan.end();
|
|
1803
|
+
return result;
|
|
1804
|
+
} catch (err) {
|
|
1805
|
+
telemetrySpan.endWithError(err instanceof Error ? err : String(err));
|
|
1806
|
+
throw err;
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
/**
|
|
1810
|
+
* Add an event to the **active flow execution span**.
|
|
1811
|
+
*
|
|
1812
|
+
* If called inside a tool's execute(), the event appears on the
|
|
1813
|
+
* tool execution span. If no active span exists, creates a
|
|
1814
|
+
* lightweight child span carrying the event.
|
|
1815
|
+
*
|
|
1816
|
+
* @param name — event name (e.g., 'validation-complete', 'cache-hit')
|
|
1817
|
+
* @param attributes — optional event attributes
|
|
1818
|
+
*/
|
|
1819
|
+
addEvent(name, attributes) {
|
|
1820
|
+
const activeSpan = this.getActiveSpan();
|
|
1821
|
+
if (activeSpan) {
|
|
1822
|
+
activeSpan.addEvent(name, attributes);
|
|
1823
|
+
} else {
|
|
1824
|
+
const span = this.tracer.startSpan(
|
|
1825
|
+
name,
|
|
1826
|
+
{ kind: SpanKind12.INTERNAL, attributes: this.baseAttributes },
|
|
1827
|
+
this.fallbackContext
|
|
1828
|
+
);
|
|
1829
|
+
if (attributes) span.addEvent(name, attributes);
|
|
1830
|
+
span.setStatus({ code: SpanStatusCode2.OK });
|
|
1831
|
+
span.end();
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
/**
|
|
1835
|
+
* Set attributes on the **active flow execution span**.
|
|
1836
|
+
*
|
|
1837
|
+
* If called inside a tool's execute(), attributes are set on the
|
|
1838
|
+
* tool execution span. If no active span exists, this is a no-op.
|
|
1839
|
+
*
|
|
1840
|
+
* @param attrs — key-value attributes
|
|
1841
|
+
*/
|
|
1842
|
+
setAttributes(attrs) {
|
|
1843
|
+
const activeSpan = this.getActiveSpan();
|
|
1844
|
+
if (activeSpan) {
|
|
1845
|
+
activeSpan.setAttributes(attrs);
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
/**
|
|
1849
|
+
* Get the trace ID of the current request.
|
|
1850
|
+
* Useful for including in external API calls or logs.
|
|
1851
|
+
*/
|
|
1852
|
+
get traceId() {
|
|
1853
|
+
return trace4.getSpan(this.fallbackContext)?.spanContext().traceId ?? "";
|
|
1854
|
+
}
|
|
1855
|
+
/**
|
|
1856
|
+
* Get the session tracing ID (privacy-safe hash).
|
|
1857
|
+
*/
|
|
1858
|
+
get sessionId() {
|
|
1859
|
+
return this.sessionHash;
|
|
1860
|
+
}
|
|
1861
|
+
};
|
|
1862
|
+
|
|
1863
|
+
// libs/observability/src/telemetry/telemetry.tokens.ts
|
|
1864
|
+
var TELEMETRY_ACCESSOR = /* @__PURE__ */ Symbol.for("frontmcp:observability:telemetry-accessor");
|
|
1865
|
+
|
|
1866
|
+
// libs/observability/src/plugin/observability.plugin.ts
|
|
1867
|
+
var PromptHook = FlowHooksOf("prompts:get-prompt");
|
|
1868
|
+
var ListPromptsHook = FlowHooksOf("prompts:list-prompts");
|
|
1869
|
+
var SkillSearchHook = FlowHooksOf("skills:search");
|
|
1870
|
+
var SkillLoadHook = FlowHooksOf("skills:load");
|
|
1871
|
+
var CompletionHook = FlowHooksOf("completion:complete");
|
|
1872
|
+
var LegacySseHook = FlowHooksOf("handle:legacy-sse");
|
|
1873
|
+
var StreamableHttpHook = FlowHooksOf("handle:streamable-http");
|
|
1874
|
+
var StatelessHttpHook = FlowHooksOf("handle:stateless-http");
|
|
1875
|
+
var AuthVerifyHook = FlowHooksOf("auth:verify");
|
|
1876
|
+
var SessionVerifyHook = FlowHooksOf("session:verify");
|
|
1877
|
+
var OAuthTokenHook = FlowHooksOf("oauth:token");
|
|
1878
|
+
var OAuthAuthorizeHook = FlowHooksOf("oauth:authorize");
|
|
1879
|
+
var OAuthCallbackHook = FlowHooksOf("oauth:callback");
|
|
1880
|
+
var OAuthProviderCallbackHook = FlowHooksOf("oauth:provider-callback");
|
|
1881
|
+
var OAuthRegisterHook = FlowHooksOf("oauth:register");
|
|
1882
|
+
var ElicitRequestHook = FlowHooksOf("elicitation:request");
|
|
1883
|
+
var ElicitResultHook = FlowHooksOf("elicitation:result");
|
|
1884
|
+
var SubscribeResourceHook = FlowHooksOf("resources:subscribe");
|
|
1885
|
+
var UnsubscribeResourceHook = FlowHooksOf("resources:unsubscribe");
|
|
1886
|
+
var SkillsHttpLlmTxtHook = FlowHooksOf("skills-http:llm-txt");
|
|
1887
|
+
var SkillsHttpLlmFullTxtHook = FlowHooksOf("skills-http:llm-full-txt");
|
|
1888
|
+
var SkillsHttpApiHook = FlowHooksOf("skills-http:api");
|
|
1889
|
+
var WellKnownJwksHook = FlowHooksOf("well-known.jwks");
|
|
1890
|
+
var WellKnownOAuthServerHook = FlowHooksOf("well-known.oauth-authorization-server");
|
|
1891
|
+
var WellKnownPrmHook = FlowHooksOf("well-known.prm");
|
|
1892
|
+
var LoggingSetLevelHook = FlowHooksOf("logging:set-level");
|
|
1893
|
+
var DEFAULT_TRACING = {
|
|
1894
|
+
httpSpans: true,
|
|
1895
|
+
executionSpans: true,
|
|
1896
|
+
hookSpans: false,
|
|
1897
|
+
fetchSpans: true,
|
|
1898
|
+
flowStageEvents: true,
|
|
1899
|
+
transportSpans: true,
|
|
1900
|
+
authSpans: true,
|
|
1901
|
+
oauthSpans: true,
|
|
1902
|
+
elicitationSpans: true,
|
|
1903
|
+
startupReport: true
|
|
1904
|
+
};
|
|
1905
|
+
var ObservabilityPlugin = class extends DynamicPlugin {
|
|
1906
|
+
constructor(options = {}) {
|
|
1907
|
+
super();
|
|
1908
|
+
this.options = resolveOptions(options);
|
|
1909
|
+
this.tracingOpts = this.options.tracing !== false ? this.options.tracing : DEFAULT_TRACING;
|
|
1910
|
+
}
|
|
1911
|
+
get tracingEnabled() {
|
|
1912
|
+
return this.options.tracing !== false;
|
|
1913
|
+
}
|
|
1914
|
+
_httpWillTrace(ctx) {
|
|
1915
|
+
if (this.tracingEnabled) onHttpWillTrace(this.tracingOpts, ctx);
|
|
1916
|
+
}
|
|
1917
|
+
_httpWillQuota(ctx) {
|
|
1918
|
+
if (this.tracingEnabled) onHttpWillAcquireQuota(ctx);
|
|
1919
|
+
}
|
|
1920
|
+
_httpDidSemaphore(ctx) {
|
|
1921
|
+
if (this.tracingEnabled) onHttpDidAcquireQuota(ctx);
|
|
1922
|
+
}
|
|
1923
|
+
_httpWillAuth(ctx) {
|
|
1924
|
+
if (this.tracingEnabled) onHttpWillCheckAuth(ctx);
|
|
1925
|
+
}
|
|
1926
|
+
_httpDidAuth(ctx) {
|
|
1927
|
+
if (this.tracingEnabled) onHttpDidCheckAuth(ctx);
|
|
1928
|
+
}
|
|
1929
|
+
_httpWillRoute(ctx) {
|
|
1930
|
+
if (this.tracingEnabled) onHttpWillRoute(ctx);
|
|
1931
|
+
}
|
|
1932
|
+
_httpDidRoute(ctx) {
|
|
1933
|
+
if (this.tracingEnabled) onHttpDidRoute(ctx);
|
|
1934
|
+
}
|
|
1935
|
+
_httpDidFinalize(ctx) {
|
|
1936
|
+
if (this.tracingEnabled) onHttpDidFinalize(ctx);
|
|
1937
|
+
}
|
|
1938
|
+
_toolWillParse(ctx) {
|
|
1939
|
+
if (this.tracingEnabled) onToolWillParse(this.tracingOpts, ctx);
|
|
1940
|
+
}
|
|
1941
|
+
_toolWillFind(ctx) {
|
|
1942
|
+
if (this.tracingEnabled) onToolWillFindTool(ctx);
|
|
1943
|
+
}
|
|
1944
|
+
_toolWillCheckAuth(ctx) {
|
|
1945
|
+
if (this.tracingEnabled) onToolWillCheckAuth(ctx);
|
|
1946
|
+
}
|
|
1947
|
+
_toolWillCreateCtx(ctx) {
|
|
1948
|
+
if (this.tracingEnabled) onToolWillCreateContext(ctx);
|
|
1949
|
+
}
|
|
1950
|
+
_toolWillValidate(ctx) {
|
|
1951
|
+
if (this.tracingEnabled) onToolWillValidateInput(ctx);
|
|
1952
|
+
}
|
|
1953
|
+
_toolWillExecute(ctx) {
|
|
1954
|
+
if (this.tracingEnabled) onToolWillExecute(this.tracingOpts, ctx);
|
|
1955
|
+
}
|
|
1956
|
+
_toolDidExecute(ctx) {
|
|
1957
|
+
if (this.tracingEnabled) onToolDidExecute(this.tracingOpts, ctx);
|
|
1958
|
+
}
|
|
1959
|
+
_toolWillValidateOut(ctx) {
|
|
1960
|
+
if (this.tracingEnabled) onToolWillValidateOutput(ctx);
|
|
1961
|
+
}
|
|
1962
|
+
_toolWillApplyUI(ctx) {
|
|
1963
|
+
if (this.tracingEnabled) onToolWillApplyUI(ctx);
|
|
1964
|
+
}
|
|
1965
|
+
_toolDidFinalize(ctx) {
|
|
1966
|
+
if (this.tracingEnabled) onToolDidFinalize(ctx);
|
|
1967
|
+
}
|
|
1968
|
+
_resourceWillParse(ctx) {
|
|
1969
|
+
if (this.tracingEnabled) onResourceWillParse(this.tracingOpts, ctx);
|
|
1970
|
+
}
|
|
1971
|
+
_resourceWillFind(ctx) {
|
|
1972
|
+
if (this.tracingEnabled) onResourceWillFind(ctx);
|
|
1973
|
+
}
|
|
1974
|
+
_resourceWillExecute(ctx) {
|
|
1975
|
+
if (this.tracingEnabled) onResourceWillExecute(this.tracingOpts, ctx);
|
|
1976
|
+
}
|
|
1977
|
+
_resourceDidExecute(ctx) {
|
|
1978
|
+
if (this.tracingEnabled) onResourceDidExecute(ctx);
|
|
1979
|
+
}
|
|
1980
|
+
_resourceDidFinalize(ctx) {
|
|
1981
|
+
if (this.tracingEnabled) onResourceDidFinalize(ctx);
|
|
1982
|
+
}
|
|
1983
|
+
_promptWillParse(ctx) {
|
|
1984
|
+
if (this.tracingEnabled) onPromptWillParse(this.tracingOpts, ctx);
|
|
1985
|
+
}
|
|
1986
|
+
_promptWillFind(ctx) {
|
|
1987
|
+
if (this.tracingEnabled) onPromptWillFind(ctx);
|
|
1988
|
+
}
|
|
1989
|
+
_promptWillExecute(ctx) {
|
|
1990
|
+
if (this.tracingEnabled) onPromptWillExecute(this.tracingOpts, ctx);
|
|
1991
|
+
}
|
|
1992
|
+
_promptDidExecute(ctx) {
|
|
1993
|
+
if (this.tracingEnabled) onPromptDidExecute(ctx);
|
|
1994
|
+
}
|
|
1995
|
+
_promptDidFinalize(ctx) {
|
|
1996
|
+
if (this.tracingEnabled) onPromptDidFinalize(ctx);
|
|
1997
|
+
}
|
|
1998
|
+
_agentWillParse(ctx) {
|
|
1999
|
+
if (this.tracingEnabled) onAgentWillParse(this.tracingOpts, ctx);
|
|
2000
|
+
}
|
|
2001
|
+
_agentWillFind(ctx) {
|
|
2002
|
+
if (this.tracingEnabled) onAgentWillFind(ctx);
|
|
2003
|
+
}
|
|
2004
|
+
_agentWillExecute(ctx) {
|
|
2005
|
+
if (this.tracingEnabled) onAgentWillExecute(this.tracingOpts, ctx);
|
|
2006
|
+
}
|
|
2007
|
+
_agentDidExecute(ctx) {
|
|
2008
|
+
if (this.tracingEnabled) onAgentDidExecute(ctx);
|
|
2009
|
+
}
|
|
2010
|
+
_agentDidFinalize(ctx) {
|
|
2011
|
+
if (this.tracingEnabled) onAgentDidFinalize(ctx);
|
|
2012
|
+
}
|
|
2013
|
+
_listToolsWill(ctx) {
|
|
2014
|
+
if (this.tracingEnabled) onGenericFlowWillStart("tools/list", this.tracingOpts, ctx);
|
|
2015
|
+
}
|
|
2016
|
+
_listToolsDidFind(ctx) {
|
|
2017
|
+
if (this.tracingEnabled) onGenericFlowStage("findTools", ctx);
|
|
2018
|
+
}
|
|
2019
|
+
_listToolsDone(ctx) {
|
|
2020
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2021
|
+
}
|
|
2022
|
+
_listResourcesWill(ctx) {
|
|
2023
|
+
if (this.tracingEnabled) onGenericFlowWillStart("resources/list", this.tracingOpts, ctx);
|
|
2024
|
+
}
|
|
2025
|
+
_listResourcesDone(ctx) {
|
|
2026
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2027
|
+
}
|
|
2028
|
+
_listTemplatesWill(ctx) {
|
|
2029
|
+
if (this.tracingEnabled) onGenericFlowWillStart("resources/listTemplates", this.tracingOpts, ctx);
|
|
2030
|
+
}
|
|
2031
|
+
_listTemplatesDone(ctx) {
|
|
2032
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2033
|
+
}
|
|
2034
|
+
_listPromptsWill(ctx) {
|
|
2035
|
+
if (this.tracingEnabled) onGenericFlowWillStart("prompts/list", this.tracingOpts, ctx);
|
|
2036
|
+
}
|
|
2037
|
+
_listPromptsDone(ctx) {
|
|
2038
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2039
|
+
}
|
|
2040
|
+
_skillSearchWill(ctx) {
|
|
2041
|
+
if (this.tracingEnabled) onGenericFlowWillStart("skills/search", this.tracingOpts, ctx);
|
|
2042
|
+
}
|
|
2043
|
+
_skillSearchDone(ctx) {
|
|
2044
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2045
|
+
}
|
|
2046
|
+
_skillLoadWill(ctx) {
|
|
2047
|
+
if (this.tracingEnabled) onGenericFlowWillStart("skills/load", this.tracingOpts, ctx);
|
|
2048
|
+
}
|
|
2049
|
+
_skillLoadStage(ctx) {
|
|
2050
|
+
if (this.tracingEnabled) onGenericFlowStage("loadSkills", ctx);
|
|
2051
|
+
}
|
|
2052
|
+
_skillLoadDone(ctx) {
|
|
2053
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2054
|
+
}
|
|
2055
|
+
_completionWill(ctx) {
|
|
2056
|
+
if (this.tracingEnabled) onGenericFlowWillStart("completion/complete", this.tracingOpts, ctx);
|
|
2057
|
+
}
|
|
2058
|
+
_completionDone(ctx) {
|
|
2059
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2060
|
+
}
|
|
2061
|
+
_sseWillParse(ctx) {
|
|
2062
|
+
if (this.tracingEnabled) onTransportWillStart("legacy-sse", this.tracingOpts, ctx);
|
|
2063
|
+
}
|
|
2064
|
+
_sseDidRoute(ctx) {
|
|
2065
|
+
if (this.tracingEnabled) onTransportDidRoute(ctx);
|
|
2066
|
+
}
|
|
2067
|
+
_sseDidInit(ctx) {
|
|
2068
|
+
if (this.tracingEnabled) onTransportStage("onInitialize", ctx);
|
|
2069
|
+
}
|
|
2070
|
+
_sseDidMsg(ctx) {
|
|
2071
|
+
if (this.tracingEnabled) onTransportStage("onMessage", ctx);
|
|
2072
|
+
}
|
|
2073
|
+
_sseDidElicit(ctx) {
|
|
2074
|
+
if (this.tracingEnabled) onTransportStage("onElicitResult", ctx);
|
|
2075
|
+
}
|
|
2076
|
+
_sseDidCleanup(ctx) {
|
|
2077
|
+
if (this.tracingEnabled) onTransportDidFinalize(ctx);
|
|
2078
|
+
}
|
|
2079
|
+
_shttpWillParse(ctx) {
|
|
2080
|
+
if (this.tracingEnabled) onTransportWillStart("streamable-http", this.tracingOpts, ctx);
|
|
2081
|
+
}
|
|
2082
|
+
_shttpDidRoute(ctx) {
|
|
2083
|
+
if (this.tracingEnabled) onTransportDidRoute(ctx);
|
|
2084
|
+
}
|
|
2085
|
+
_shttpDidInit(ctx) {
|
|
2086
|
+
if (this.tracingEnabled) onTransportStage("onInitialize", ctx);
|
|
2087
|
+
}
|
|
2088
|
+
_shttpDidMsg(ctx) {
|
|
2089
|
+
if (this.tracingEnabled) onTransportStage("onMessage", ctx);
|
|
2090
|
+
}
|
|
2091
|
+
_shttpDidElicit(ctx) {
|
|
2092
|
+
if (this.tracingEnabled) onTransportStage("onElicitResult", ctx);
|
|
2093
|
+
}
|
|
2094
|
+
_shttpDidSse(ctx) {
|
|
2095
|
+
if (this.tracingEnabled) onTransportStage("onSseListener", ctx);
|
|
2096
|
+
}
|
|
2097
|
+
_shttpDidExtApps(ctx) {
|
|
2098
|
+
if (this.tracingEnabled) onTransportStage("onExtApps", ctx);
|
|
2099
|
+
}
|
|
2100
|
+
_shttpDidCleanup(ctx) {
|
|
2101
|
+
if (this.tracingEnabled) onTransportDidFinalize(ctx);
|
|
2102
|
+
}
|
|
2103
|
+
_slhttpWillParse(ctx) {
|
|
2104
|
+
if (this.tracingEnabled) onTransportWillStart("stateless-http", this.tracingOpts, ctx);
|
|
2105
|
+
}
|
|
2106
|
+
_slhttpDidHandle(ctx) {
|
|
2107
|
+
if (this.tracingEnabled) onTransportStage("handleRequest", ctx);
|
|
2108
|
+
}
|
|
2109
|
+
_slhttpDidCleanup(ctx) {
|
|
2110
|
+
if (this.tracingEnabled) onTransportDidFinalize(ctx);
|
|
2111
|
+
}
|
|
2112
|
+
_authVerifyWill(ctx) {
|
|
2113
|
+
if (this.tracingEnabled) onAuthWillStart("auth:verify", this.tracingOpts, ctx);
|
|
2114
|
+
}
|
|
2115
|
+
_authVerifyDidMode(ctx) {
|
|
2116
|
+
if (this.tracingEnabled) onAuthDidDetermineMode(ctx);
|
|
2117
|
+
}
|
|
2118
|
+
_authVerifyDidToken(ctx) {
|
|
2119
|
+
if (this.tracingEnabled) onAuthStage("verifyToken", ctx);
|
|
2120
|
+
}
|
|
2121
|
+
_authVerifyDidBuild(ctx) {
|
|
2122
|
+
if (this.tracingEnabled) onAuthDidFinalize(ctx);
|
|
2123
|
+
}
|
|
2124
|
+
_sessionVerifyWill(ctx) {
|
|
2125
|
+
if (this.tracingEnabled) onAuthWillStart("session:verify", this.tracingOpts, ctx);
|
|
2126
|
+
}
|
|
2127
|
+
_sessionVerifyDidJwt(ctx) {
|
|
2128
|
+
if (this.tracingEnabled) onAuthStage("verifyIfJwt", ctx);
|
|
2129
|
+
}
|
|
2130
|
+
_sessionVerifyDidBuild(ctx) {
|
|
2131
|
+
if (this.tracingEnabled) onAuthDidFinalize(ctx);
|
|
2132
|
+
}
|
|
2133
|
+
_oauthTokenWill(ctx) {
|
|
2134
|
+
if (this.tracingEnabled) onGenericFlowWillStart("oauth/token", this.tracingOpts, ctx);
|
|
2135
|
+
}
|
|
2136
|
+
_oauthTokenDone(ctx) {
|
|
2137
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2138
|
+
}
|
|
2139
|
+
_oauthAuthzWill(ctx) {
|
|
2140
|
+
if (this.tracingEnabled) onGenericFlowWillStart("oauth/authorize", this.tracingOpts, ctx);
|
|
2141
|
+
}
|
|
2142
|
+
_oauthAuthzDone(ctx) {
|
|
2143
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2144
|
+
}
|
|
2145
|
+
_oauthCallbackWill(ctx) {
|
|
2146
|
+
if (this.tracingEnabled) onGenericFlowWillStart("oauth/callback", this.tracingOpts, ctx);
|
|
2147
|
+
}
|
|
2148
|
+
_oauthCallbackDone(ctx) {
|
|
2149
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2150
|
+
}
|
|
2151
|
+
_oauthProviderWill(ctx) {
|
|
2152
|
+
if (this.tracingEnabled) onGenericFlowWillStart("oauth/provider-callback", this.tracingOpts, ctx);
|
|
2153
|
+
}
|
|
2154
|
+
_oauthProviderDone(ctx) {
|
|
2155
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2156
|
+
}
|
|
2157
|
+
_oauthRegisterWill(ctx) {
|
|
2158
|
+
if (this.tracingEnabled) onGenericFlowWillStart("oauth/register", this.tracingOpts, ctx);
|
|
2159
|
+
}
|
|
2160
|
+
_oauthRegisterDone(ctx) {
|
|
2161
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2162
|
+
}
|
|
2163
|
+
_elicitReqWill(ctx) {
|
|
2164
|
+
if (this.tracingEnabled) onGenericFlowWillStart("elicitation/request", this.tracingOpts, ctx);
|
|
2165
|
+
}
|
|
2166
|
+
_elicitReqDone(ctx) {
|
|
2167
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2168
|
+
}
|
|
2169
|
+
_elicitResWill(ctx) {
|
|
2170
|
+
if (this.tracingEnabled) onGenericFlowWillStart("elicitation/result", this.tracingOpts, ctx);
|
|
2171
|
+
}
|
|
2172
|
+
_elicitResDone(ctx) {
|
|
2173
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2174
|
+
}
|
|
2175
|
+
_subscribeWill(ctx) {
|
|
2176
|
+
if (this.tracingEnabled) onGenericFlowWillStart("resources/subscribe", this.tracingOpts, ctx);
|
|
2177
|
+
}
|
|
2178
|
+
_subscribeDone(ctx) {
|
|
2179
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2180
|
+
}
|
|
2181
|
+
_unsubscribeWill(ctx) {
|
|
2182
|
+
if (this.tracingEnabled) onGenericFlowWillStart("resources/unsubscribe", this.tracingOpts, ctx);
|
|
2183
|
+
}
|
|
2184
|
+
_unsubscribeDone(ctx) {
|
|
2185
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2186
|
+
}
|
|
2187
|
+
_skillsLlmTxtWill(ctx) {
|
|
2188
|
+
if (this.tracingEnabled) onGenericFlowWillStart("skills-http/llm-txt", this.tracingOpts, ctx);
|
|
2189
|
+
}
|
|
2190
|
+
_skillsLlmTxtDone(ctx) {
|
|
2191
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2192
|
+
}
|
|
2193
|
+
_skillsLlmFullTxtWill(ctx) {
|
|
2194
|
+
if (this.tracingEnabled) onGenericFlowWillStart("skills-http/llm-full-txt", this.tracingOpts, ctx);
|
|
2195
|
+
}
|
|
2196
|
+
_skillsLlmFullTxtDone(ctx) {
|
|
2197
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2198
|
+
}
|
|
2199
|
+
_skillsApiWill(ctx) {
|
|
2200
|
+
if (this.tracingEnabled) onGenericFlowWillStart("skills-http/api", this.tracingOpts, ctx);
|
|
2201
|
+
}
|
|
2202
|
+
_skillsApiDone(ctx) {
|
|
2203
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2204
|
+
}
|
|
2205
|
+
_jwksWill(ctx) {
|
|
2206
|
+
if (this.tracingEnabled) onGenericFlowWillStart("well-known/jwks", this.tracingOpts, ctx);
|
|
2207
|
+
}
|
|
2208
|
+
_jwksDone(ctx) {
|
|
2209
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2210
|
+
}
|
|
2211
|
+
_oauthServerWill(ctx) {
|
|
2212
|
+
if (this.tracingEnabled) onGenericFlowWillStart("well-known/oauth-server", this.tracingOpts, ctx);
|
|
2213
|
+
}
|
|
2214
|
+
_oauthServerDone(ctx) {
|
|
2215
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2216
|
+
}
|
|
2217
|
+
_prmWill(ctx) {
|
|
2218
|
+
if (this.tracingEnabled) onGenericFlowWillStart("well-known/prm", this.tracingOpts, ctx);
|
|
2219
|
+
}
|
|
2220
|
+
_prmDone(ctx) {
|
|
2221
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2222
|
+
}
|
|
2223
|
+
_setLevelWill(ctx) {
|
|
2224
|
+
if (this.tracingEnabled) onGenericFlowWillStart("logging/set-level", this.tracingOpts, ctx);
|
|
2225
|
+
}
|
|
2226
|
+
_setLevelDone(ctx) {
|
|
2227
|
+
if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
|
|
2228
|
+
}
|
|
2229
|
+
_toolDidCreateCtxFetch(ctx) {
|
|
2230
|
+
if (this.tracingEnabled) wrapContextFetch(this.tracingOpts, ctx);
|
|
2231
|
+
}
|
|
2232
|
+
_agentDidExecuteMeta(ctx) {
|
|
2233
|
+
if (this.tracingEnabled) onAgentDidExecuteEnrich(ctx);
|
|
2234
|
+
}
|
|
2235
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2236
|
+
// Startup Report (public method)
|
|
2237
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2238
|
+
/**
|
|
2239
|
+
* Emit startup telemetry report.
|
|
2240
|
+
* Call after scope.initialize() completes with component counts.
|
|
2241
|
+
*/
|
|
2242
|
+
reportStartupTelemetry(data) {
|
|
2243
|
+
if (this.options.tracing === false) return;
|
|
2244
|
+
reportStartup(data);
|
|
2245
|
+
}
|
|
2246
|
+
};
|
|
2247
|
+
ObservabilityPlugin.defaultOptions = {
|
|
2248
|
+
tracing: DEFAULT_TRACING,
|
|
2249
|
+
logging: false,
|
|
2250
|
+
requestLogs: false
|
|
2251
|
+
};
|
|
2252
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2253
|
+
// Dynamic Providers
|
|
2254
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2255
|
+
ObservabilityPlugin.dynamicProviders = (input) => {
|
|
2256
|
+
const options = resolveOptions(input);
|
|
2257
|
+
const providers = [];
|
|
2258
|
+
if (options.tracing !== false) {
|
|
2259
|
+
providers.push({
|
|
2260
|
+
name: "observability:tracer",
|
|
2261
|
+
provide: OTEL_TRACER,
|
|
2262
|
+
useValue: trace5.getTracer("@frontmcp/observability")
|
|
2263
|
+
});
|
|
2264
|
+
providers.push({
|
|
2265
|
+
name: "observability:config",
|
|
2266
|
+
provide: OTEL_CONFIG,
|
|
2267
|
+
useValue: options.tracing
|
|
2268
|
+
});
|
|
2269
|
+
providers.push({
|
|
2270
|
+
name: "observability:telemetry-accessor",
|
|
2271
|
+
provide: TELEMETRY_ACCESSOR,
|
|
2272
|
+
scope: ProviderScope.CONTEXT,
|
|
2273
|
+
inject: () => [FRONTMCP_CONTEXT],
|
|
2274
|
+
useFactory: (ctx) => new TelemetryAccessor(ctx)
|
|
2275
|
+
});
|
|
2276
|
+
}
|
|
2277
|
+
if (options.logging !== false) {
|
|
2278
|
+
const loggingOpts = options.logging;
|
|
2279
|
+
const sinks = createSinks(loggingOpts.sinks);
|
|
2280
|
+
const transport = new StructuredLogTransport(
|
|
2281
|
+
sinks,
|
|
2282
|
+
{
|
|
2283
|
+
redactFields: loggingOpts.redactFields,
|
|
2284
|
+
includeStacks: loggingOpts.includeStacks,
|
|
2285
|
+
staticFields: loggingOpts.staticFields
|
|
2286
|
+
},
|
|
2287
|
+
void 0
|
|
2288
|
+
);
|
|
2289
|
+
providers.push({
|
|
2290
|
+
name: "observability:structured-log-transport",
|
|
2291
|
+
provide: StructuredLogTransport,
|
|
2292
|
+
useValue: transport
|
|
2293
|
+
});
|
|
2294
|
+
}
|
|
2295
|
+
if (options.requestLogs !== false) {
|
|
2296
|
+
const requestLogOpts = options.requestLogs;
|
|
2297
|
+
providers.push({
|
|
2298
|
+
name: "observability:request-log-collector",
|
|
2299
|
+
provide: REQUEST_LOG_COLLECTOR,
|
|
2300
|
+
scope: ProviderScope.CONTEXT,
|
|
2301
|
+
inject: () => [FRONTMCP_CONTEXT],
|
|
2302
|
+
useFactory: (ctx) => {
|
|
2303
|
+
return new RequestLogCollector(
|
|
2304
|
+
{
|
|
2305
|
+
requestId: ctx.requestId,
|
|
2306
|
+
traceId: ctx.traceContext.traceId,
|
|
2307
|
+
sessionIdHash: sessionTracingId(ctx.sessionId).slice(0, 12),
|
|
2308
|
+
scopeId: ctx.scopeId
|
|
2309
|
+
},
|
|
2310
|
+
requestLogOpts
|
|
2311
|
+
);
|
|
2312
|
+
}
|
|
2313
|
+
});
|
|
2314
|
+
}
|
|
2315
|
+
return providers;
|
|
2316
|
+
};
|
|
2317
|
+
__decorateClass([
|
|
2318
|
+
HttpHook.Will("traceRequest", { priority: -1e3 })
|
|
2319
|
+
], ObservabilityPlugin.prototype, "_httpWillTrace", 1);
|
|
2320
|
+
__decorateClass([
|
|
2321
|
+
HttpHook.Will("acquireQuota", { priority: -1e3 })
|
|
2322
|
+
], ObservabilityPlugin.prototype, "_httpWillQuota", 1);
|
|
2323
|
+
__decorateClass([
|
|
2324
|
+
HttpHook.Did("acquireSemaphore", { priority: 1e3 })
|
|
2325
|
+
], ObservabilityPlugin.prototype, "_httpDidSemaphore", 1);
|
|
2326
|
+
__decorateClass([
|
|
2327
|
+
HttpHook.Will("checkAuthorization", { priority: -1e3 })
|
|
2328
|
+
], ObservabilityPlugin.prototype, "_httpWillAuth", 1);
|
|
2329
|
+
__decorateClass([
|
|
2330
|
+
HttpHook.Did("checkAuthorization", { priority: 1e3 })
|
|
2331
|
+
], ObservabilityPlugin.prototype, "_httpDidAuth", 1);
|
|
2332
|
+
__decorateClass([
|
|
2333
|
+
HttpHook.Will("router", { priority: -1e3 })
|
|
2334
|
+
], ObservabilityPlugin.prototype, "_httpWillRoute", 1);
|
|
2335
|
+
__decorateClass([
|
|
2336
|
+
HttpHook.Did("router", { priority: 1e3 })
|
|
2337
|
+
], ObservabilityPlugin.prototype, "_httpDidRoute", 1);
|
|
2338
|
+
__decorateClass([
|
|
2339
|
+
HttpHook.Did("finalize", { priority: 1e3 })
|
|
2340
|
+
], ObservabilityPlugin.prototype, "_httpDidFinalize", 1);
|
|
2341
|
+
__decorateClass([
|
|
2342
|
+
ToolHook.Will("parseInput", { priority: -1e3 })
|
|
2343
|
+
], ObservabilityPlugin.prototype, "_toolWillParse", 1);
|
|
2344
|
+
__decorateClass([
|
|
2345
|
+
ToolHook.Will("findTool", { priority: -1e3 })
|
|
2346
|
+
], ObservabilityPlugin.prototype, "_toolWillFind", 1);
|
|
2347
|
+
__decorateClass([
|
|
2348
|
+
ToolHook.Will("checkToolAuthorization", { priority: -1e3 })
|
|
2349
|
+
], ObservabilityPlugin.prototype, "_toolWillCheckAuth", 1);
|
|
2350
|
+
__decorateClass([
|
|
2351
|
+
ToolHook.Will("createToolCallContext", { priority: -1e3 })
|
|
2352
|
+
], ObservabilityPlugin.prototype, "_toolWillCreateCtx", 1);
|
|
2353
|
+
__decorateClass([
|
|
2354
|
+
ToolHook.Will("validateInput", { priority: -1e3 })
|
|
2355
|
+
], ObservabilityPlugin.prototype, "_toolWillValidate", 1);
|
|
2356
|
+
__decorateClass([
|
|
2357
|
+
ToolHook.Will("execute", { priority: -1e3 })
|
|
2358
|
+
], ObservabilityPlugin.prototype, "_toolWillExecute", 1);
|
|
2359
|
+
__decorateClass([
|
|
2360
|
+
ToolHook.Did("execute", { priority: 1e3 })
|
|
2361
|
+
], ObservabilityPlugin.prototype, "_toolDidExecute", 1);
|
|
2362
|
+
__decorateClass([
|
|
2363
|
+
ToolHook.Will("validateOutput", { priority: -1e3 })
|
|
2364
|
+
], ObservabilityPlugin.prototype, "_toolWillValidateOut", 1);
|
|
2365
|
+
__decorateClass([
|
|
2366
|
+
ToolHook.Will("applyUI", { priority: -1e3 })
|
|
2367
|
+
], ObservabilityPlugin.prototype, "_toolWillApplyUI", 1);
|
|
2368
|
+
__decorateClass([
|
|
2369
|
+
ToolHook.Did("finalize", { priority: 1e3 })
|
|
2370
|
+
], ObservabilityPlugin.prototype, "_toolDidFinalize", 1);
|
|
2371
|
+
__decorateClass([
|
|
2372
|
+
ResourceHook.Will("parseInput", { priority: -1e3 })
|
|
2373
|
+
], ObservabilityPlugin.prototype, "_resourceWillParse", 1);
|
|
2374
|
+
__decorateClass([
|
|
2375
|
+
ResourceHook.Will("findResource", { priority: -1e3 })
|
|
2376
|
+
], ObservabilityPlugin.prototype, "_resourceWillFind", 1);
|
|
2377
|
+
__decorateClass([
|
|
2378
|
+
ResourceHook.Will("execute", { priority: -1e3 })
|
|
2379
|
+
], ObservabilityPlugin.prototype, "_resourceWillExecute", 1);
|
|
2380
|
+
__decorateClass([
|
|
2381
|
+
ResourceHook.Did("execute", { priority: 1e3 })
|
|
2382
|
+
], ObservabilityPlugin.prototype, "_resourceDidExecute", 1);
|
|
2383
|
+
__decorateClass([
|
|
2384
|
+
ResourceHook.Did("finalize", { priority: 1e3 })
|
|
2385
|
+
], ObservabilityPlugin.prototype, "_resourceDidFinalize", 1);
|
|
2386
|
+
__decorateClass([
|
|
2387
|
+
PromptHook.Will("parseInput", { priority: -1e3 })
|
|
2388
|
+
], ObservabilityPlugin.prototype, "_promptWillParse", 1);
|
|
2389
|
+
__decorateClass([
|
|
2390
|
+
PromptHook.Will("findPrompt", { priority: -1e3 })
|
|
2391
|
+
], ObservabilityPlugin.prototype, "_promptWillFind", 1);
|
|
2392
|
+
__decorateClass([
|
|
2393
|
+
PromptHook.Will("execute", { priority: -1e3 })
|
|
2394
|
+
], ObservabilityPlugin.prototype, "_promptWillExecute", 1);
|
|
2395
|
+
__decorateClass([
|
|
2396
|
+
PromptHook.Did("execute", { priority: 1e3 })
|
|
2397
|
+
], ObservabilityPlugin.prototype, "_promptDidExecute", 1);
|
|
2398
|
+
__decorateClass([
|
|
2399
|
+
PromptHook.Did("finalize", { priority: 1e3 })
|
|
2400
|
+
], ObservabilityPlugin.prototype, "_promptDidFinalize", 1);
|
|
2401
|
+
__decorateClass([
|
|
2402
|
+
AgentCallHook.Will("parseInput", { priority: -1e3 })
|
|
2403
|
+
], ObservabilityPlugin.prototype, "_agentWillParse", 1);
|
|
2404
|
+
__decorateClass([
|
|
2405
|
+
AgentCallHook.Will("findAgent", { priority: -1e3 })
|
|
2406
|
+
], ObservabilityPlugin.prototype, "_agentWillFind", 1);
|
|
2407
|
+
__decorateClass([
|
|
2408
|
+
AgentCallHook.Will("execute", { priority: -1e3 })
|
|
2409
|
+
], ObservabilityPlugin.prototype, "_agentWillExecute", 1);
|
|
2410
|
+
__decorateClass([
|
|
2411
|
+
AgentCallHook.Did("execute", { priority: 1e3 })
|
|
2412
|
+
], ObservabilityPlugin.prototype, "_agentDidExecute", 1);
|
|
2413
|
+
__decorateClass([
|
|
2414
|
+
AgentCallHook.Did("finalize", { priority: 1e3 })
|
|
2415
|
+
], ObservabilityPlugin.prototype, "_agentDidFinalize", 1);
|
|
2416
|
+
__decorateClass([
|
|
2417
|
+
ListToolsHook.Will("parseInput", { priority: -1e3 })
|
|
2418
|
+
], ObservabilityPlugin.prototype, "_listToolsWill", 1);
|
|
2419
|
+
__decorateClass([
|
|
2420
|
+
ListToolsHook.Did("findTools", { priority: 1e3 })
|
|
2421
|
+
], ObservabilityPlugin.prototype, "_listToolsDidFind", 1);
|
|
2422
|
+
__decorateClass([
|
|
2423
|
+
ListToolsHook.Did("parseTools", { priority: 1e3 })
|
|
2424
|
+
], ObservabilityPlugin.prototype, "_listToolsDone", 1);
|
|
2425
|
+
__decorateClass([
|
|
2426
|
+
ListResourcesHook.Will("parseInput", { priority: -1e3 })
|
|
2427
|
+
], ObservabilityPlugin.prototype, "_listResourcesWill", 1);
|
|
2428
|
+
__decorateClass([
|
|
2429
|
+
ListResourcesHook.Did("parseResources", { priority: 1e3 })
|
|
2430
|
+
], ObservabilityPlugin.prototype, "_listResourcesDone", 1);
|
|
2431
|
+
__decorateClass([
|
|
2432
|
+
ListResourceTemplatesHook.Will("parseInput", { priority: -1e3 })
|
|
2433
|
+
], ObservabilityPlugin.prototype, "_listTemplatesWill", 1);
|
|
2434
|
+
__decorateClass([
|
|
2435
|
+
ListResourceTemplatesHook.Did("parseTemplates", { priority: 1e3 })
|
|
2436
|
+
], ObservabilityPlugin.prototype, "_listTemplatesDone", 1);
|
|
2437
|
+
__decorateClass([
|
|
2438
|
+
ListPromptsHook.Will("parseInput", { priority: -1e3 })
|
|
2439
|
+
], ObservabilityPlugin.prototype, "_listPromptsWill", 1);
|
|
2440
|
+
__decorateClass([
|
|
2441
|
+
ListPromptsHook.Did("parsePrompts", { priority: 1e3 })
|
|
2442
|
+
], ObservabilityPlugin.prototype, "_listPromptsDone", 1);
|
|
2443
|
+
__decorateClass([
|
|
2444
|
+
SkillSearchHook.Will("parseInput", { priority: -1e3 })
|
|
2445
|
+
], ObservabilityPlugin.prototype, "_skillSearchWill", 1);
|
|
2446
|
+
__decorateClass([
|
|
2447
|
+
SkillSearchHook.Did("finalize", { priority: 1e3 })
|
|
2448
|
+
], ObservabilityPlugin.prototype, "_skillSearchDone", 1);
|
|
2449
|
+
__decorateClass([
|
|
2450
|
+
SkillLoadHook.Will("parseInput", { priority: -1e3 })
|
|
2451
|
+
], ObservabilityPlugin.prototype, "_skillLoadWill", 1);
|
|
2452
|
+
__decorateClass([
|
|
2453
|
+
SkillLoadHook.Will("loadSkills", { priority: -1e3 })
|
|
2454
|
+
], ObservabilityPlugin.prototype, "_skillLoadStage", 1);
|
|
2455
|
+
__decorateClass([
|
|
2456
|
+
SkillLoadHook.Did("finalize", { priority: 1e3 })
|
|
2457
|
+
], ObservabilityPlugin.prototype, "_skillLoadDone", 1);
|
|
2458
|
+
__decorateClass([
|
|
2459
|
+
CompletionHook.Will("parseInput", { priority: -1e3 })
|
|
2460
|
+
], ObservabilityPlugin.prototype, "_completionWill", 1);
|
|
2461
|
+
__decorateClass([
|
|
2462
|
+
CompletionHook.Did("finalize", { priority: 1e3 })
|
|
2463
|
+
], ObservabilityPlugin.prototype, "_completionDone", 1);
|
|
2464
|
+
__decorateClass([
|
|
2465
|
+
LegacySseHook.Will("parseInput", { priority: -1e3 })
|
|
2466
|
+
], ObservabilityPlugin.prototype, "_sseWillParse", 1);
|
|
2467
|
+
__decorateClass([
|
|
2468
|
+
LegacySseHook.Did("router", { priority: 1e3 })
|
|
2469
|
+
], ObservabilityPlugin.prototype, "_sseDidRoute", 1);
|
|
2470
|
+
__decorateClass([
|
|
2471
|
+
LegacySseHook.Did("onInitialize", { priority: 1e3 })
|
|
2472
|
+
], ObservabilityPlugin.prototype, "_sseDidInit", 1);
|
|
2473
|
+
__decorateClass([
|
|
2474
|
+
LegacySseHook.Did("onMessage", { priority: 1e3 })
|
|
2475
|
+
], ObservabilityPlugin.prototype, "_sseDidMsg", 1);
|
|
2476
|
+
__decorateClass([
|
|
2477
|
+
LegacySseHook.Did("onElicitResult", { priority: 1e3 })
|
|
2478
|
+
], ObservabilityPlugin.prototype, "_sseDidElicit", 1);
|
|
2479
|
+
__decorateClass([
|
|
2480
|
+
LegacySseHook.Did("cleanup", { priority: 1e3 })
|
|
2481
|
+
], ObservabilityPlugin.prototype, "_sseDidCleanup", 1);
|
|
2482
|
+
__decorateClass([
|
|
2483
|
+
StreamableHttpHook.Will("parseInput", { priority: -1e3 })
|
|
2484
|
+
], ObservabilityPlugin.prototype, "_shttpWillParse", 1);
|
|
2485
|
+
__decorateClass([
|
|
2486
|
+
StreamableHttpHook.Did("router", { priority: 1e3 })
|
|
2487
|
+
], ObservabilityPlugin.prototype, "_shttpDidRoute", 1);
|
|
2488
|
+
__decorateClass([
|
|
2489
|
+
StreamableHttpHook.Did("onInitialize", { priority: 1e3 })
|
|
2490
|
+
], ObservabilityPlugin.prototype, "_shttpDidInit", 1);
|
|
2491
|
+
__decorateClass([
|
|
2492
|
+
StreamableHttpHook.Did("onMessage", { priority: 1e3 })
|
|
2493
|
+
], ObservabilityPlugin.prototype, "_shttpDidMsg", 1);
|
|
2494
|
+
__decorateClass([
|
|
2495
|
+
StreamableHttpHook.Did("onElicitResult", { priority: 1e3 })
|
|
2496
|
+
], ObservabilityPlugin.prototype, "_shttpDidElicit", 1);
|
|
2497
|
+
__decorateClass([
|
|
2498
|
+
StreamableHttpHook.Did("onSseListener", { priority: 1e3 })
|
|
2499
|
+
], ObservabilityPlugin.prototype, "_shttpDidSse", 1);
|
|
2500
|
+
__decorateClass([
|
|
2501
|
+
StreamableHttpHook.Did("onExtApps", { priority: 1e3 })
|
|
2502
|
+
], ObservabilityPlugin.prototype, "_shttpDidExtApps", 1);
|
|
2503
|
+
__decorateClass([
|
|
2504
|
+
StreamableHttpHook.Did("cleanup", { priority: 1e3 })
|
|
2505
|
+
], ObservabilityPlugin.prototype, "_shttpDidCleanup", 1);
|
|
2506
|
+
__decorateClass([
|
|
2507
|
+
StatelessHttpHook.Will("parseInput", { priority: -1e3 })
|
|
2508
|
+
], ObservabilityPlugin.prototype, "_slhttpWillParse", 1);
|
|
2509
|
+
__decorateClass([
|
|
2510
|
+
StatelessHttpHook.Did("handleRequest", { priority: 1e3 })
|
|
2511
|
+
], ObservabilityPlugin.prototype, "_slhttpDidHandle", 1);
|
|
2512
|
+
__decorateClass([
|
|
2513
|
+
StatelessHttpHook.Did("cleanup", { priority: 1e3 })
|
|
2514
|
+
], ObservabilityPlugin.prototype, "_slhttpDidCleanup", 1);
|
|
2515
|
+
__decorateClass([
|
|
2516
|
+
AuthVerifyHook.Will("parseInput", { priority: -1e3 })
|
|
2517
|
+
], ObservabilityPlugin.prototype, "_authVerifyWill", 1);
|
|
2518
|
+
__decorateClass([
|
|
2519
|
+
AuthVerifyHook.Did("determineAuthMode", { priority: 1e3 })
|
|
2520
|
+
], ObservabilityPlugin.prototype, "_authVerifyDidMode", 1);
|
|
2521
|
+
__decorateClass([
|
|
2522
|
+
AuthVerifyHook.Did("verifyToken", { priority: 1e3 })
|
|
2523
|
+
], ObservabilityPlugin.prototype, "_authVerifyDidToken", 1);
|
|
2524
|
+
__decorateClass([
|
|
2525
|
+
AuthVerifyHook.Did("buildAuthorization", { priority: 1e3 })
|
|
2526
|
+
], ObservabilityPlugin.prototype, "_authVerifyDidBuild", 1);
|
|
2527
|
+
__decorateClass([
|
|
2528
|
+
SessionVerifyHook.Will("parseInput", { priority: -1e3 })
|
|
2529
|
+
], ObservabilityPlugin.prototype, "_sessionVerifyWill", 1);
|
|
2530
|
+
__decorateClass([
|
|
2531
|
+
SessionVerifyHook.Did("verifyIfJwt", { priority: 1e3 })
|
|
2532
|
+
], ObservabilityPlugin.prototype, "_sessionVerifyDidJwt", 1);
|
|
2533
|
+
__decorateClass([
|
|
2534
|
+
SessionVerifyHook.Did("buildAuthorizedOutput", { priority: 1e3 })
|
|
2535
|
+
], ObservabilityPlugin.prototype, "_sessionVerifyDidBuild", 1);
|
|
2536
|
+
__decorateClass([
|
|
2537
|
+
OAuthTokenHook.Will("parseInput", { priority: -1e3 })
|
|
2538
|
+
], ObservabilityPlugin.prototype, "_oauthTokenWill", 1);
|
|
2539
|
+
__decorateClass([
|
|
2540
|
+
OAuthTokenHook.Did("buildTokenResponse", { priority: 1e3 })
|
|
2541
|
+
], ObservabilityPlugin.prototype, "_oauthTokenDone", 1);
|
|
2542
|
+
__decorateClass([
|
|
2543
|
+
OAuthAuthorizeHook.Will("parseInput", { priority: -1e3 })
|
|
2544
|
+
], ObservabilityPlugin.prototype, "_oauthAuthzWill", 1);
|
|
2545
|
+
__decorateClass([
|
|
2546
|
+
OAuthAuthorizeHook.Did("buildAuthorizeOutput", { priority: 1e3 })
|
|
2547
|
+
], ObservabilityPlugin.prototype, "_oauthAuthzDone", 1);
|
|
2548
|
+
__decorateClass([
|
|
2549
|
+
OAuthCallbackHook.Will("parseInput", { priority: -1e3 })
|
|
2550
|
+
], ObservabilityPlugin.prototype, "_oauthCallbackWill", 1);
|
|
2551
|
+
__decorateClass([
|
|
2552
|
+
OAuthCallbackHook.Did("redirectToClient", { priority: 1e3 })
|
|
2553
|
+
], ObservabilityPlugin.prototype, "_oauthCallbackDone", 1);
|
|
2554
|
+
__decorateClass([
|
|
2555
|
+
OAuthProviderCallbackHook.Will("parseInput", { priority: -1e3 })
|
|
2556
|
+
], ObservabilityPlugin.prototype, "_oauthProviderWill", 1);
|
|
2557
|
+
__decorateClass([
|
|
2558
|
+
OAuthProviderCallbackHook.Did("handleNextProviderOrComplete", { priority: 1e3 })
|
|
2559
|
+
], ObservabilityPlugin.prototype, "_oauthProviderDone", 1);
|
|
2560
|
+
__decorateClass([
|
|
2561
|
+
OAuthRegisterHook.Will("parseInput", { priority: -1e3 })
|
|
2562
|
+
], ObservabilityPlugin.prototype, "_oauthRegisterWill", 1);
|
|
2563
|
+
__decorateClass([
|
|
2564
|
+
OAuthRegisterHook.Did("respondRegistration", { priority: 1e3 })
|
|
2565
|
+
], ObservabilityPlugin.prototype, "_oauthRegisterDone", 1);
|
|
2566
|
+
__decorateClass([
|
|
2567
|
+
ElicitRequestHook.Will("parseInput", { priority: -1e3 })
|
|
2568
|
+
], ObservabilityPlugin.prototype, "_elicitReqWill", 1);
|
|
2569
|
+
__decorateClass([
|
|
2570
|
+
ElicitRequestHook.Did("finalize", { priority: 1e3 })
|
|
2571
|
+
], ObservabilityPlugin.prototype, "_elicitReqDone", 1);
|
|
2572
|
+
__decorateClass([
|
|
2573
|
+
ElicitResultHook.Will("parseInput", { priority: -1e3 })
|
|
2574
|
+
], ObservabilityPlugin.prototype, "_elicitResWill", 1);
|
|
2575
|
+
__decorateClass([
|
|
2576
|
+
ElicitResultHook.Did("finalize", { priority: 1e3 })
|
|
2577
|
+
], ObservabilityPlugin.prototype, "_elicitResDone", 1);
|
|
2578
|
+
__decorateClass([
|
|
2579
|
+
SubscribeResourceHook.Will("parseInput", { priority: -1e3 })
|
|
2580
|
+
], ObservabilityPlugin.prototype, "_subscribeWill", 1);
|
|
2581
|
+
__decorateClass([
|
|
2582
|
+
SubscribeResourceHook.Did("finalize", { priority: 1e3 })
|
|
2583
|
+
], ObservabilityPlugin.prototype, "_subscribeDone", 1);
|
|
2584
|
+
__decorateClass([
|
|
2585
|
+
UnsubscribeResourceHook.Will("parseInput", { priority: -1e3 })
|
|
2586
|
+
], ObservabilityPlugin.prototype, "_unsubscribeWill", 1);
|
|
2587
|
+
__decorateClass([
|
|
2588
|
+
UnsubscribeResourceHook.Did("finalize", { priority: 1e3 })
|
|
2589
|
+
], ObservabilityPlugin.prototype, "_unsubscribeDone", 1);
|
|
2590
|
+
__decorateClass([
|
|
2591
|
+
SkillsHttpLlmTxtHook.Will("checkEnabled", { priority: -1e3 })
|
|
2592
|
+
], ObservabilityPlugin.prototype, "_skillsLlmTxtWill", 1);
|
|
2593
|
+
__decorateClass([
|
|
2594
|
+
SkillsHttpLlmTxtHook.Did("generateContent", { priority: 1e3 })
|
|
2595
|
+
], ObservabilityPlugin.prototype, "_skillsLlmTxtDone", 1);
|
|
2596
|
+
__decorateClass([
|
|
2597
|
+
SkillsHttpLlmFullTxtHook.Will("checkEnabled", { priority: -1e3 })
|
|
2598
|
+
], ObservabilityPlugin.prototype, "_skillsLlmFullTxtWill", 1);
|
|
2599
|
+
__decorateClass([
|
|
2600
|
+
SkillsHttpLlmFullTxtHook.Did("generateContent", { priority: 1e3 })
|
|
2601
|
+
], ObservabilityPlugin.prototype, "_skillsLlmFullTxtDone", 1);
|
|
2602
|
+
__decorateClass([
|
|
2603
|
+
SkillsHttpApiHook.Will("checkEnabled", { priority: -1e3 })
|
|
2604
|
+
], ObservabilityPlugin.prototype, "_skillsApiWill", 1);
|
|
2605
|
+
__decorateClass([
|
|
2606
|
+
SkillsHttpApiHook.Did("handleRequest", { priority: 1e3 })
|
|
2607
|
+
], ObservabilityPlugin.prototype, "_skillsApiDone", 1);
|
|
2608
|
+
__decorateClass([
|
|
2609
|
+
WellKnownJwksHook.Will("parseInput", { priority: -1e3 })
|
|
2610
|
+
], ObservabilityPlugin.prototype, "_jwksWill", 1);
|
|
2611
|
+
__decorateClass([
|
|
2612
|
+
WellKnownJwksHook.Did("collectData", { priority: 1e3 })
|
|
2613
|
+
], ObservabilityPlugin.prototype, "_jwksDone", 1);
|
|
2614
|
+
__decorateClass([
|
|
2615
|
+
WellKnownOAuthServerHook.Will("parseInput", { priority: -1e3 })
|
|
2616
|
+
], ObservabilityPlugin.prototype, "_oauthServerWill", 1);
|
|
2617
|
+
__decorateClass([
|
|
2618
|
+
WellKnownOAuthServerHook.Did("collectData", { priority: 1e3 })
|
|
2619
|
+
], ObservabilityPlugin.prototype, "_oauthServerDone", 1);
|
|
2620
|
+
__decorateClass([
|
|
2621
|
+
WellKnownPrmHook.Will("parseInput", { priority: -1e3 })
|
|
2622
|
+
], ObservabilityPlugin.prototype, "_prmWill", 1);
|
|
2623
|
+
__decorateClass([
|
|
2624
|
+
WellKnownPrmHook.Did("collectData", { priority: 1e3 })
|
|
2625
|
+
], ObservabilityPlugin.prototype, "_prmDone", 1);
|
|
2626
|
+
__decorateClass([
|
|
2627
|
+
LoggingSetLevelHook.Will("parseInput", { priority: -1e3 })
|
|
2628
|
+
], ObservabilityPlugin.prototype, "_setLevelWill", 1);
|
|
2629
|
+
__decorateClass([
|
|
2630
|
+
LoggingSetLevelHook.Did("finalize", { priority: 1e3 })
|
|
2631
|
+
], ObservabilityPlugin.prototype, "_setLevelDone", 1);
|
|
2632
|
+
__decorateClass([
|
|
2633
|
+
ToolHook.Did("createToolCallContext", { priority: 999 })
|
|
2634
|
+
], ObservabilityPlugin.prototype, "_toolDidCreateCtxFetch", 1);
|
|
2635
|
+
__decorateClass([
|
|
2636
|
+
AgentCallHook.Did("execute", { priority: 999 })
|
|
2637
|
+
], ObservabilityPlugin.prototype, "_agentDidExecuteMeta", 1);
|
|
2638
|
+
ObservabilityPlugin = __decorateClass([
|
|
2639
|
+
Plugin({
|
|
2640
|
+
name: "observability",
|
|
2641
|
+
description: "Full-system OpenTelemetry instrumentation, structured logging, and request logs",
|
|
2642
|
+
providers: [],
|
|
2643
|
+
contextExtensions: [
|
|
2644
|
+
{
|
|
2645
|
+
property: "telemetry",
|
|
2646
|
+
token: TELEMETRY_ACCESSOR,
|
|
2647
|
+
errorMessage: "ObservabilityPlugin is not installed or tracing is disabled. Add ObservabilityPlugin.init() to your plugins array."
|
|
2648
|
+
}
|
|
2649
|
+
]
|
|
2650
|
+
})
|
|
2651
|
+
], ObservabilityPlugin);
|
|
2652
|
+
function resolveOptions(input) {
|
|
2653
|
+
return {
|
|
2654
|
+
tracing: resolveTracingOptions(input.tracing),
|
|
2655
|
+
logging: resolveLoggingOptions(input.logging),
|
|
2656
|
+
requestLogs: resolveRequestLogOptions(input.requestLogs)
|
|
2657
|
+
};
|
|
2658
|
+
}
|
|
2659
|
+
function resolveTracingOptions(input) {
|
|
2660
|
+
if (input === false) return false;
|
|
2661
|
+
if (input === true || input === void 0) return DEFAULT_TRACING;
|
|
2662
|
+
return { ...DEFAULT_TRACING, ...input };
|
|
2663
|
+
}
|
|
2664
|
+
function resolveLoggingOptions(input) {
|
|
2665
|
+
if (input === false || input === void 0) return false;
|
|
2666
|
+
if (input === true) return {};
|
|
2667
|
+
return input;
|
|
2668
|
+
}
|
|
2669
|
+
function resolveRequestLogOptions(input) {
|
|
2670
|
+
if (input === false || input === void 0) return false;
|
|
2671
|
+
if (input === true) return {};
|
|
2672
|
+
return input;
|
|
2673
|
+
}
|
|
2674
|
+
|
|
2675
|
+
// libs/observability/src/otel/context-propagator.ts
|
|
2676
|
+
import {
|
|
2677
|
+
trace as trace6
|
|
2678
|
+
} from "@opentelemetry/api";
|
|
2679
|
+
var TRACEPARENT_HEADER = "traceparent";
|
|
2680
|
+
var FrontMcpPropagator = class {
|
|
2681
|
+
inject(context, carrier, setter) {
|
|
2682
|
+
const span = trace6.getSpan(context);
|
|
2683
|
+
if (!span) return;
|
|
2684
|
+
const sc = span.spanContext();
|
|
2685
|
+
if (!sc || !isValidSpanContext(sc)) return;
|
|
2686
|
+
const flags = sc.traceFlags.toString(16).padStart(2, "0");
|
|
2687
|
+
const traceparent = `00-${sc.traceId}-${sc.spanId}-${flags}`;
|
|
2688
|
+
setter.set(carrier, TRACEPARENT_HEADER, traceparent);
|
|
2689
|
+
}
|
|
2690
|
+
extract(context, carrier, getter) {
|
|
2691
|
+
const traceparent = getter.get(carrier, TRACEPARENT_HEADER);
|
|
2692
|
+
const value = Array.isArray(traceparent) ? traceparent[0] : traceparent;
|
|
2693
|
+
if (!value) return context;
|
|
2694
|
+
const parsed = parseTraceparent(value);
|
|
2695
|
+
if (!parsed) return context;
|
|
2696
|
+
const spanContext = {
|
|
2697
|
+
traceId: parsed.traceId,
|
|
2698
|
+
spanId: parsed.parentId,
|
|
2699
|
+
traceFlags: parsed.traceFlags,
|
|
2700
|
+
isRemote: true
|
|
2701
|
+
};
|
|
2702
|
+
const span = trace6.wrapSpanContext(spanContext);
|
|
2703
|
+
return trace6.setSpan(context, span);
|
|
2704
|
+
}
|
|
2705
|
+
fields() {
|
|
2706
|
+
return [TRACEPARENT_HEADER];
|
|
2707
|
+
}
|
|
2708
|
+
};
|
|
2709
|
+
function parseTraceparent(value) {
|
|
2710
|
+
const parts = value.split("-");
|
|
2711
|
+
if (parts.length !== 4) return null;
|
|
2712
|
+
const [version, traceId, parentId, flags] = parts;
|
|
2713
|
+
if (version !== "00") return null;
|
|
2714
|
+
if (!/^[a-f0-9]{32}$/i.test(traceId) || traceId === "00000000000000000000000000000000") return null;
|
|
2715
|
+
if (!/^[a-f0-9]{16}$/i.test(parentId) || parentId === "0000000000000000") return null;
|
|
2716
|
+
if (!/^[0-9a-fA-F]{2}$/.test(flags)) return null;
|
|
2717
|
+
const traceFlags = parseInt(flags, 16);
|
|
2718
|
+
return {
|
|
2719
|
+
traceId: traceId.toLowerCase(),
|
|
2720
|
+
parentId: parentId.toLowerCase(),
|
|
2721
|
+
traceFlags
|
|
2722
|
+
};
|
|
2723
|
+
}
|
|
2724
|
+
function isValidSpanContext(sc) {
|
|
2725
|
+
return sc.traceId !== "00000000000000000000000000000000" && sc.spanId !== "0000000000000000" && sc.traceId.length === 32 && sc.spanId.length === 16;
|
|
2726
|
+
}
|
|
2727
|
+
|
|
2728
|
+
// libs/observability/src/otel/otel.setup.ts
|
|
2729
|
+
function setupOTel(options) {
|
|
2730
|
+
const serviceName = options?.serviceName ?? process.env["OTEL_SERVICE_NAME"] ?? "frontmcp-server";
|
|
2731
|
+
const exporterType = options?.exporter ?? "console";
|
|
2732
|
+
const endpoint = options?.endpoint ?? process.env["OTEL_EXPORTER_OTLP_ENDPOINT"] ?? "http://localhost:4318";
|
|
2733
|
+
let traceExporter;
|
|
2734
|
+
if (exporterType === "otlp") {
|
|
2735
|
+
try {
|
|
2736
|
+
const { OTLPTraceExporter } = __require("@opentelemetry/exporter-trace-otlp-http");
|
|
2737
|
+
traceExporter = new OTLPTraceExporter({ url: `${endpoint}/v1/traces` });
|
|
2738
|
+
} catch {
|
|
2739
|
+
throw new Error(
|
|
2740
|
+
"setupOTel: @opentelemetry/exporter-trace-otlp-http is required for OTLP export. Install it with: npm install @opentelemetry/exporter-trace-otlp-http"
|
|
2741
|
+
);
|
|
2742
|
+
}
|
|
2743
|
+
} else if (exporterType === "console") {
|
|
2744
|
+
const { ConsoleSpanExporter } = __require("@opentelemetry/sdk-trace-base");
|
|
2745
|
+
traceExporter = new ConsoleSpanExporter();
|
|
2746
|
+
}
|
|
2747
|
+
try {
|
|
2748
|
+
const { NodeSDK } = __require("@opentelemetry/sdk-node");
|
|
2749
|
+
const { Resource } = __require("@opentelemetry/resources");
|
|
2750
|
+
const { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } = __require("@opentelemetry/semantic-conventions");
|
|
2751
|
+
const resource = new Resource({
|
|
2752
|
+
[ATTR_SERVICE_NAME]: serviceName,
|
|
2753
|
+
...options?.serviceVersion ? { [ATTR_SERVICE_VERSION]: options.serviceVersion } : {}
|
|
2754
|
+
});
|
|
2755
|
+
const sdk = new NodeSDK({
|
|
2756
|
+
resource,
|
|
2757
|
+
traceExporter
|
|
2758
|
+
});
|
|
2759
|
+
sdk.start();
|
|
2760
|
+
return async () => {
|
|
2761
|
+
await sdk.shutdown();
|
|
2762
|
+
};
|
|
2763
|
+
} catch {
|
|
2764
|
+
throw new Error(
|
|
2765
|
+
"setupOTel: @opentelemetry/sdk-node is required. Install it with: npm install @opentelemetry/sdk-node @opentelemetry/resources @opentelemetry/semantic-conventions"
|
|
2766
|
+
);
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2770
|
+
// libs/observability/src/otel/spans/hook.span.ts
|
|
2771
|
+
import { SpanKind as SpanKind13 } from "@opentelemetry/api";
|
|
2772
|
+
function recordHookEvent(parentSpan, stage, owner) {
|
|
2773
|
+
const attributes = {};
|
|
2774
|
+
if (owner) {
|
|
2775
|
+
attributes[FrontMcpAttributes.HOOK_OWNER] = owner;
|
|
2776
|
+
}
|
|
2777
|
+
parentSpan.addEvent(`hook.${stage}`, attributes);
|
|
2778
|
+
}
|
|
2779
|
+
function startHookSpan(tracer, options) {
|
|
2780
|
+
const attributes = {
|
|
2781
|
+
[FrontMcpAttributes.HOOK_STAGE]: options.stage
|
|
2782
|
+
};
|
|
2783
|
+
if (options.owner) {
|
|
2784
|
+
attributes[FrontMcpAttributes.HOOK_OWNER] = options.owner;
|
|
2785
|
+
}
|
|
2786
|
+
if (options.flowName) {
|
|
2787
|
+
attributes[FrontMcpAttributes.FLOW_NAME] = options.flowName;
|
|
2788
|
+
}
|
|
2789
|
+
return startSpan(tracer, {
|
|
2790
|
+
name: `hook ${options.stage}`,
|
|
2791
|
+
kind: SpanKind13.INTERNAL,
|
|
2792
|
+
attributes,
|
|
2793
|
+
parentContext: options.parentContext
|
|
2794
|
+
});
|
|
2795
|
+
}
|
|
2796
|
+
|
|
2797
|
+
// libs/observability/src/otel/spans/pretty-span-exporter.ts
|
|
2798
|
+
import { SpanKind as SpanKind14, SpanStatusCode as SpanStatusCode3 } from "@opentelemetry/api";
|
|
2799
|
+
var RESET = "\x1B[0m";
|
|
2800
|
+
var DIM = "\x1B[2m";
|
|
2801
|
+
var BOLD = "\x1B[1m";
|
|
2802
|
+
var CYAN = "\x1B[36m";
|
|
2803
|
+
var GREEN = "\x1B[32m";
|
|
2804
|
+
var RED = "\x1B[31m";
|
|
2805
|
+
var YELLOW = "\x1B[33m";
|
|
2806
|
+
var KIND_LABELS = {
|
|
2807
|
+
[SpanKind14.INTERNAL]: "INTERNAL",
|
|
2808
|
+
[SpanKind14.SERVER]: "SERVER",
|
|
2809
|
+
[SpanKind14.CLIENT]: "CLIENT",
|
|
2810
|
+
[SpanKind14.PRODUCER]: "PRODUCER",
|
|
2811
|
+
[SpanKind14.CONSUMER]: "CONSUMER"
|
|
2812
|
+
};
|
|
2813
|
+
var SHOW_ATTRS = /* @__PURE__ */ new Set([
|
|
2814
|
+
"rpc.system",
|
|
2815
|
+
"rpc.method",
|
|
2816
|
+
"rpc.service",
|
|
2817
|
+
"mcp.method.name",
|
|
2818
|
+
"mcp.session.id",
|
|
2819
|
+
"mcp.component.type",
|
|
2820
|
+
"mcp.component.key",
|
|
2821
|
+
"http.request.method",
|
|
2822
|
+
"http.response.status_code",
|
|
2823
|
+
"url.path",
|
|
2824
|
+
"frontmcp.tool.name",
|
|
2825
|
+
"frontmcp.tool.owner",
|
|
2826
|
+
"frontmcp.transport.type",
|
|
2827
|
+
"frontmcp.transport.request_type",
|
|
2828
|
+
"frontmcp.auth.mode",
|
|
2829
|
+
"frontmcp.auth.result",
|
|
2830
|
+
"frontmcp.flow.name",
|
|
2831
|
+
"enduser.id"
|
|
2832
|
+
]);
|
|
2833
|
+
var PrettySpanExporter = class {
|
|
2834
|
+
constructor() {
|
|
2835
|
+
this.useAnsi = typeof process !== "undefined" && !!process.stdout?.isTTY;
|
|
2836
|
+
}
|
|
2837
|
+
export(spans, resultCallback) {
|
|
2838
|
+
for (const span of spans) {
|
|
2839
|
+
console.log(this.format(span));
|
|
2840
|
+
}
|
|
2841
|
+
resultCallback({ code: 0 });
|
|
2842
|
+
}
|
|
2843
|
+
shutdown() {
|
|
2844
|
+
return Promise.resolve();
|
|
2845
|
+
}
|
|
2846
|
+
format(span) {
|
|
2847
|
+
const traceShort = span.spanContext().traceId.slice(0, 8);
|
|
2848
|
+
const durationMs = (span.duration[0] * 1e3 + span.duration[1] / 1e6).toFixed(1);
|
|
2849
|
+
const kind = KIND_LABELS[span.kind] ?? "UNKNOWN";
|
|
2850
|
+
const statusOk = span.status.code !== SpanStatusCode3.ERROR;
|
|
2851
|
+
const attrs = Object.entries(span.attributes).filter(([k]) => SHOW_ATTRS.has(k)).map(([k, v]) => {
|
|
2852
|
+
const short = k.replace("frontmcp.", "").replace("mcp.", "");
|
|
2853
|
+
return `${short}=${v}`;
|
|
2854
|
+
}).join(" ");
|
|
2855
|
+
const eventCount = span.events.length;
|
|
2856
|
+
const eventSummary = eventCount > 0 ? ` (${eventCount} events)` : "";
|
|
2857
|
+
if (this.useAnsi) {
|
|
2858
|
+
const statusColor = statusOk ? GREEN : RED;
|
|
2859
|
+
const kindColor = span.kind === SpanKind14.SERVER ? CYAN : DIM;
|
|
2860
|
+
return [
|
|
2861
|
+
`${DIM}\u21B3${RESET}`,
|
|
2862
|
+
`${BOLD}${statusColor}SPAN${RESET}`,
|
|
2863
|
+
`${BOLD}${span.name}${RESET}`,
|
|
2864
|
+
`${DIM}[${traceShort}]${RESET}`,
|
|
2865
|
+
`${YELLOW}${durationMs}ms${RESET}`,
|
|
2866
|
+
`${kindColor}${kind}${RESET}`,
|
|
2867
|
+
attrs ? `${DIM}${attrs}${RESET}` : "",
|
|
2868
|
+
eventSummary ? `${DIM}${eventSummary}${RESET}` : ""
|
|
2869
|
+
].filter(Boolean).join(" ");
|
|
2870
|
+
}
|
|
2871
|
+
return ["\u21B3 SPAN", span.name, `[${traceShort}]`, `${durationMs}ms`, kind, attrs, eventSummary].filter(Boolean).join(" ");
|
|
2872
|
+
}
|
|
2873
|
+
};
|
|
2874
|
+
|
|
2875
|
+
// libs/observability/src/logging/sinks/index.ts
|
|
2876
|
+
init_winston_sink();
|
|
2877
|
+
init_pino_sink();
|
|
2878
|
+
init_otlp_sink();
|
|
2879
|
+
|
|
2880
|
+
// libs/observability/src/testing/index.ts
|
|
2881
|
+
import {
|
|
2882
|
+
BasicTracerProvider,
|
|
2883
|
+
InMemorySpanExporter,
|
|
2884
|
+
SimpleSpanProcessor
|
|
2885
|
+
} from "@opentelemetry/sdk-trace-base";
|
|
2886
|
+
function createTestTracer(name = "test") {
|
|
2887
|
+
const exporter = new InMemorySpanExporter();
|
|
2888
|
+
const provider = new BasicTracerProvider();
|
|
2889
|
+
provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
|
|
2890
|
+
const tracer = provider.getTracer(name);
|
|
2891
|
+
return {
|
|
2892
|
+
tracer,
|
|
2893
|
+
exporter,
|
|
2894
|
+
provider,
|
|
2895
|
+
cleanup: async () => {
|
|
2896
|
+
exporter.reset();
|
|
2897
|
+
await provider.forceFlush();
|
|
2898
|
+
await provider.shutdown();
|
|
2899
|
+
}
|
|
2900
|
+
};
|
|
2901
|
+
}
|
|
2902
|
+
function getFinishedSpans(exporter) {
|
|
2903
|
+
return exporter.getFinishedSpans();
|
|
2904
|
+
}
|
|
2905
|
+
function assertSpanExists(spans, name) {
|
|
2906
|
+
const match = spans.find((s) => s.name === name);
|
|
2907
|
+
if (!match) {
|
|
2908
|
+
const names = spans.map((s) => s.name).join(", ");
|
|
2909
|
+
throw new Error(`Expected span "${name}" but found: [${names}]`);
|
|
2910
|
+
}
|
|
2911
|
+
return match;
|
|
2912
|
+
}
|
|
2913
|
+
function assertSpanAttribute(span, key, value) {
|
|
2914
|
+
const actual = span.attributes[key];
|
|
2915
|
+
if (actual !== value) {
|
|
2916
|
+
throw new Error(
|
|
2917
|
+
`Expected span "${span.name}" attribute "${key}" to be ${JSON.stringify(value)} but got ${JSON.stringify(actual)}`
|
|
2918
|
+
);
|
|
2919
|
+
}
|
|
2920
|
+
}
|
|
2921
|
+
function findSpan(spans, name) {
|
|
2922
|
+
return spans.find((s) => s.name === name);
|
|
2923
|
+
}
|
|
2924
|
+
function findSpansByAttribute(spans, key, value) {
|
|
2925
|
+
return spans.filter((s) => s.attributes[key] === value);
|
|
2926
|
+
}
|
|
2927
|
+
export {
|
|
2928
|
+
CallbackSink,
|
|
2929
|
+
ConsoleSink,
|
|
2930
|
+
EnduserAttributes,
|
|
2931
|
+
FrontMcpAttributes,
|
|
2932
|
+
FrontMcpPropagator,
|
|
2933
|
+
HttpAttributes,
|
|
2934
|
+
LOG_LEVEL_TO_OTEL_SEVERITY,
|
|
2935
|
+
McpAttributes,
|
|
2936
|
+
OTEL_CONFIG,
|
|
2937
|
+
OTEL_TRACER,
|
|
2938
|
+
ObservabilityPlugin,
|
|
2939
|
+
OtlpSink,
|
|
2940
|
+
PinoSink,
|
|
2941
|
+
PrettySpanExporter,
|
|
2942
|
+
REQUEST_LOG_COLLECTOR,
|
|
2943
|
+
RequestLogCollector,
|
|
2944
|
+
RpcAttributes,
|
|
2945
|
+
StdoutSink,
|
|
2946
|
+
StructuredLogTransport,
|
|
2947
|
+
TELEMETRY_ACCESSOR,
|
|
2948
|
+
TelemetryAccessor,
|
|
2949
|
+
TelemetrySpan,
|
|
2950
|
+
WinstonSink,
|
|
2951
|
+
assertSpanAttribute,
|
|
2952
|
+
assertSpanExists,
|
|
2953
|
+
createOTelContextFromTrace,
|
|
2954
|
+
createSink,
|
|
2955
|
+
createSinks,
|
|
2956
|
+
createTestTracer,
|
|
2957
|
+
emitStartupReport,
|
|
2958
|
+
endSpanError,
|
|
2959
|
+
endSpanOk,
|
|
2960
|
+
findSpan,
|
|
2961
|
+
findSpansByAttribute,
|
|
2962
|
+
frontmcpToOTelSpanContext,
|
|
2963
|
+
getFinishedSpans,
|
|
2964
|
+
otelToFrontmcpContext,
|
|
2965
|
+
recordHookEvent,
|
|
2966
|
+
redactFields,
|
|
2967
|
+
reportStartup,
|
|
2968
|
+
sessionTracingId,
|
|
2969
|
+
setAuthMode,
|
|
2970
|
+
setAuthResult,
|
|
2971
|
+
setFetchResponseStatus,
|
|
2972
|
+
setHttpResponseStatus,
|
|
2973
|
+
setTransportRequestType,
|
|
2974
|
+
setupOTel,
|
|
2975
|
+
startAuthSpan,
|
|
2976
|
+
startFetchSpan,
|
|
2977
|
+
startHookSpan,
|
|
2978
|
+
startHttpServerSpan,
|
|
2979
|
+
startPromptSpan,
|
|
2980
|
+
startResourceSpan,
|
|
2981
|
+
startRpcSpan,
|
|
2982
|
+
startSpan,
|
|
2983
|
+
startToolSpan,
|
|
2984
|
+
startTransportSpan,
|
|
2985
|
+
withSpan
|
|
2986
|
+
};
|