fix: diagnose code agent by agentrun ids
This commit is contained in:
@@ -61,7 +61,11 @@ export function compactDiagnoseCodeAgentResult(value: unknown): Record<string, u
|
||||
mapping: mapping === null ? null : {
|
||||
mode: mapping.mode ?? null,
|
||||
businessTraceId: mapping.businessTraceId ?? null,
|
||||
runId: mapping.runId ?? null,
|
||||
commandId: mapping.commandId ?? null,
|
||||
runnerJobId: mapping.runnerJobId ?? null,
|
||||
otelTraceId: mapping.otelTraceId ?? null,
|
||||
searchQuery: mapping.searchQuery ?? null,
|
||||
searchOk: mapping.searchOk ?? null,
|
||||
searchParseOk: mapping.searchParseOk ?? null,
|
||||
candidateTraceCount: mapping.candidateTraceCount ?? null,
|
||||
@@ -143,6 +147,8 @@ export function compactDiagnoseAgentRun(value: unknown): Record<string, unknown>
|
||||
terminalSource: agentrun.terminalSource ?? null,
|
||||
latestSeq: agentrun.latestSeq ?? null,
|
||||
terminalEventType: agentrun.terminalEventType ?? null,
|
||||
failureKind: agentrun.failureKind ?? null,
|
||||
observedFailureKinds: limitArray(agentrun.observedFailureKinds, 5),
|
||||
runnerProviderClassification: agentrun.runnerProviderClassification ?? null,
|
||||
authority: compactAgentRunAuthority(agentrun.authority),
|
||||
};
|
||||
@@ -166,6 +172,7 @@ export function compactAgentRunAuthority(value: unknown): Record<string, unknown
|
||||
terminalSource: authority.terminalSource ?? null,
|
||||
terminalEventSeq: authority.terminalEventSeq ?? null,
|
||||
terminalEventType: authority.terminalEventType ?? null,
|
||||
failureKind: authority.failureKind ?? null,
|
||||
latestSeq: authority.latestSeq ?? null,
|
||||
eventCount: authority.eventCount ?? null,
|
||||
fallback: authority.fallback ?? null,
|
||||
|
||||
@@ -746,14 +746,75 @@ PY
|
||||
`;
|
||||
}
|
||||
|
||||
function cliArg(value: string): string {
|
||||
return /^[A-Za-z0-9_./:=@+-]+$/u.test(value) ? value : shQuote(value);
|
||||
}
|
||||
|
||||
function diagnoseSearchFilters(options: DiagnoseCodeAgentOptions): string[] {
|
||||
const filters: string[] = [];
|
||||
if (options.businessTraceId !== null) filters.push(`.traceId = ${JSON.stringify(options.businessTraceId)}`);
|
||||
if (options.runId !== null) filters.push(`.runId = ${JSON.stringify(options.runId)}`);
|
||||
if (options.commandId !== null) filters.push(`.commandId = ${JSON.stringify(options.commandId)}`);
|
||||
if (options.runnerJobId !== null) filters.push(`.runnerJobId = ${JSON.stringify(options.runnerJobId)}`);
|
||||
return filters;
|
||||
}
|
||||
|
||||
function diagnoseSearchMode(options: DiagnoseCodeAgentOptions): string {
|
||||
if (options.businessTraceId !== null && options.runId === null && options.commandId === null && options.runnerJobId === null) return "business-trace-id";
|
||||
if (options.traceId !== null) return "trace-id";
|
||||
return "trace-attribute-query";
|
||||
}
|
||||
|
||||
function buildDiagnoseCodeAgentCommand(target: ObservabilityTarget, options: DiagnoseCodeAgentOptions, full: boolean): string {
|
||||
const parts = ["bun", "scripts/cli.ts", "platform-infra", "observability", "diagnose-code-agent", "--target", target.id];
|
||||
if (options.businessTraceId !== null) parts.push("--business-trace-id", options.businessTraceId);
|
||||
if (options.traceId !== null) parts.push("--trace-id", options.traceId);
|
||||
if (options.runId !== null) parts.push("--run-id", options.runId);
|
||||
if (options.commandId !== null) parts.push("--command-id", options.commandId);
|
||||
if (options.runnerJobId !== null) parts.push("--runner-job-id", options.runnerJobId);
|
||||
parts.push("--lookback-minutes", String(options.lookbackMinutes), "--candidate-limit", String(options.candidateLimit), "--limit", String(options.limit));
|
||||
if (full) parts.push("--full");
|
||||
return parts.map(cliArg).join(" ");
|
||||
}
|
||||
|
||||
function buildDiagnoseSearchCommand(target: ObservabilityTarget, tempoQuery: string | null): string {
|
||||
const query = tempoQuery ?? "{ .traceId = \"<trc_...>\" }";
|
||||
return [
|
||||
"bun",
|
||||
"scripts/cli.ts",
|
||||
"platform-infra",
|
||||
"observability",
|
||||
"search",
|
||||
"--target",
|
||||
target.id,
|
||||
"--query",
|
||||
query,
|
||||
"--lookback-minutes",
|
||||
"10080",
|
||||
"--candidate-limit",
|
||||
"500",
|
||||
"--limit",
|
||||
"10",
|
||||
].map(cliArg).join(" ");
|
||||
}
|
||||
|
||||
export function diagnoseCodeAgentScript(observability: ObservabilityConfig, target: ObservabilityTarget, searchPath: string | null, options: DiagnoseCodeAgentOptions): string {
|
||||
const proxyPrefix = `/api/v1/namespaces/${target.namespace}/services/http:${observability.traceBackend.serviceName}:http/proxy`;
|
||||
const searchProxyPath = searchPath === null ? null : `${proxyPrefix}${searchPath}`;
|
||||
const traceIdLiteral = options.traceId === null ? "None" : JSON.stringify(options.traceId);
|
||||
const businessTraceIdLiteral = options.businessTraceId === null ? "None" : JSON.stringify(options.businessTraceId);
|
||||
const runIdLiteral = options.runId === null ? "None" : JSON.stringify(options.runId);
|
||||
const commandIdLiteral = options.commandId === null ? "None" : JSON.stringify(options.commandId);
|
||||
const runnerJobIdLiteral = options.runnerJobId === null ? "None" : JSON.stringify(options.runnerJobId);
|
||||
const searchPathLiteral = searchPath === null ? "None" : JSON.stringify(searchPath);
|
||||
const searchProxyPathLiteral = searchProxyPath === null ? "None" : JSON.stringify(searchProxyPath);
|
||||
const businessTraceIdForNext = options.businessTraceId ?? "<trc_...>";
|
||||
const tempoQuery = (() => {
|
||||
const filters = diagnoseSearchFilters(options);
|
||||
return filters.length > 0 ? `{ ${filters.join(" && ")} }` : null;
|
||||
})();
|
||||
const searchMode = diagnoseSearchMode(options);
|
||||
const diagnoseFullCommand = buildDiagnoseCodeAgentCommand(target, options, true);
|
||||
const searchCommand = buildDiagnoseSearchCommand(target, tempoQuery);
|
||||
return `
|
||||
set -u
|
||||
python3 - <<'PY'
|
||||
@@ -761,11 +822,18 @@ import collections, json, re, subprocess, time, urllib.parse
|
||||
|
||||
BUSINESS_TRACE_ID = ${businessTraceIdLiteral}
|
||||
TRACE_ID = ${traceIdLiteral}
|
||||
RUN_ID = ${runIdLiteral}
|
||||
COMMAND_ID = ${commandIdLiteral}
|
||||
RUNNER_JOB_ID = ${runnerJobIdLiteral}
|
||||
TARGET_ID = ${JSON.stringify(target.id)}
|
||||
SEARCH_MODE = ${JSON.stringify(searchMode)}
|
||||
SEARCH_QUERY = ${tempoQuery === null ? "None" : JSON.stringify(tempoQuery)}
|
||||
SEARCH_PATH = ${searchPathLiteral}
|
||||
SEARCH_PROXY_PATH = ${searchProxyPathLiteral}
|
||||
TRACE_PROXY_PREFIX = ${JSON.stringify(proxyPrefix)}
|
||||
TRACE_PATH_TEMPLATE = ${JSON.stringify(observability.probes.traceQueryPathTemplate)}
|
||||
DIAGNOSE_FULL_COMMAND = ${JSON.stringify(diagnoseFullCommand)}
|
||||
SEARCH_COMMAND = ${JSON.stringify(searchCommand)}
|
||||
FULL = ${options.full ? "True" : "False"}
|
||||
RAW = ${options.raw ? "True" : "False"}
|
||||
LIMIT = ${options.limit}
|
||||
@@ -982,6 +1050,28 @@ def classify_terminal_status(status, spans):
|
||||
return "running"
|
||||
return "unknown"
|
||||
|
||||
def preferred_failure_kind(values):
|
||||
kinds = []
|
||||
for value in values:
|
||||
if value in (None, ""):
|
||||
continue
|
||||
text = str(value).strip()
|
||||
if not text:
|
||||
continue
|
||||
if text not in kinds:
|
||||
kinds.append(text)
|
||||
if not kinds:
|
||||
return None
|
||||
for kind in kinds:
|
||||
lowered = kind.lower()
|
||||
if lowered.startswith("provider-") or lowered.startswith("provider_") or "provider-auth" in lowered:
|
||||
return kind
|
||||
for kind in kinds:
|
||||
lowered = kind.lower()
|
||||
if lowered not in ("infra-failed", "infra_failed", "unknown"):
|
||||
return kind
|
||||
return kinds[-1]
|
||||
|
||||
def agentrun_authority_summary(identity):
|
||||
run_id = identity.get("runId") if isinstance(identity, dict) else None
|
||||
command_id = identity.get("commandId") if isinstance(identity, dict) else None
|
||||
@@ -1382,7 +1472,7 @@ def http_status_summary(spans):
|
||||
def agentrun_summary(spans, authority=None):
|
||||
terminal_spans = []
|
||||
latest_seq = None
|
||||
failure_kind = None
|
||||
failure_kinds = []
|
||||
failure_message = None
|
||||
terminal_category = None
|
||||
seq_keys = ("maxSeq", "traceLastSeq", "endSeq", "seq", "eventSeq", "sourceSeq", "sourceLatestSeq", "latestSeq", "lastSeq")
|
||||
@@ -1401,7 +1491,7 @@ def agentrun_summary(spans, authority=None):
|
||||
if not derived and name.startswith("runner_terminal."):
|
||||
derived = name.split(".", 1)[1]
|
||||
if attrs.get("failureKind") not in (None, ""):
|
||||
failure_kind = attrs.get("failureKind")
|
||||
failure_kinds.append(attrs.get("failureKind"))
|
||||
if attrs.get("failureMessage") not in (None, ""):
|
||||
failure_message = attrs.get("failureMessage")
|
||||
if attrs.get("terminalCategory") not in (None, ""):
|
||||
@@ -1423,12 +1513,15 @@ def agentrun_summary(spans, authority=None):
|
||||
if isinstance(authority, dict) and authority.get("terminalStatus") not in (None, ""):
|
||||
terminal_status = authority.get("terminalStatus")
|
||||
terminal_event_type = authority.get("terminalEventType") or terminal_event_type
|
||||
failure_kind = authority.get("failureKind") or failure_kind
|
||||
if authority.get("failureKind") not in (None, ""):
|
||||
failure_kinds.append(authority.get("failureKind"))
|
||||
terminal_source = "agentrun-authority"
|
||||
failure_kind = preferred_failure_kind(failure_kinds)
|
||||
runner_classification = classify_terminal_status(terminal_status, spans)
|
||||
return {
|
||||
"terminalStatus": terminal_status,
|
||||
"failureKind": failure_kind,
|
||||
"observedFailureKinds": failure_kinds,
|
||||
"failureMessage": failure_message,
|
||||
"terminalCategory": terminal_category,
|
||||
"latestSeq": latest_seq,
|
||||
@@ -1562,6 +1655,20 @@ def root_cause_candidates(http_summary, agentrun, read_model, lag_summary, error
|
||||
"summary": "HWLAB projection stale is suspected because AgentRun is terminal but HWLAB read-model evidence is incomplete.",
|
||||
"evidence": lag_summary.get("reasons", []),
|
||||
})
|
||||
failure_kind = str(agentrun.get("failureKind") or "")
|
||||
if failure_kind == "provider-auth-failed":
|
||||
candidates.append({
|
||||
"code": "provider_auth_failed",
|
||||
"label": "provider auth failed",
|
||||
"confidence": 0.96,
|
||||
"summary": "Provider credential refresh/auth failed before the manager reconciler closed the command; fix provider auth before retrying this Code Agent path.",
|
||||
"evidence": {
|
||||
"terminalStatus": agentrun.get("terminalStatus"),
|
||||
"failureKind": agentrun.get("failureKind"),
|
||||
"observedFailureKinds": agentrun.get("observedFailureKinds"),
|
||||
"terminalCategory": agentrun.get("terminalCategory"),
|
||||
},
|
||||
})
|
||||
if agentrun.get("terminalStatus") in ("failed", "error", "timeout", "blocked", "cancelled"):
|
||||
candidates.append({
|
||||
"code": "agentrun_terminal_failed",
|
||||
@@ -1712,7 +1819,11 @@ def resolve_trace():
|
||||
return TRACE_ID, {
|
||||
"mode": "trace-id",
|
||||
"businessTraceId": BUSINESS_TRACE_ID,
|
||||
"runId": RUN_ID,
|
||||
"commandId": COMMAND_ID,
|
||||
"runnerJobId": RUNNER_JOB_ID,
|
||||
"otelTraceId": TRACE_ID,
|
||||
"searchQuery": SEARCH_QUERY,
|
||||
"searchPath": None,
|
||||
"searchOk": None,
|
||||
"searchParseOk": None,
|
||||
@@ -1765,9 +1876,13 @@ def resolve_trace():
|
||||
if selected_low_confidence and not selected_complete:
|
||||
selected_rejected_reason = "best candidate is only a single-span Workbench GET/SSE trace; no high-confidence Code Agent trace was found in the scanned window"
|
||||
mapping = {
|
||||
"mode": "business-trace-id",
|
||||
"mode": SEARCH_MODE,
|
||||
"businessTraceId": BUSINESS_TRACE_ID,
|
||||
"runId": RUN_ID,
|
||||
"commandId": COMMAND_ID,
|
||||
"runnerJobId": RUNNER_JOB_ID,
|
||||
"otelTraceId": selected_trace_id,
|
||||
"searchQuery": SEARCH_QUERY,
|
||||
"searchPath": SEARCH_PATH,
|
||||
"searchProxyPath": SEARCH_PROXY_PATH,
|
||||
"searchOk": search_rc == 0,
|
||||
@@ -1787,7 +1902,7 @@ def resolve_trace():
|
||||
if RAW:
|
||||
mapping["rawSearchBody"] = search_parsed if isinstance(search_parsed, dict) else search_body[-12000:]
|
||||
if selected_trace_id is None:
|
||||
return None, mapping, "no OTel trace found for business trace"
|
||||
return None, mapping, "no OTel trace found for diagnosis query"
|
||||
if selected_rejected_reason is not None:
|
||||
return None, mapping, selected_rejected_reason
|
||||
return selected_trace_id, mapping, None
|
||||
@@ -1803,8 +1918,8 @@ if resolved_trace_id is None:
|
||||
"facts": [],
|
||||
},
|
||||
"next": {
|
||||
"expandWindow": "bun scripts/cli.ts platform-infra observability diagnose-code-agent --target ${target.id} --business-trace-id ${businessTraceIdForNext} --lookback-minutes 10080 --candidate-limit 500 --full",
|
||||
"search": "bun scripts/cli.ts platform-infra observability search --target ${target.id} --query '{ .traceId = \\"${businessTraceIdForNext}\\" }' --lookback-minutes 10080 --candidate-limit 500 --limit 10",
|
||||
"expandWindow": DIAGNOSE_FULL_COMMAND,
|
||||
"search": SEARCH_COMMAND,
|
||||
},
|
||||
}
|
||||
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
||||
@@ -1907,6 +2022,8 @@ payload = {
|
||||
"agentrun": {
|
||||
"terminalStatus": agentrun.get("terminalStatus"),
|
||||
"terminalSource": agentrun.get("terminalSource"),
|
||||
"failureKind": agentrun.get("failureKind"),
|
||||
"observedFailureKinds": agentrun.get("observedFailureKinds"),
|
||||
"latestSeq": agentrun.get("latestSeq"),
|
||||
"terminalEventType": agentrun.get("terminalEventType"),
|
||||
"runnerProviderClassification": agentrun.get("runnerProviderClassification"),
|
||||
@@ -1931,7 +2048,7 @@ payload = {
|
||||
"spanNameCounts": flat["spanNameCounts"][:12],
|
||||
"evidence": evidence,
|
||||
"next": {
|
||||
"diagnoseFull": "bun scripts/cli.ts platform-infra observability diagnose-code-agent --target ${target.id} --business-trace-id ${businessTraceIdForNext} --full",
|
||||
"diagnoseFull": DIAGNOSE_FULL_COMMAND,
|
||||
"traceSummary": "bun scripts/cli.ts platform-infra observability trace --target ${target.id} --trace-id %s --limit 80" % resolved_trace_id,
|
||||
"traceReads": "bun scripts/cli.ts platform-infra observability trace --target ${target.id} --trace-id %s --grep trace_events_read --limit 20 --full" % resolved_trace_id,
|
||||
"turnStatus": "bun scripts/cli.ts platform-infra observability trace --target ${target.id} --trace-id %s --grep turn_status_read --limit 20 --full" % resolved_trace_id,
|
||||
|
||||
@@ -207,6 +207,9 @@ export function buildDiagnoseCommand(target: ObservabilityTarget, options: Diagn
|
||||
const parts = ["bun", "scripts/cli.ts", "platform-infra", "observability", "diagnose-code-agent", "--target", target.id];
|
||||
if (options.businessTraceId !== null) parts.push("--business-trace-id", options.businessTraceId);
|
||||
if (options.traceId !== null) parts.push("--trace-id", options.traceId);
|
||||
if (options.runId !== null) parts.push("--run-id", options.runId);
|
||||
if (options.commandId !== null) parts.push("--command-id", options.commandId);
|
||||
if (options.runnerJobId !== null) parts.push("--runner-job-id", options.runnerJobId);
|
||||
parts.push("--lookback-minutes", String(options.lookbackMinutes), "--candidate-limit", String(options.candidateLimit), "--limit", String(options.limit));
|
||||
if (full) parts.push("--full");
|
||||
return parts.map(cliArg).join(" ");
|
||||
|
||||
@@ -39,6 +39,7 @@ export function observabilityHelp(): Record<string, unknown> {
|
||||
"bun scripts/cli.ts platform-infra observability search --target D601 --grep 'no rollout found' [--lookback-minutes 360] [--candidate-limit 80] [--limit 20] [--full|--raw]",
|
||||
"bun scripts/cli.ts platform-infra observability search --target D601 --path /v1/workbench/sessions --status 502 [--lookback-minutes 120] [--full|--raw]",
|
||||
"bun scripts/cli.ts platform-infra observability diagnose-code-agent --target D601 --business-trace-id <trc_...> [--full|--raw]",
|
||||
"bun scripts/cli.ts platform-infra observability diagnose-code-agent --target D601 --run-id <run_...> [--command-id <cmd_...>] [--runner-job-id <rjob_...>] [--full|--raw]",
|
||||
],
|
||||
boundary: "Prometheus remains the metrics source; this command owns only platform-infra OTel Collector, trace backend readiness, and trace lookup.",
|
||||
};
|
||||
@@ -217,6 +218,9 @@ export function parseDiagnoseCodeAgentOptions(args: string[]): DiagnoseCodeAgent
|
||||
const commonArgs: string[] = [];
|
||||
let businessTraceId: string | null = null;
|
||||
let traceId: string | null = null;
|
||||
let runId: string | null = null;
|
||||
let commandId: string | null = null;
|
||||
let runnerJobId: string | null = null;
|
||||
let limit = 40;
|
||||
let candidateLimit = 300;
|
||||
let lookbackMinutes = 10080;
|
||||
@@ -234,6 +238,24 @@ export function parseDiagnoseCodeAgentOptions(args: string[]): DiagnoseCodeAgent
|
||||
if (!/^[0-9a-fA-F]{32}$/u.test(value)) throw new Error(`${arg} must be a 32-character OpenTelemetry trace id encoded as hex`);
|
||||
traceId = value.toLowerCase();
|
||||
index += 1;
|
||||
} else if (arg === "--run-id" || arg === "--run") {
|
||||
const value = args[index + 1];
|
||||
if (value === undefined || value.startsWith("--")) throw new Error(`${arg} requires a value`);
|
||||
if (!/^run_[A-Za-z0-9_-]+$/u.test(value)) throw new Error(`${arg} must look like run_<id>`);
|
||||
runId = value;
|
||||
index += 1;
|
||||
} else if (arg === "--command-id" || arg === "--command") {
|
||||
const value = args[index + 1];
|
||||
if (value === undefined || value.startsWith("--")) throw new Error(`${arg} requires a value`);
|
||||
if (!/^cmd_[A-Za-z0-9_-]+$/u.test(value)) throw new Error(`${arg} must look like cmd_<id>`);
|
||||
commandId = value;
|
||||
index += 1;
|
||||
} else if (arg === "--runner-job-id" || arg === "--runner-job" || arg === "--runnerjob") {
|
||||
const value = args[index + 1];
|
||||
if (value === undefined || value.startsWith("--")) throw new Error(`${arg} requires a value`);
|
||||
if (!/^rjob_[A-Za-z0-9_-]+$/u.test(value)) throw new Error(`${arg} must look like rjob_<id>`);
|
||||
runnerJobId = value;
|
||||
index += 1;
|
||||
} else if (arg === "--limit") {
|
||||
const value = args[index + 1];
|
||||
if (value === undefined || value.startsWith("--")) throw new Error("--limit requires a value");
|
||||
@@ -263,6 +285,8 @@ export function parseDiagnoseCodeAgentOptions(args: string[]): DiagnoseCodeAgent
|
||||
}
|
||||
}
|
||||
}
|
||||
if (businessTraceId === null && traceId === null) throw new Error("observability diagnose-code-agent requires --business-trace-id <trc_...> or --trace-id <otelTraceId>");
|
||||
return { ...parseCommonOptions(commonArgs), businessTraceId, traceId, limit, candidateLimit, lookbackMinutes };
|
||||
if (businessTraceId === null && traceId === null && runId === null && commandId === null && runnerJobId === null) {
|
||||
throw new Error("observability diagnose-code-agent requires --business-trace-id <trc_...>, --trace-id <otelTraceId>, --run-id <run_...>, --command-id <cmd_...>, or --runner-job-id <rjob_...>");
|
||||
}
|
||||
return { ...parseCommonOptions(commonArgs), businessTraceId, traceId, runId, commandId, runnerJobId, limit, candidateLimit, lookbackMinutes };
|
||||
}
|
||||
|
||||
@@ -141,18 +141,34 @@ export function businessTraceIdFromSearchText(value: string | null): string | nu
|
||||
return match?.[0] ?? null;
|
||||
}
|
||||
|
||||
function diagnoseTraceSearchFilters(options: DiagnoseCodeAgentOptions): string[] {
|
||||
const filters: string[] = [];
|
||||
if (options.businessTraceId !== null) filters.push(`.traceId = ${JSON.stringify(options.businessTraceId)}`);
|
||||
if (options.runId !== null) filters.push(`.runId = ${JSON.stringify(options.runId)}`);
|
||||
if (options.commandId !== null) filters.push(`.commandId = ${JSON.stringify(options.commandId)}`);
|
||||
if (options.runnerJobId !== null) filters.push(`.runnerJobId = ${JSON.stringify(options.runnerJobId)}`);
|
||||
return filters;
|
||||
}
|
||||
|
||||
function diagnoseTraceSearchMode(options: DiagnoseCodeAgentOptions): string {
|
||||
if (options.businessTraceId !== null && options.runId === null && options.commandId === null && options.runnerJobId === null) return "business-trace-id";
|
||||
return "trace-attribute-query";
|
||||
}
|
||||
|
||||
export async function diagnoseCodeAgent(config: UniDeskConfig, options: DiagnoseCodeAgentOptions): Promise<Record<string, unknown> | RenderedCliResult> {
|
||||
const observability = readObservabilityConfig();
|
||||
const target = resolveTarget(observability, options.targetId);
|
||||
const endSeconds = Math.floor(Date.now() / 1000);
|
||||
const startSeconds = endSeconds - (options.lookbackMinutes * 60);
|
||||
let searchPath: string | null = null;
|
||||
if (options.traceId === null && options.businessTraceId !== null) {
|
||||
const searchFilters = diagnoseTraceSearchFilters(options);
|
||||
const tempoQuery = searchFilters.length > 0 ? `{ ${searchFilters.join(" && ")} }` : null;
|
||||
if (options.traceId === null && tempoQuery !== null) {
|
||||
const params = new URLSearchParams({
|
||||
start: String(startSeconds),
|
||||
end: String(endSeconds),
|
||||
limit: String(options.candidateLimit),
|
||||
q: `{ .traceId = "${options.businessTraceId}" }`,
|
||||
q: tempoQuery,
|
||||
});
|
||||
searchPath = `/api/search?${params.toString()}`;
|
||||
}
|
||||
@@ -164,6 +180,11 @@ export async function diagnoseCodeAgent(config: UniDeskConfig, options: Diagnose
|
||||
service: observability.traceBackend.serviceName,
|
||||
businessTraceId: options.businessTraceId,
|
||||
traceId: options.traceId,
|
||||
runId: options.runId,
|
||||
commandId: options.commandId,
|
||||
runnerJobId: options.runnerJobId,
|
||||
mode: diagnoseTraceSearchMode(options),
|
||||
tempoQuery,
|
||||
path: searchPath,
|
||||
lookbackMinutes: options.lookbackMinutes,
|
||||
candidateLimit: options.candidateLimit,
|
||||
@@ -530,6 +551,7 @@ export function renderDiagnoseCodeAgentTable(input: {
|
||||
"",
|
||||
"Identity:",
|
||||
` businessTraceId=${textValue(mapping?.businessTraceId ?? input.query.businessTraceId)} otelTraceId=${traceId}`,
|
||||
` queryMode=${textValue(mapping?.mode ?? input.query.mode)} tempoQuery=${shortenMiddle(textValue(mapping?.searchQuery ?? input.query.tempoQuery), 80)}`,
|
||||
` runId=${textValue(identity?.runId)} commandId=${textValue(identity?.commandId)} runnerJobId=${textValue(identity?.runnerJobId)} runnerId=${textValue(identity?.runnerId)}`,
|
||||
` backendProfile=${textValue(identity?.backendProfile)} sourceCommit=${shortenMiddle(textValue(identity?.sourceCommit), 20)}`,
|
||||
"",
|
||||
@@ -541,7 +563,7 @@ export function renderDiagnoseCodeAgentTable(input: {
|
||||
"",
|
||||
"Summary:",
|
||||
` target=${input.target.id} spanCount=${textValue(input.result.spanCount)} servicePath=${joinValues(input.result.servicePath, 60)}`,
|
||||
` agentrun=${textValue(agentrun?.terminalStatus)} source=${textValue(agentrun?.terminalSource)} authority=${shortenEnd(JSON.stringify((asPlainRecord(agentrun?.authority) ?? {})), 120)}`,
|
||||
` agentrun=${textValue(agentrun?.terminalStatus)} failureKind=${textValue(agentrun?.failureKind)} source=${textValue(agentrun?.terminalSource)} authority=${shortenEnd(JSON.stringify((asPlainRecord(agentrun?.authority) ?? {})), 120)}`,
|
||||
` readModel=${shortenEnd(JSON.stringify(input.result.hwlabReadModel ?? null), 140)}`,
|
||||
];
|
||||
const next = asPlainRecord(input.result.next);
|
||||
|
||||
@@ -157,6 +157,9 @@ export interface SearchOptions extends CommonOptions {
|
||||
export interface DiagnoseCodeAgentOptions extends CommonOptions {
|
||||
businessTraceId: string | null;
|
||||
traceId: string | null;
|
||||
runId: string | null;
|
||||
commandId: string | null;
|
||||
runnerJobId: string | null;
|
||||
limit: number;
|
||||
candidateLimit: number;
|
||||
lookbackMinutes: number;
|
||||
|
||||
@@ -359,6 +359,7 @@ export function platformInfraHelp(): unknown {
|
||||
"bun scripts/cli.ts platform-infra observability trace --target D601 --trace-id <traceId> [--grep text] [--limit 40] [--full|--raw]",
|
||||
"bun scripts/cli.ts platform-infra observability search --target D601 --grep 'no rollout found' [--lookback-minutes 360] [--candidate-limit 80] [--limit 20]",
|
||||
"bun scripts/cli.ts platform-infra observability diagnose-code-agent --target D601 --business-trace-id <trc_...> [--full|--raw]",
|
||||
"bun scripts/cli.ts platform-infra observability diagnose-code-agent --target D601 --run-id <run_...> [--command-id <cmd_...>] [--runner-job-id <rjob_...>]",
|
||||
],
|
||||
description: "Operate YAML-controlled platform-infra services such as Sub2API, LangBot, n8n, WeChat archive workflows and OpenTelemetry tracing. Public services use PK01 Caddy+FRP rather than Kubernetes Ingress, NodePort, or LoadBalancer.",
|
||||
target,
|
||||
|
||||
Reference in New Issue
Block a user