fix(otel): show workbench api spans in trace summary (#795)

Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
Lyon
2026-06-24 07:21:30 +08:00
committed by GitHub
parent 6abc904a6e
commit d45fc1890e
+28 -3
View File
@@ -823,15 +823,17 @@ function renderTraceTable(input: {
? [...asArray(input.result.errorSpans), ...asArray(input.result.spans)]
: asArray(input.result.spans);
const spanRows = uniqueSpanRecords(spanSource)
.sort((left, right) => traceSpanImportanceScore(right) - traceSpanImportanceScore(left))
.slice(0, 10)
.map((span) => {
const attrs = asPlainRecord(span.attributes);
const durationMs = traceSpanDurationMs(span, attrs);
return [
shortenEnd(textValue(span.name), 40),
shortenEnd(textValue(span.service), 22),
shortenEnd(spanColumnAttr(attrs, ["http.route", "workbench.ui.route"]), 34),
spanColumnAttr(attrs, ["http.response.status_code", "http.status_code", "http.response.status_class"]),
spanColumnAttr(attrs, ["workbench.ui.value_ms"]),
numberValue(durationMs),
spanColumnAttr(attrs, ["workbench.ui.resource_duration_ms"]),
spanColumnAttr(attrs, ["workbench.ui.resource_fetch_to_request_ms"]),
spanColumnAttr(attrs, ["workbench.ui.resource_request_wait_ms"]),
@@ -865,7 +867,7 @@ function renderTraceTable(input: {
formatTable(["FIELD", "VALUE"], identityRows.length > 0 ? identityRows : [["-", "-"]]),
"",
"Key spans:",
formatTable(["NAME", "SERVICE", "ROUTE", "STATUS", "VALUE_MS", "RES_MS", "FETCH_REQ", "REQ_WAIT", "RESP_XFER", "PROTO", "DETAIL"], spanRows.length > 0 ? spanRows : [["-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-"]]),
formatTable(["NAME", "SERVICE", "ROUTE", "STATUS", "DUR_MS", "RES_MS", "FETCH_REQ", "REQ_WAIT", "RESP_XFER", "PROTO", "DETAIL"], spanRows.length > 0 ? spanRows : [["-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-"]]),
"",
"Span name counts:",
formatTable(["NAME", "COUNT"], countRows.length > 0 ? countRows : [["-", "-"]]),
@@ -1023,6 +1025,29 @@ function renderDiagnoseCodeAgentTable(input: {
};
}
function traceSpanDurationMs(span: Record<string, unknown>, attrs: Record<string, unknown> | null): number {
const topLevel = numberFromUnknown(span.durationMs);
if (Number.isFinite(topLevel)) return topLevel;
if (attrs === null) return Number.NaN;
for (const key of ["workbench.ui.value_ms", "workbench.ui.resource_duration_ms", "durationMs"]) {
const value = numberFromUnknown(attrs[key]);
if (Number.isFinite(value)) return value;
}
return Number.NaN;
}
function traceSpanImportanceScore(span: Record<string, unknown>): number {
const attrs = asPlainRecord(span.attributes);
const statusCode = textValue(span.statusCode);
const name = textValue(span.name).toLowerCase();
const hasFailure = spanColumnAttr(attrs, ["failureKind", "errorSummary", "error.message", "exception.message"]) !== "-";
const terminalStatus = spanColumnAttr(attrs, ["terminalStatus"]);
const problemScore = statusCode === "STATUS_CODE_ERROR" || statusCode === "2" || name.includes("error") || hasFailure || terminalStatus === "failed" || terminalStatus === "blocked" ? 1_000_000_000 : 0;
const durationMs = traceSpanDurationMs(span, attrs);
const durationScore = Number.isFinite(durationMs) ? durationMs : 0;
return problemScore + durationScore;
}
function searchTraceStatus(trace: Record<string, unknown>): string {
if (trace.queryOk === false) return "query-bad";
if (trace.parseOk === false) return "parse-bad";
@@ -2297,7 +2322,7 @@ for batch in batches_from_body(parsed):
error_spans.append(item)
if matched:
matched_spans.append(item)
if error or name in IMPORTANT_NAMES or name.startswith("runner_error.") or name.startswith("runner_terminal."):
if error or name in IMPORTANT_NAMES or name.startswith("runner_error.") or name.startswith("runner_terminal.") or name.startswith("workbench.api_request."):
signature = key_signature(item)
if signature not in seen_key_spans:
seen_key_spans.add(signature)