Merge pull request #609 from pikasTech/fix/observability-compact-default-20260621

fix: 压缩 observability 默认输出
This commit is contained in:
Lyon
2026-06-21 23:29:19 +08:00
committed by GitHub
+211 -2
View File
@@ -675,6 +675,11 @@ async function search(config: UniDeskConfig, options: SearchOptions): Promise<Re
const searchPath = `/api/search?${params.toString()}`;
const result = await capture(config, target.route, ["sh"], searchScript(observability, target, searchPath, options));
const parsed = parseJsonOutput(result.stdout);
const exposedResult = parsed === null
? compactCapture(result, { full: true })
: options.full || options.raw
? redactSensitiveUnknown(parsed)
: redactSensitiveUnknown(compactSearchResult(parsed));
return {
ok: result.exitCode === 0 && parsed?.ok === true,
action: "platform-infra-observability-search",
@@ -693,7 +698,7 @@ async function search(config: UniDeskConfig, options: SearchOptions): Promise<Re
candidateLimit: options.candidateLimit,
limit: options.limit,
},
result: redactSensitiveUnknown(parsed) ?? compactCapture(result, { full: true }),
result: exposedResult,
};
}
@@ -720,6 +725,11 @@ async function diagnoseCodeAgent(config: UniDeskConfig, options: DiagnoseCodeAge
}
const result = await capture(config, target.route, ["sh"], diagnoseCodeAgentScript(observability, target, searchPath, options));
const parsed = parseJsonOutput(result.stdout);
const exposedResult = parsed === null
? compactCapture(result, { full: true })
: options.full || options.raw
? redactSensitiveUnknown(parsed)
: redactSensitiveUnknown(compactDiagnoseCodeAgentResult(parsed));
return {
ok: result.exitCode === 0 && parsed?.ok === true,
action: "platform-infra-observability-diagnose-code-agent",
@@ -735,10 +745,209 @@ async function diagnoseCodeAgent(config: UniDeskConfig, options: DiagnoseCodeAge
candidateLimit: options.candidateLimit,
limit: options.limit,
},
result: redactSensitiveUnknown(parsed) ?? compactCapture(result, { full: true }),
result: exposedResult,
};
}
function compactSearchResult(value: unknown): Record<string, unknown> {
const source = asPlainRecord(value) ?? {};
const traces = asArray(source.traces).map(compactSearchTrace);
return {
ok: source.ok === true,
searchPath: source.searchPath ?? null,
grep: source.grep ?? null,
tempoQuery: source.tempoQuery ?? null,
pathFilter: source.pathFilter ?? null,
statusFilter: source.statusFilter ?? null,
limit: source.limit ?? null,
candidateLimit: source.candidateLimit ?? null,
searchParseOk: source.searchParseOk ?? null,
candidateTraceCount: source.candidateTraceCount ?? null,
scannedTraceCount: source.scannedTraceCount ?? null,
matchedTraceCount: source.matchedTraceCount ?? null,
scanStopped: source.scanStopped ?? null,
matchingActive: source.matchingActive ?? null,
traces,
truncated: source.truncated ?? null,
next: source.next ?? null,
searchStderrTail: source.searchStderrTail ?? null,
disclosure: {
defaultView: "compact trace rows only; span arrays are omitted to keep stdout below config/unidesk-cli.yaml output.maxStdoutBytes",
expand: "rerun with --full or query a specific trace id with platform-infra observability trace",
},
};
}
function compactSearchTrace(value: unknown): Record<string, unknown> {
const trace = asPlainRecord(value) ?? {};
return {
traceId: trace.traceId ?? null,
traceCommand: trace.traceCommand ?? null,
grepCommand: trace.grepCommand ?? null,
meta: compactMetaRecord(trace.meta),
queryOk: trace.queryOk ?? null,
parseOk: trace.parseOk ?? null,
rawMatched: trace.rawMatched ?? null,
matchingActive: trace.matchingActive ?? null,
bodyBytes: trace.bodyBytes ?? null,
spanCount: trace.spanCount ?? null,
serviceCount: trace.serviceCount ?? null,
services: trace.services ?? null,
businessTraceIds: trace.businessTraceIds ?? null,
errorSpanCount: trace.errorSpanCount ?? null,
matchedSpanCount: trace.matchedSpanCount ?? null,
spanNameCounts: compactNameCounts(trace.spanNameCounts, 6),
errorSpanNames: compactSpanNames(trace.errorSpans, 5),
matchedSpanNames: compactSpanNames(trace.matchedSpans, 8),
stderrTail: trace.stderrTail ?? null,
};
}
function compactDiagnoseCodeAgentResult(value: unknown): Record<string, unknown> {
const source = asPlainRecord(value) ?? {};
const mapping = asPlainRecord(source.mapping);
const evidence = asPlainRecord(source.evidence);
return {
ok: source.ok === true,
mapping: mapping === null ? null : {
mode: mapping.mode ?? null,
businessTraceId: mapping.businessTraceId ?? null,
otelTraceId: mapping.otelTraceId ?? null,
searchOk: mapping.searchOk ?? null,
searchParseOk: mapping.searchParseOk ?? null,
candidateTraceCount: mapping.candidateTraceCount ?? null,
scannedCandidateCount: mapping.scannedCandidateCount ?? null,
candidateSelectionMode: mapping.candidateSelectionMode ?? null,
selectedScore: mapping.selectedScore ?? null,
selectedQuality: mapping.selectedQuality ?? null,
selectedLowConfidence: mapping.selectedLowConfidence ?? null,
selectedRejectedReason: mapping.selectedRejectedReason ?? null,
selectedReasons: limitArray(mapping.selectedReasons, 8),
selectedMeta: compactMetaRecord(mapping.selectedMeta),
candidatePreview: asArray(mapping.candidatePreview).slice(0, 3).map(compactDiagnoseCandidate),
searchStderrTail: mapping.searchStderrTail ?? null,
},
tracePath: source.tracePath ?? null,
bodyBytes: source.bodyBytes ?? null,
traceParseOk: source.traceParseOk ?? null,
spanCount: source.spanCount ?? null,
services: source.services ?? null,
servicePath: source.servicePath ?? null,
businessTraceIds: source.businessTraceIds ?? null,
identity: source.identity ?? null,
agentrun: compactRecord(source.agentrun, ["terminalStatus", "latestSeq", "terminalEventType", "runnerProviderClassification"]),
hwlabReadModel: source.hwlabReadModel ?? null,
http: source.http ?? null,
projectionLag: source.projectionLag ?? null,
summary: source.summary ?? null,
rootCauseCandidates: asArray(source.rootCauseCandidates).slice(0, 5).map(compactRootCauseCandidate),
spanNameCounts: compactNameCounts(source.spanNameCounts, 10),
evidence: evidence === null ? null : {
httpProblemSpanCount: evidence.httpProblemSpanCount ?? null,
terminalSpanCount: evidence.terminalSpanCount ?? null,
turnStatusReadSpanCount: evidence.turnStatusReadSpanCount ?? null,
projectionSpanCount: evidence.projectionSpanCount ?? null,
errorSpanCount: evidence.errorSpanCount ?? null,
errorSpanSampleNames: evidence.errorSpanSampleNames ?? null,
idleWarningSpanCount: evidence.idleWarningSpanCount ?? null,
idleWarningSpanTail: compactSpanList(evidence.idleWarningSpanTail, 3),
},
next: source.next ?? null,
stderrTail: source.stderrTail ?? null,
disclosure: {
defaultView: "compact diagnosis only; detailed span evidence is omitted to keep stdout below config/unidesk-cli.yaml output.maxStdoutBytes",
expand: "rerun diagnose-code-agent with --full, or query a specific trace id with platform-infra observability trace --grep <span>",
},
};
}
function compactDiagnoseCandidate(value: unknown): Record<string, unknown> {
const candidate = asPlainRecord(value) ?? {};
return {
traceId: candidate.traceId ?? null,
score: candidate.score ?? null,
reasons: limitArray(candidate.reasons, 6),
parseOk: candidate.parseOk ?? null,
queryOk: candidate.queryOk ?? null,
spanCount: candidate.spanCount ?? null,
services: candidate.services ?? null,
servicePath: candidate.servicePath ?? null,
identity: candidate.identity ?? null,
terminalStatus: candidate.terminalStatus ?? null,
errorSpanCount: candidate.errorSpanCount ?? null,
candidateQuality: candidate.candidateQuality ?? null,
lowConfidence: candidate.lowConfidence ?? null,
rootTraceName: candidate.rootTraceName ?? null,
rootServiceName: candidate.rootServiceName ?? null,
spanNamePreview: limitArray(candidate.spanNamePreview, 8),
traceCommand: candidate.traceCommand ?? null,
};
}
function compactRootCauseCandidate(value: unknown): Record<string, unknown> {
const candidate = asPlainRecord(value) ?? {};
return {
code: candidate.code ?? null,
label: candidate.label ?? null,
confidence: candidate.confidence ?? null,
summary: candidate.summary ?? null,
evidenceCount: Array.isArray(candidate.evidence) ? candidate.evidence.length : candidate.evidence === undefined || candidate.evidence === null ? 0 : 1,
};
}
function compactSpanList(value: unknown, limit: number): unknown[] {
return asArray(value).slice(0, limit).map((item) => {
const span = asPlainRecord(item) ?? {};
const attrs = asPlainRecord(span.attributes) ?? {};
return {
name: span.name ?? null,
service: span.service ?? null,
attributes: compactRecord(attrs, ["failureKind", "terminalStatus", "status", "eventType", "idleMs", "waitingFor", "lastEventLabel", "http.route", "http.status_code", "http.response.status_code"]),
};
});
}
function compactSpanNames(value: unknown, limit: number): string[] {
return asArray(value).slice(0, limit).map((item) => {
const span = asPlainRecord(item);
return String(span?.name ?? "<unknown>");
});
}
function compactNameCounts(value: unknown, limit: number): unknown[] {
return asArray(value).slice(0, limit).map((item) => {
const record = asPlainRecord(item) ?? {};
return { name: record.name ?? null, count: record.count ?? null };
});
}
function compactMetaRecord(value: unknown): Record<string, unknown> | null {
return compactRecord(value, ["traceID", "traceId", "rootServiceName", "rootTraceName", "startTimeUnixNano", "durationMs"]);
}
function compactRecord(value: unknown, keys: string[]): Record<string, unknown> | null {
const source = asPlainRecord(value);
if (source === null) return null;
const result: Record<string, unknown> = {};
for (const key of keys) {
if (Object.prototype.hasOwnProperty.call(source, key)) result[key] = source[key];
}
return result;
}
function asPlainRecord(value: unknown): Record<string, unknown> | null {
if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
return value as Record<string, unknown>;
}
function asArray(value: unknown): unknown[] {
return Array.isArray(value) ? value : [];
}
function limitArray(value: unknown, limit: number): unknown[] {
return asArray(value).slice(0, limit);
}
function renderManifest(observability: ObservabilityConfig, target: ObservabilityTarget): string {
const collectorImage = imageReference(observability.images.collector);
const tempoImage = imageReference(observability.images.tempo);