fix(workbench): tag read model not found spans (#1990)
Co-authored-by: root <root@lyon.remote>
This commit is contained in:
@@ -270,6 +270,33 @@ function attachWorkbenchRealtimeOtelContext(request, fields = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
function attachWorkbenchReadModelDiagnosticOtel(request, fields = {}) {
|
||||
const context = request?.hwlabHttpRequestContext;
|
||||
if (!context) return;
|
||||
const code = textValue(fields.code) || "workbench_read_model_not_found";
|
||||
const route = textValue(fields.route) || context.route || "/v1/workbench";
|
||||
context.route = route;
|
||||
context.lastHttpError = {
|
||||
code,
|
||||
category: "workbench_read_model",
|
||||
layer: "workbench.read_model"
|
||||
};
|
||||
context.otelAttributes = {
|
||||
...(context.otelAttributes ?? {}),
|
||||
"workbench.route": route,
|
||||
"workbench.read_model.route": route,
|
||||
"workbench.read_model.result": code,
|
||||
"workbench.read_model.count": Number.isFinite(Number(fields.count)) ? Math.trunc(Number(fields.count)) : null,
|
||||
"workbench.session_id": fields.sessionId ?? null,
|
||||
"workbench.trace_id": fields.traceId ?? null,
|
||||
"workbench.turn_id": fields.turnId ?? null,
|
||||
traceId: fields.traceId ?? null,
|
||||
"error.code": code,
|
||||
"error.category": "workbench_read_model",
|
||||
"error.layer": "workbench.read_model"
|
||||
};
|
||||
}
|
||||
|
||||
function emitWorkbenchRealtimeAcceptedOtelSpan(request, env = process.env) {
|
||||
const context = request?.hwlabHttpRequestContext;
|
||||
if (!context?.traceId) return;
|
||||
@@ -1237,7 +1264,11 @@ async function handleWorkbenchSessionDetail(request, response, options, actor, s
|
||||
const result = await queryFactsByRouteId(readModel, sessionId, { families: WORKBENCH_SESSION_DETAIL_FAMILIES });
|
||||
if (result.error) return sendJson(response, 503, workbenchProjectionStoreError(result.error));
|
||||
const session = visibleFactSessions(result.facts, actor)[0] ?? null;
|
||||
if (!session) return sendJson(response, 404, workbenchError("workbench_session_not_found", "Workbench session is not visible to the current actor.", { sessionId }));
|
||||
if (!session) {
|
||||
const body = workbenchError("workbench_session_not_found", "Workbench session is not visible to the current actor.", { sessionId });
|
||||
attachWorkbenchReadModelDiagnosticOtel(request, { route: "/v1/workbench/sessions/:id", code: "workbench_session_not_found", sessionId, count: result.count });
|
||||
return sendJson(response, 404, body);
|
||||
}
|
||||
sendJson(response, 200, {
|
||||
ok: true,
|
||||
status: "found",
|
||||
@@ -1253,7 +1284,11 @@ async function handleWorkbenchMessagePage(request, response, url, options, actor
|
||||
const result = await queryFactsByRouteId(readModel, sessionId, { families: WORKBENCH_SESSION_MESSAGE_PAGE_FAMILIES });
|
||||
if (result.error) return sendJson(response, 503, workbenchProjectionStoreError(result.error));
|
||||
const session = visibleFactSessions(result.facts, actor)[0] ?? null;
|
||||
if (!session) return sendJson(response, 404, workbenchError("workbench_session_not_found", "Workbench session is not visible to the current actor.", { sessionId }));
|
||||
if (!session) {
|
||||
const body = workbenchError("workbench_session_not_found", "Workbench session is not visible to the current actor.", { sessionId });
|
||||
attachWorkbenchReadModelDiagnosticOtel(request, { route: "/v1/workbench/sessions/:id/messages", code: "workbench_session_not_found", sessionId, count: result.count });
|
||||
return sendJson(response, 404, body);
|
||||
}
|
||||
const messages = factMessagesForSession(session, result.facts);
|
||||
const limit = boundedLimit(url.searchParams.get("limit"));
|
||||
const offset = cursorOffset(url.searchParams.get("cursor") ?? url.searchParams.get("after"));
|
||||
@@ -1298,6 +1333,7 @@ async function handleWorkbenchTurnSnapshot(request, response, url, options, acto
|
||||
const found = Boolean(session || turn);
|
||||
if (!found) {
|
||||
const body = workbenchError("workbench_turn_not_found", "Workbench turn is not visible to the current actor.", { turnId, traceId });
|
||||
attachWorkbenchReadModelDiagnosticOtel(request, { route: "/v1/workbench/turns/:id", code: "workbench_turn_not_found", traceId, turnId, count: result.count });
|
||||
recordWorkbenchTurnReadMetric(options, url, 404, body, startedAt);
|
||||
return sendJson(response, 404, body);
|
||||
}
|
||||
@@ -1351,8 +1387,10 @@ async function handleWorkbenchTraceEventPage(request, response, url, options, ac
|
||||
if (contextSession || contextTurn) {
|
||||
const projection = factProjectionForTrace(context.facts, traceId);
|
||||
const blocker = traceEventsReadModelBlocker("workbench_trace_metadata_missing", "Workbench trace metadata is missing from the trace events read model.", { traceId, projection, session: contextSession, turn: contextTurn, route: url.pathname });
|
||||
attachWorkbenchReadModelDiagnosticOtel(request, { route: "/v1/workbench/traces/:id/events", code: "workbench_trace_metadata_missing", sessionId: factSessionId(contextSession), traceId, count: context.count });
|
||||
return sendJson(response, 404, workbenchTraceEventsReadModelError(blocker, { traceId, projection, session: contextSession, turn: contextTurn }));
|
||||
}
|
||||
attachWorkbenchReadModelDiagnosticOtel(request, { route: "/v1/workbench/traces/:id/events", code: "workbench_trace_not_found", traceId, count: context.count });
|
||||
return sendJson(response, 404, workbenchError("workbench_trace_not_found", "Workbench trace is not visible to the current actor.", { traceId }));
|
||||
}
|
||||
const projection = factProjectionForTrace(metadataFacts, traceId);
|
||||
|
||||
Reference in New Issue
Block a user