feat: 聚合可观测性收口检查
This commit is contained in:
@@ -11,12 +11,15 @@ Skill(cli-spec)。用于 UniDesk OpenTelemetry/Tempo 链路追踪运维、按 tr
|
||||
|
||||
```bash
|
||||
bun scripts/cli.ts platform-infra observability status
|
||||
bun scripts/cli.ts platform-infra observability closeout --target <NODE> [--query <PromQL>]... [--trace-id <traceId>] [--service <service>]
|
||||
bun scripts/cli.ts platform-infra observability trace <traceId>
|
||||
bun scripts/cli.ts platform-infra observability search --grep <service> --limit 20
|
||||
```
|
||||
|
||||
基本状态、trace 查询、噪声压制、读取窗口与乱序调查见 [references/traces.md](references/traces.md);业务 trace 映射、Code Agent/AgentRun 排障、codex-stdio 追穿和何时先改进 OTel 见 [references/code-agent.md](references/code-agent.md)。
|
||||
|
||||
同类运行面复核优先用 `closeout` 一次汇总 status、validate 及显式选择的 PromQL/trace;子检查失败固定为 non-blocking warning,单项细节再走原命令下钻。
|
||||
|
||||
## P0 边界
|
||||
|
||||
- 微服务契约版本、源码/镜像版本和 `commitId` 漂移只能记录为非阻塞 warning;不得建议或实现线上 admission、dispatch、readiness 或用户业务门禁。业务已成功时,漂移告警不能改写成功结论。
|
||||
|
||||
@@ -105,6 +105,7 @@ metricsBackend:
|
||||
timeoutSeconds: 15
|
||||
maxSeries: 200
|
||||
maxResponseBytes: 262144
|
||||
maxCloseoutQueries: 8
|
||||
|
||||
sampling:
|
||||
mode: parentbased_traceidratio
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# R5 任务报告
|
||||
|
||||
## 目标
|
||||
|
||||
完成 [UniDesk #2322](https://github.com/pikasTech/unidesk/issues/2322),提供 YAML/参数驱动的 `platform-infra observability closeout` 只读聚合入口,减少同类运行面复核的重复 CLI 调用。
|
||||
|
||||
## 实现
|
||||
|
||||
- 固定聚合现有 `status` 与 `validate`,不复制 Kubernetes、Tempo 或 Prometheus 访问实现。
|
||||
- 支持可重复 `--query <PromQL>`、可选 `--trace-id <id>` 与 `--service <text>`。
|
||||
- 所有子操作并发执行;聚合结果固定 `mutation=false`、`blocking=false`,可选证据失败只输出 non-blocking warning。
|
||||
- 默认输出有界表格,`--full`/`--raw` 返回脱敏结构;命令与参数未写死产品、namespace 或 instance。
|
||||
- query fan-out 上限由 `config/platform-infra/observability.yaml#metricsBackend.query.maxCloseoutQueries` 控制,并在远端访问前校验。
|
||||
- 同步更新 `unidesk-otel` skill 与 observability 长期参考。
|
||||
|
||||
## 验证
|
||||
|
||||
- `bun test scripts/src/platform-infra-observability.test.ts`:10 pass,0 fail。
|
||||
- `bun scripts/cli.ts platform-infra observability closeout --help`:scoped help 正常,无 PikaOA 产品硬编码。
|
||||
- NC01 真实只读 smoke 以一次 CLI 调用汇总 status、validate、两项 readiness PromQL 与已有 trace,5 项检查全部 `ok=true`,输出 `mutation=false blocking=false`。
|
||||
- `git diff --check` 通过。
|
||||
|
||||
## 边界
|
||||
|
||||
未修改公共运行面、Prometheus/Tempo/Collector、scrape/relabel、CI/CD 或业务 readiness 门禁;PR 仅创建,不合并。
|
||||
@@ -110,3 +110,7 @@
|
||||
##### R4.4.2.10 [in_progress]
|
||||
|
||||
执行 [HWLAB #2538](https://github.com/pikasTech/HWLAB/issues/2538) P0 架构纠偏:确认 PR #2540 把已工作的 agentrun.event.v1→hwlab.event.v1→实时 SSE/Kafka retention 回放错误替换为强制 PostgreSQL transactional projector,构成重大架构偏移;从最新 v0.3 分析偏移提交并创建新的精确纠偏提交,恢复 direct publish、live Kafka SSE、Kafka refresh replay 及其单一 Kafka authority,删除强制 v8 schema 启动门禁和数据库迁移依赖,保留 canonical duration 修复、feature-config schema、HTTP fallback 禁令及其他无关改动;通过新 PR 和自动 PaC/GitOps/Argo 上线后校对实时、回放、terminal/final 与 canonical duration,完成任务后将详细报告写入[任务报告](./details/observability-trace-reliability/R4.4.2.10_Task_Report.md)。
|
||||
|
||||
## R5 [completed]
|
||||
|
||||
实现 [UniDesk #2322](https://github.com/pikasTech/unidesk/issues/2322):新增 YAML/参数驱动的 `platform-infra observability closeout` 只读聚合入口,在一次 CLI 调用中有界汇总 status、validate 及可选 PromQL/OTel trace 证据;保持 `mutation=false`、non-blocking,不修改公共运行面,完成任务后将详细报告写入任务报告,完成任务后将详细报告写入[任务报告](./details/observability-trace-reliability/R5_Task_Report.md)。
|
||||
|
||||
@@ -4,6 +4,11 @@ UniDesk 的可观测性优先级高于静默成功。CLI、服务日志、Docker
|
||||
|
||||
## 共享 Prometheus 指标面
|
||||
|
||||
- 同类运行面收口优先使用单次只读聚合入口:
|
||||
- `bun scripts/cli.ts platform-infra observability closeout --target <NODE>` 固定汇总 status 与 validate;
|
||||
- 可重复 `--query <PromQL>` 增加指标证据,可选 `--trace-id <id>` 与 `--service <text>` 增加 trace 证据;
|
||||
- 子检查失败只产生 `blocking=false` warning,不修改运行面,也不改变业务成功终态;
|
||||
- 需要单项完整证据时再使用对应 status、validate、metrics-query 或 trace 下钻。
|
||||
- `config/platform-infra/observability.yaml` 同时拥有 Collector、Tempo 和 Prometheus 的 image、retention、storage、port、目标 `targetIds`、服务发现与查询预算;TypeScript 只校验和渲染。
|
||||
- Prometheus 仅作用于 `metricsBackend.targetIds` 选中的 observability target;其他 target 的 plan 显示 `disabled-for-target`,manifest、status probe/capture 和 `metrics-query` 均不访问 Prometheus。
|
||||
- Prometheus 使用 Kubernetes 原生 pod 服务发现。YAML 通过结构化 `labelSelector.key/value` 声明稳定 label,并用 `prometheus.io/scrape=true`、`prometheus.io/path`、`prometheus.io/port` annotation 声明抓取;显式 path 优先,仅在 annotation 缺失时使用 `defaultPath`,不允许业务专属分支。
|
||||
|
||||
@@ -7,6 +7,7 @@ import { resolveTarget } from "./platform-infra-observability/actions";
|
||||
import { isKubernetesLabelValue, isKubernetesQualifiedName, readObservabilityConfig } from "./platform-infra-observability/config";
|
||||
import { renderObservabilityPlanFailure } from "./platform-infra-observability/plan-render";
|
||||
import { prometheusMetaLabel, re2Literal } from "./platform-infra-observability/prometheus";
|
||||
import { parseCloseoutOptions } from "./platform-infra-observability/options";
|
||||
import { statusScript } from "./platform-infra-observability/search-script";
|
||||
import { renderManifest } from "./platform-infra-observability/trace-script";
|
||||
|
||||
@@ -123,13 +124,46 @@ describe("platform-infra observability progressive disclosure", () => {
|
||||
expect(result.status).toBe(0);
|
||||
const payload = JSON.parse(result.stdout) as Record<string, any>;
|
||||
expect(payload.data.operations.map((item: Record<string, unknown>) => item.name)).toEqual([
|
||||
"plan", "apply", "status", "validate", "trace", "search", "diagnose-code-agent", "metrics-query",
|
||||
"plan", "apply", "status", "validate", "trace", "search", "diagnose-code-agent", "metrics-query", "closeout",
|
||||
]);
|
||||
expect(payload.data.scopedHelp).toContain("<operation> --help");
|
||||
expect(payload.data.usage).toBeUndefined();
|
||||
expect(result.stdout).not.toContain("platform-infra sub2api");
|
||||
});
|
||||
|
||||
test("closeout accepts repeatable parameter-driven evidence without a product-specific default", () => {
|
||||
expect(parseCloseoutOptions([
|
||||
"--target", "NC01",
|
||||
"--query", "database_ready",
|
||||
"--query", "migration_ready",
|
||||
"--trace-id", "a7a8f10dc985505c74fad89eeb1ba39f",
|
||||
"--service", "example-api",
|
||||
"--full",
|
||||
])).toEqual({
|
||||
targetId: "NC01",
|
||||
queries: ["database_ready", "migration_ready"],
|
||||
traceId: "a7a8f10dc985505c74fad89eeb1ba39f",
|
||||
service: "example-api",
|
||||
full: true,
|
||||
raw: false,
|
||||
});
|
||||
|
||||
const help = cli(["platform-infra", "observability", "closeout", "--help"]);
|
||||
expect(help.status).toBe(0);
|
||||
const payload = JSON.parse(help.stdout) as Record<string, any>;
|
||||
expect(payload.data.command).toBe("platform-infra observability closeout");
|
||||
expect(payload.data.boundary).toContain("non-blocking warning");
|
||||
expect(help.stdout).not.toContain("pikaoa");
|
||||
expect(() => parseCloseoutOptions(["--target", "NC01", "--service", "example-api"])).toThrow("--service requires --trace-id");
|
||||
expect(readObservabilityConfig().metricsBackend.query.maxCloseoutQueries).toBe(8);
|
||||
});
|
||||
|
||||
test("closeout rejects query fan-out above the YAML budget before remote access", async () => {
|
||||
const args = ["closeout", "--target", "NC01"];
|
||||
for (let index = 0; index < 9; index += 1) args.push("--query", `metric_${index}`);
|
||||
await expect(runPlatformObservabilityCommand({} as never, args)).rejects.toThrow("at most 8 --query values");
|
||||
});
|
||||
|
||||
test("configRef failures name the source and a bounded next command", () => {
|
||||
const rendered = renderObservabilityPlanFailure(
|
||||
new Error("config/hwlab-node-lanes.yaml#lanes.v03.targets.NC01.runtime.namespace is missing segment namespace"),
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
// 只读聚合 status、validate 以及调用者显式选择的 metrics/trace 证据。
|
||||
import type { UniDeskConfig } from "../config";
|
||||
import type { RenderedCliResult } from "../output";
|
||||
import { redactSensitiveUnknown } from "../platform-infra-ops-library";
|
||||
import { metricsQuery } from "./prometheus";
|
||||
import { status, validate } from "./actions";
|
||||
import { trace } from "./render";
|
||||
import { formatTable, shortenEnd, textValue } from "./manifest";
|
||||
import { resolveTarget } from "./actions";
|
||||
import { readObservabilityConfig } from "./config";
|
||||
import { targetSummary } from "./summary";
|
||||
import type { CloseoutOptions } from "./types";
|
||||
|
||||
type Result = Record<string, unknown>;
|
||||
|
||||
export async function closeout(config: UniDeskConfig, options: CloseoutOptions): Promise<Result | RenderedCliResult> {
|
||||
const observability = readObservabilityConfig();
|
||||
const target = resolveTarget(observability, options.targetId);
|
||||
if (options.queries.length > observability.metricsBackend.query.maxCloseoutQueries) {
|
||||
throw new Error(`observability closeout accepts at most ${observability.metricsBackend.query.maxCloseoutQueries} --query values from config/platform-infra/observability.yaml`);
|
||||
}
|
||||
const operations: Array<Promise<Result>> = [
|
||||
settled("status", () => status(config, { targetId: target.id, full: true, raw: false })),
|
||||
settled("validate", () => validate(config, { targetId: target.id, full: true, raw: false })),
|
||||
];
|
||||
for (const query of options.queries) {
|
||||
operations.push(settled(`metrics:${query}`, () => metricsQuery(config, { targetId: target.id, query, full: true, raw: false })));
|
||||
}
|
||||
if (options.traceId !== null) {
|
||||
operations.push(settled("trace", () => trace(config, {
|
||||
targetId: target.id,
|
||||
traceId: options.traceId,
|
||||
grep: options.service,
|
||||
limit: 40,
|
||||
full: true,
|
||||
raw: true,
|
||||
})));
|
||||
}
|
||||
const settledResults = await Promise.all(operations);
|
||||
const statusResult = settledResults[0];
|
||||
const validateResult = settledResults[1];
|
||||
const statusOk = statusResult.ok === true;
|
||||
const validateOk = validateResult.ok === true;
|
||||
const warnings = settledResults
|
||||
.filter((item) => item.ok !== true)
|
||||
.map((item) => ({ code: "observability-closeout-child-failed", operation: item.operation, blocking: false, detail: item.error ?? "child operation returned not-ok" }));
|
||||
const result: Result = {
|
||||
ok: statusOk && validateOk,
|
||||
action: "platform-infra-observability-closeout",
|
||||
mutation: false,
|
||||
blocking: false,
|
||||
target: targetSummary(target),
|
||||
requested: { queries: options.queries, traceId: options.traceId, service: options.service },
|
||||
status: redactSensitiveUnknown(statusResult),
|
||||
validate: redactSensitiveUnknown(validateResult),
|
||||
optional: settledResults.slice(2).map((item) => redactSensitiveUnknown(item)),
|
||||
warnings,
|
||||
};
|
||||
if (options.full || options.raw) return result;
|
||||
return renderCloseout(result, target.id, target.namespace);
|
||||
}
|
||||
|
||||
async function settled(operation: string, run: () => Promise<unknown>): Promise<Result> {
|
||||
try {
|
||||
const value = await run();
|
||||
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
||||
return { operation, ...(value as Result) };
|
||||
}
|
||||
return { operation, ok: false, error: "child operation returned an unsupported payload" };
|
||||
} catch (error) {
|
||||
return { operation, ok: false, error: error instanceof Error ? error.message : String(error) };
|
||||
}
|
||||
}
|
||||
|
||||
function renderCloseout(result: Result, targetId: string, namespace: string): RenderedCliResult {
|
||||
const statusResult = asRecord(result.status);
|
||||
const validateResult = asRecord(result.validate);
|
||||
const optional = Array.isArray(result.optional) ? result.optional.filter(asRecord) : [];
|
||||
const rows = [
|
||||
["status", textValue(statusResult?.ok)],
|
||||
["validate", textValue(validateResult?.ok)],
|
||||
...optional.map((item) => [textValue(item.operation), textValue(item.ok)]),
|
||||
];
|
||||
const warnings = Array.isArray(result.warnings) ? result.warnings.filter(asRecord) : [];
|
||||
const lines = [
|
||||
`platform-infra observability closeout (${result.ok === true ? "ok" : "not-ok"})`,
|
||||
"",
|
||||
`target=${targetId} namespace=${namespace} ready=${result.ok === true} mutation=false blocking=false`,
|
||||
"",
|
||||
"Checks:",
|
||||
formatTable(["OPERATION", "OK"], rows.length > 0 ? rows : [["-", "-"]]),
|
||||
];
|
||||
if (warnings.length > 0) {
|
||||
lines.push("", "Warnings:", formatTable(["OPERATION", "BLOCKING", "DETAIL"], warnings.map((item) => [shortenEnd(textValue(item.operation), 28), textValue(item.blocking), shortenEnd(textValue(item.detail), 100)])));
|
||||
}
|
||||
lines.push("", "Disclosure:", " status/validate are always collected; metrics and trace are opt-in via --query/--trace-id.", " Optional failures remain non-blocking warnings; use --full for structured child results.");
|
||||
return { ok: result.ok === true, command: "platform-infra observability closeout", contentType: "text/plain", renderedText: lines.join("\n") };
|
||||
}
|
||||
|
||||
function asRecord(value: unknown): Result | null {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value) ? value as Result : null;
|
||||
}
|
||||
@@ -124,6 +124,7 @@ export function readObservabilityConfig(): ObservabilityConfig {
|
||||
timeoutSeconds: integerField(metricsQuery, "timeoutSeconds", "metricsBackend.query"),
|
||||
maxSeries: integerField(metricsQuery, "maxSeries", "metricsBackend.query"),
|
||||
maxResponseBytes: integerField(metricsQuery, "maxResponseBytes", "metricsBackend.query"),
|
||||
maxCloseoutQueries: integerField(metricsQuery, "maxCloseoutQueries", "metricsBackend.query"),
|
||||
},
|
||||
},
|
||||
sampling: {
|
||||
@@ -152,7 +153,7 @@ export function readObservabilityConfig(): ObservabilityConfig {
|
||||
if (!isKubernetesQualifiedName(config.metricsBackend.discovery.labelSelector.key)) throw new Error(`${configLabel}.metricsBackend.discovery.labelSelector.key must be a Kubernetes qualified name`);
|
||||
if (!isKubernetesLabelValue(config.metricsBackend.discovery.labelSelector.value)) throw new Error(`${configLabel}.metricsBackend.discovery.labelSelector.value must be a Kubernetes label value`);
|
||||
if (config.collector.replicas < 0 || config.traceBackend.replicas < 0 || config.metricsBackend.replicas < 0) throw new Error(`${configLabel} replicas must be >= 0`);
|
||||
if (config.metricsBackend.query.timeoutSeconds < 1 || config.metricsBackend.query.maxSeries < 1 || config.metricsBackend.query.maxResponseBytes < 1024) throw new Error(`${configLabel}.metricsBackend.query budgets must be positive and maxResponseBytes must be >= 1024`);
|
||||
if (config.metricsBackend.query.timeoutSeconds < 1 || config.metricsBackend.query.maxSeries < 1 || config.metricsBackend.query.maxResponseBytes < 1024 || config.metricsBackend.query.maxCloseoutQueries < 1) throw new Error(`${configLabel}.metricsBackend.query budgets must be positive and maxResponseBytes must be >= 1024`);
|
||||
if (config.sampling.ratio < 0 || config.sampling.ratio > 1) throw new Error(`${configLabel}.sampling.ratio must be between 0 and 1`);
|
||||
if (!config.probes.traceQueryPathTemplate.includes("{{traceId}}")) throw new Error(`${configLabel}.probes.traceQueryPathTemplate must include {{traceId}}`);
|
||||
return config;
|
||||
|
||||
@@ -9,5 +9,6 @@ export * from "./apply-status-scripts";
|
||||
export * from "./trace-script";
|
||||
export * from "./search-script";
|
||||
export * from "./diagnose-code-agent-script";
|
||||
export * from "./closeout";
|
||||
export * from "./summary";
|
||||
export * from "./plan-render";
|
||||
|
||||
@@ -19,13 +19,14 @@ import {
|
||||
capture,
|
||||
} from "../platform-infra-ops-library";
|
||||
|
||||
import type { ApplyOptions, CommonOptions, DiagnoseCodeAgentOptions, MetricsQueryOptions, SearchOptions, TraceOptions } from "./types";
|
||||
import type { ApplyOptions, CloseoutOptions, CommonOptions, DiagnoseCodeAgentOptions, MetricsQueryOptions, SearchOptions, TraceOptions } from "./types";
|
||||
import { apply, plan, status, validate } from "./actions";
|
||||
import { diagnoseCodeAgent, search, trace } from "./render";
|
||||
import { renderObservabilityPlan, renderObservabilityPlanFailure } from "./plan-render";
|
||||
import { metricsQuery } from "./prometheus";
|
||||
import { closeout } from "./closeout";
|
||||
|
||||
const observabilityOperations = ["plan", "apply", "status", "validate", "trace", "search", "diagnose-code-agent", "metrics-query"] as const;
|
||||
const observabilityOperations = ["plan", "apply", "status", "validate", "trace", "search", "diagnose-code-agent", "metrics-query", "closeout"] as const;
|
||||
|
||||
export function observabilityHelp(scope: string | null = null): Record<string, unknown> {
|
||||
const scoped = scope === null ? null : observabilityOperationHelp(scope);
|
||||
@@ -64,6 +65,7 @@ export async function runPlatformObservabilityCommand(config: UniDeskConfig, arg
|
||||
if (action === "search") return await search(config, parseSearchOptions(args.slice(1)));
|
||||
if (action === "diagnose-code-agent") return await diagnoseCodeAgent(config, parseDiagnoseCodeAgentOptions(args.slice(1)));
|
||||
if (action === "metrics-query") return await metricsQuery(config, parseMetricsQueryOptions(args.slice(1)));
|
||||
if (action === "closeout") return await closeout(config, parseCloseoutOptions(args.slice(1)));
|
||||
return { ok: false, error: "unsupported-platform-infra-observability-command", args, help: observabilityHelp() };
|
||||
}
|
||||
|
||||
@@ -113,6 +115,13 @@ function observabilityOperationHelp(scope: string): Record<string, unknown> | nu
|
||||
usage: ["bun scripts/cli.ts platform-infra observability metrics-query --target <NODE> --query <promql> [--full|--raw]"],
|
||||
options: ["--target <NODE>", "--query <promql>", "--full", "--raw"],
|
||||
};
|
||||
if (scope === "closeout") return {
|
||||
...common,
|
||||
command: "platform-infra observability closeout",
|
||||
usage: ["bun scripts/cli.ts platform-infra observability closeout --target <NODE> [--query <promql>]... [--trace-id <OTel trace id>] [--service <service text>] [--full|--raw]"],
|
||||
options: ["--target <NODE>", "--query <promql> (repeatable)", "--trace-id <32-hex>", "--service <service text>", "--full", "--raw"],
|
||||
boundary: "只读聚合 status/validate 及显式 metrics/trace;所有可观测性缺口均为 non-blocking warning。",
|
||||
};
|
||||
if (scope === "search") return {
|
||||
...common,
|
||||
command: "platform-infra observability search",
|
||||
@@ -155,6 +164,36 @@ export function parseMetricsQueryOptions(args: string[]): MetricsQueryOptions {
|
||||
return { ...parseCommonOptions(commonArgs), query };
|
||||
}
|
||||
|
||||
export function parseCloseoutOptions(args: string[]): CloseoutOptions {
|
||||
const commonArgs: string[] = [];
|
||||
const queries: string[] = [];
|
||||
let traceId: string | null = null;
|
||||
let service: string | null = null;
|
||||
for (let index = 0; index < args.length; index += 1) {
|
||||
const arg = args[index];
|
||||
const value = args[index + 1];
|
||||
if (arg === "--query") {
|
||||
if (value === undefined || value.startsWith("--")) throw new Error("--query requires a value");
|
||||
queries.push(value);
|
||||
index += 1;
|
||||
} else if (arg === "--trace-id" || arg === "--service") {
|
||||
if (value === undefined || value.startsWith("--")) throw new Error(`${arg} requires a value`);
|
||||
if (arg === "--trace-id") traceId = value;
|
||||
else service = value;
|
||||
index += 1;
|
||||
} else {
|
||||
commonArgs.push(arg);
|
||||
if (arg === "--target") {
|
||||
commonArgs.push(value ?? "");
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (traceId !== null && !/^[0-9a-fA-F]{32}$/u.test(traceId)) throw new Error("trace id must be a 32-character OpenTelemetry trace id encoded as hex");
|
||||
if (service !== null && traceId === null) throw new Error("--service requires --trace-id");
|
||||
return { ...parseCommonOptions(commonArgs), queries, traceId, service };
|
||||
}
|
||||
|
||||
export function parseCommonOptions(args: string[]): CommonOptions {
|
||||
let targetId: string | null = null;
|
||||
let full = false;
|
||||
|
||||
@@ -111,7 +111,7 @@ export interface PrometheusConfig {
|
||||
scrapeInterval: string;
|
||||
scrapeTimeout: string;
|
||||
};
|
||||
query: { path: string; timeoutSeconds: number; maxSeries: number; maxResponseBytes: number };
|
||||
query: { path: string; timeoutSeconds: number; maxSeries: number; maxResponseBytes: number; maxCloseoutQueries: number };
|
||||
}
|
||||
|
||||
export interface ImageSpec {
|
||||
@@ -196,3 +196,9 @@ export interface DiagnoseCodeAgentOptions extends CommonOptions {
|
||||
export interface MetricsQueryOptions extends CommonOptions {
|
||||
query: string | null;
|
||||
}
|
||||
|
||||
export interface CloseoutOptions extends CommonOptions {
|
||||
queries: string[];
|
||||
traceId: string | null;
|
||||
service: string | null;
|
||||
}
|
||||
|
||||
@@ -483,6 +483,7 @@ export function platformInfraHelp(): unknown {
|
||||
"bun scripts/cli.ts platform-infra observability apply --target D601 --confirm",
|
||||
"bun scripts/cli.ts platform-infra observability status --target D601",
|
||||
"bun scripts/cli.ts platform-infra observability validate --target D601",
|
||||
"bun scripts/cli.ts platform-infra observability closeout --target D601 [--query 'up'] [--trace-id <otel-trace-id>] [--service <service>] [--full|--raw]",
|
||||
"bun scripts/cli.ts platform-infra observability trace <traceId> --target D601 [--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]",
|
||||
|
||||
Reference in New Issue
Block a user