From d45fc1890ef43986d7984d1ff3836653648d7288 Mon Sep 17 00:00:00 2001 From: Lyon <88232613+pikasTech@users.noreply.github.com> Date: Wed, 24 Jun 2026 07:21:30 +0800 Subject: [PATCH] fix(otel): show workbench api spans in trace summary (#795) Co-authored-by: Codex --- scripts/src/platform-infra-observability.ts | 31 +++++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/scripts/src/platform-infra-observability.ts b/scripts/src/platform-infra-observability.ts index fb1b8ad5..7ed73cc0 100644 --- a/scripts/src/platform-infra-observability.ts +++ b/scripts/src/platform-infra-observability.ts @@ -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, attrs: Record | 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): 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 { 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)