bfi-cli 0.1.69 → 0.1.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.mjs +158 -4
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -7996,15 +7996,23 @@ const YMC_DEFAULT_BASE = process.env.BFI_YMC_BASE || "http://172.20.35.178:8901/
7996
7996
  var YmcApi = class {
7997
7997
  baseUrl;
7998
7998
  token;
7999
- constructor(token = null, baseUrl) {
7999
+ dryRun;
8000
+ constructor(token = null, baseUrl, dryRun = false) {
8000
8001
  this.baseUrl = (baseUrl || YMC_DEFAULT_BASE).replace(/\/$/, "");
8002
+ this.dryRun = dryRun;
8001
8003
  if (token) {
8002
8004
  this.token = token;
8003
8005
  return;
8004
8006
  }
8005
8007
  this.token = loadGlobalConfig()?.token ?? null;
8006
8008
  }
8009
+ _dryRunExit(method, path, body) {
8010
+ console.log(`[dry-run] ${method} ${this.baseUrl}/${path.replace(/^\//, "")}`);
8011
+ if (body !== void 0 && Object.keys(body).length > 0) console.log(JSON.stringify(body, null, 2));
8012
+ process.exit(0);
8013
+ }
8007
8014
  async call(path, body = {}, timeoutMs = 9e4) {
8015
+ if (this.dryRun) this._dryRunExit("POST", path, body);
8008
8016
  const url = `${this.baseUrl}/${path.replace(/^\//, "")}`;
8009
8017
  const payload = JSON.stringify(body);
8010
8018
  const mod = url.startsWith("https://") ? https : http;
@@ -8045,6 +8053,11 @@ var YmcApi = class {
8045
8053
  };
8046
8054
  }
8047
8055
  async download(path, body, outFile, timeoutMs = 18e4) {
8056
+ if (this.dryRun) {
8057
+ console.log(`[dry-run] POST ${this.baseUrl}/${path.replace(/^\//, "")} (响应写盘 → ${outFile})`);
8058
+ if (Object.keys(body).length > 0) console.log(JSON.stringify(body, null, 2));
8059
+ process.exit(0);
8060
+ }
8048
8061
  const url = `${this.baseUrl}/${path.replace(/^\//, "")}`;
8049
8062
  const payload = JSON.stringify(body);
8050
8063
  const mod = url.startsWith("https://") ? https : http;
@@ -8078,6 +8091,7 @@ var YmcApi = class {
8078
8091
  return raw.length;
8079
8092
  }
8080
8093
  async get(path, timeoutMs = 3e4) {
8094
+ if (this.dryRun) this._dryRunExit("GET", path);
8081
8095
  const url = `${this.baseUrl}/${path.replace(/^\//, "")}`;
8082
8096
  const mod = url.startsWith("https://") ? https : http;
8083
8097
  const raw = await new Promise((resolve, reject) => {
@@ -8189,13 +8203,22 @@ async function runYmc(args, globalOpts) {
8189
8203
  const sub = args[0];
8190
8204
  const rest = args.slice(1);
8191
8205
  const jsonMode = flag(rest, "--json");
8206
+ const dryRun = flag(rest, "--dry-run");
8192
8207
  const token = globalOpts.token;
8193
- const api = new YmcApi(token ?? null);
8194
- requireToken(api);
8208
+ const api = new YmcApi(token ?? null, void 0, dryRun);
8195
8209
  if (!sub || sub === "--help" || sub === "-h") {
8196
8210
  printHelp();
8197
8211
  return;
8198
8212
  }
8213
+ if (sub === "help") {
8214
+ printCommandHelp(rest[0] || "");
8215
+ return;
8216
+ }
8217
+ if (flag(rest, "--help") || flag(rest, "-h")) {
8218
+ printCommandHelp(sub);
8219
+ return;
8220
+ }
8221
+ if (!dryRun) requireToken(api);
8199
8222
  switch (sub) {
8200
8223
  case "status":
8201
8224
  emit(await api.get("ymc/auth/status"), jsonMode, (data) => {
@@ -8279,6 +8302,7 @@ async function runYmc(args, globalOpts) {
8279
8302
  ...opt(rest, "--days") ? { days: Number(opt(rest, "--days")) } : {},
8280
8303
  ...opt(rest, "--line") ? { line: Number(opt(rest, "--line")) } : {}
8281
8304
  };
8305
+ if (!opt(rest, "-t", "--time") && !opt(rest, "--start-time") && !opt(rest, "--days")) console.error("⚠️ 未指定时间窗:服务端按超大窗口兜底,命中可能含数天前记录——取证请显式 -t/--start-time");
8282
8306
  emit(await api.call("sls/raw", body), jsonMode, (data) => {
8283
8307
  const d = data;
8284
8308
  const rows = Array.isArray(d) ? d : d.rows ?? d.data ?? [];
@@ -8732,6 +8756,133 @@ async function runYmc(args, globalOpts) {
8732
8756
  process.exit(1);
8733
8757
  }
8734
8758
  }
8759
+ const HELP = {
8760
+ status: `bfi ymc status — 查询 YMC 登录会话状态
8761
+ 说明:显示 dev/prod 两个 host 组的登录态与过期时间。
8762
+ 注意:显示"未登录"不影响取数——首次取数会自动登录(多等几秒),不要停下。`,
8763
+ trace: `bfi ymc trace <trace_id> -e <env> [--ts <毫秒>] [--json]
8764
+ 三源合一查询:SLS 业务日志 + warningChain 链路 + ingress 访问日志(诊断首选入口)。
8765
+ 参数:
8766
+ <trace_id> 追踪 ID(全局唯一,跨服务,无需 appCode)
8767
+ -e <env> 环境:test/daily/pre/core1-4/commldev
8768
+ --ts <毫秒> Epoch 毫秒时间锚点;默认自动推导(SLS 首条日志时间),
8769
+ SLS 无日志时须显式提供
8770
+ --json 输出完整信封 {code,msg,data}
8771
+ 摘要含:span 数/异常数/最大耗时/慢调用与慢SQL告警数/Top慢span/ingress 入口。
8772
+ 注意:trace 摘要的入口 URL 可能混入同链路其他入口记录——与目标不符时核对 ingress 明细。`,
8773
+ chain: `bfi ymc chain <trace_id> -e <env> [--ts <毫秒>] [--json]
8774
+ 原子源:warningChain 全量 Span 链路(耗时分解/调用树)。trace 三源合一的链路通道单独调用。`,
8775
+ "sls-logs": `bfi ymc sls-logs <trace_id> -e <env> [--ts <毫秒>] [--json]
8776
+ 原子源:SLS 业务日志(异常全文/堆栈)。按 traceid 索引检索。`,
8777
+ "sls-raw": `bfi ymc sls-raw "<查询>" -e <env> [-t <time> | --start-time <s> --end-time <e> | --days N] [--line N] [--json]
8778
+ SLS 原始查询(阿里云 SLS 完整语法透传:索引检索 + | SELECT 分析语句)。
8779
+ 参数:
8780
+ "<查询>" 查询语句。核心规则:索引检索前置(traceid: xx / "关键词" AND applicationname: xx),
8781
+ 禁止 * | SELECT * WHERE 字段=... (WHERE 全扫描必超时)
8782
+ -t <time> 时间简写 10m/2h/3d/4w(默认无时间=服务端超大窗兜底,会命中数天前记录,务必显式指定)
8783
+ --start-time/--end-time 精确窗口 yyyy-MM-dd HH:mm:ss 北京时间(优先于 -t)
8784
+ --days N 按天数回溯(旧参数,等价 -t Nd)
8785
+ --line N 返回行数上限
8786
+ 示例:
8787
+ bfi ymc sls-raw 'traceid: abc | SELECT * LIMIT 200' -e daily -t 1d
8788
+ bfi ymc sls-raw '"Exception" AND applicationname: yonbip-scm-pu | SELECT count(*) AS cnt' -e pre -t 3d
8789
+ bfi ymc sls-raw 'applicationname: yonbip-scm-scmmp AND "unaudit" | SELECT traceid, time LIMIT 10' -e core3 -t 1d
8790
+ 注意:业务关键词检索必须 applicationname: 限定目标服务(共享路径 URL 全平台都有);
8791
+ traceid/spanid 检索例外(全局唯一)。非索引字段(logger/requesturl)不能进检索语法,只能在 SELECT 里引用。`,
8792
+ "sls-grep": `bfi ymc sls-grep "<关键词>" -e <env> -t <time> [--json]
8793
+ SLS 全文检索聚合(每组计数)。注意:计数上限 100 可能封顶,影响面/精确计数用 sls-raw + GROUP BY。`,
8794
+ slowsql: `bfi ymc slowsql -t <time> -e <env> [--sql-str <表名或片段>] [--md5 <指纹>] [--trace-id <id>] [--app <appCode>] [--no-profiler] [--page N] [--page-size N] [--json]
8795
+ 慢 SQL 告警明细(耗时降序;摘要含 服务/耗时/行数/SQL 前段/指纹/调用栈首帧)。
8796
+ 参数:
8797
+ -t <time> 时间窗(必填语义,服务端强校验)
8798
+ --sql-str 按 SQL 片段过滤(表名/语句片段)
8799
+ --md5 按 SQL MD5 指纹精确过滤(同类 SQL 归类)
8800
+ --trace-id 按链路过滤。⚠️ 按 trace 查询时不带 --app(traceId 已唯一限定,
8801
+ --app 会截断其他服务的告警行——慢 SQL 归属哪个服务事先未知)
8802
+ --app 服务维度过滤(无 traceId 时必带,裸 appCode)
8803
+ --no-profiler 显式关闭 enableProfiler(默认自动带 'true'——不带该字段上游 500,
8804
+ 带了才返回 sqlStack 调用栈)
8805
+ 示例:
8806
+ bfi ymc slowsql -t 1d --app yonbip-scm-scmmp -e core3 # 服务维度(SQL 画像)
8807
+ bfi ymc slowsql -t 1d --trace-id abc -e core3 # 链路维度(勿带 --app)`,
8808
+ slowcall: `bfi ymc slowcall -t <time> -e <env> [--trace-id <id>] [--app <appCode>] [--method <方法>] [--min-cost <ms>] [--page N] [--page-size N] [--json]
8809
+ 慢调用告警明细(耗时降序;摘要含 服务/耗时/sql/rpc/redis 分解/方法/pod)。
8810
+ 参数:
8811
+ --trace-id 按链路过滤。⚠️ 不带 --app(同 slowsql,--app 会截断下游服务告警行)
8812
+ --app 服务维度过滤(裸 appCode)
8813
+ --method 按调用方法过滤
8814
+ --min-cost <ms> 最小耗时过滤(body.costTime=[ms, 999999])
8815
+ (无 --profiler) 历史参数已移除映射——上游 enableProfiler 是"仅返回有 CPU 采样
8816
+ 记录"的过滤器,实测任何组合均空集。CPU 热点走 dump-list。
8817
+ 示例:
8818
+ bfi ymc slowcall -t 1d --trace-id abc -e core3 # 链路分层分解(跨服务根因链必用)
8819
+ bfi ymc slowcall -t 4w --app yonbip-scm-pu -e pre # 服务慢调用趋势`,
8820
+ exceptions: `bfi ymc exceptions -t <time> -e <env> [--app <appCode>] [--json]
8821
+ 异常聚合(exceptionHistory)。--app 传裸微服务名(appId 需 <env>-<appCode> 格式,传裸名上游才查得到)。`,
8822
+ alerts: `bfi ymc alerts -t <time> -e <env> [--level error|warn|info] [--page-size N] [--json]
8823
+ 告警明细。--page-size 默认 10;--level 可省。`,
8824
+ "url-stats": `bfi ymc url-stats </uri> -t <time> -e <env> --app <service_name> [--json]
8825
+ URL 性能统计(ingress 访问日志聚合):QPS/avg/P50/P90/P95/P99/状态码分布/慢请求Top10(含 traceId)。
8826
+ 参数:
8827
+ --app <service_name> ⚠️ 必带(诊断纪律):共享路径 URL(/bill/* 等通用单据接口)全平台
8828
+ 每个业务域都有——不限定服务=全平台混合假面。传裸 appCode 即可
8829
+ (服务端自适应环境前缀 wildcard,如 online-dc-core3-<app>-out)
8830
+ 示例:
8831
+ bfi ymc url-stats /bill/unaudit -t 1d -e core3 --app yonbip-scm-scmmp`,
8832
+ ingress: `bfi ymc ingress --trace-id <id> | --uri </path> [-t <time>] -e <env> [--exact] [--app <service_name>] [--size N] [--json]
8833
+ ingress 访问日志明细(网关视角:request_time vs upstream_response_time/状态码/pod/租户)。
8834
+ 参数:
8835
+ --trace-id 按链路查(时间可省,默认 30d)
8836
+ --uri 按 URI 查(默认子串匹配,--exact 精确;time 必填)
8837
+ --app service_name 过滤(uri 模式必带,裸 appCode 自适应前缀)
8838
+ --size N 返回条数(默认 100,最大 5000)`,
8839
+ "dump-list": `bfi ymc dump-list -t <time> -e <env> [--app <appCode>] [--type profiler|heap|...] [--json]
8840
+ 诊断文件列表(火焰图/JVM dump;CPU 热点取数的正确入口)。`,
8841
+ cases: `bfi ymc cases <search|show|upload|index> [参数]
8842
+ KEDB 案例库(内部诊断先验第一源)。
8843
+ search [--type <t>] [--finger "<指纹>"] [--service <svc>] [--kw "<关键词>"] [--limit N]
8844
+ show <case_id>
8845
+ upload --file <报告.html> [--type slow-req] [--finger "词1,词2"] [--env] [--service]
8846
+ index 案例库索引重建`,
8847
+ wiki: `bfi ymc wiki <search|show> [参数]
8848
+ 知识库统一检索(confluence + jira + 文库 ecfile 三源——诊断先验的外部源,勿只查其一)。
8849
+ search "<关键词>" [--source confluence|jira|ecfile] [--limit N] [--titles]
8850
+ show <id> [--source wiki|uap-wiki|gfwiki|gfjira|ecfile]
8851
+ 示例:
8852
+ bfi ymc wiki search "/bill/unaudit 超时" # 三源全查(默认)
8853
+ bfi ymc wiki show BIP-BUG-00157126 --source gfjira`,
8854
+ callstat: `bfi ymc callstat -t <time> -e <env> [--page N] [--page-size N] [--json]
8855
+ 慢调用统计版(warningCallstat 聚合视图;体检/趋势用)。--app 经 --data 传(见 call)。`,
8856
+ sqlstat: `bfi ymc sqlstat -t <time> -e <env> [--page N] [--page-size N] [--json]
8857
+ 慢 SQL 统计版(warningSqlstat 聚合视图)。`,
8858
+ events: `bfi ymc events -e <env> [--type <类型>] [--start-time <s>] [--end-time <e>] [--app <appCode>] [--pipeline <code>] [--histogram] [--json]
8859
+ 集群事件明细/直方图。`,
8860
+ "log-url": `bfi ymc log-url -e <env> [--type ingressLog|appLog|instanceLog] [--app <appId>] [--filter-app <ids>]
8861
+ 生成 SLS 日志直通 URL(浏览器直接打开的访问/业务/实例日志页签)。`,
8862
+ "sample-list": `bfi ymc sample-list -t <time> -e <env> [--json]
8863
+ 采样数据列表。`,
8864
+ rca: `bfi ymc rca -e <env> [-t <time> | --start-time <s> --end-time <e>] [--app <appId>] [--app-code <appCode>] [--json]
8865
+ YMC 官方智能诊断 RCA 全报告。⚠️ 长耗时(实测约 300s),上游需 podId 等参数,失败多因参数不足;客户端超时已设 300s。`,
8866
+ "bpr-download": `bfi ymc bpr-download <pk> -e <env> [-o <输出文件>]
8867
+ BPR 报告 HTML 下载(文件流写盘)。pk 来源:bfi ymc call bpr/list --data '{"page":1,"pageSize":10}' -e <env>。
8868
+ 输出默认 bpr_<pk前16>.html。`,
8869
+ call: `bfi ymc call <route> -e <env> [--data '<json>'] [-t <time> | --start-time <s> --end-time <e>] [--timeout <秒>] [--json]
8870
+ 通用透传:覆盖全部注册表端点(warningCall/warningSql/exceptionHistory/bpr/list/alert/detail/tool/list/app/history/environment/uba/query ...)。
8871
+ 完整清单与参数声明:curl http://172.20.35.178:8901/openapi.json 或 /docs(Swagger UI)。
8872
+ 时间参数(-t/--start-time/--end-time)由服务端按端点 time_fields 展开为 beginTs/endTs 等。
8873
+ 示例:
8874
+ bfi ymc call warningCallstat --data '{"curAppCode":"yonbip-scm-scmmp","page":1,"pageSize":10}' -e core3 -t 1h
8875
+ bfi ymc call app/history --data '{"appId":"daily-x","queryType":"podCpuUsage"}' -e daily -t 1d`
8876
+ };
8877
+ function printCommandHelp(cmd) {
8878
+ const h = HELP[cmd];
8879
+ if (h) console.log(h);
8880
+ else {
8881
+ console.error(`未知子命令:${cmd}`);
8882
+ printHelp();
8883
+ process.exit(1);
8884
+ }
8885
+ }
8735
8886
  function printHelp() {
8736
8887
  console.log(`
8737
8888
  bfi ymc — 观测查询(v2 API:YMC/Kibana/SLS/trace)
@@ -8761,8 +8912,11 @@ bfi ymc — 观测查询(v2 API:YMC/Kibana/SLS/trace)
8761
8912
  -t, --time 时间简写(10m/2h/3d/4w = 过去 N 单位到现在)
8762
8913
  --start-time <t> 开始时间 yyyy-MM-dd HH:mm:ss(与 -t 二选一;只传它=到当前)
8763
8914
  --end-time <t> 结束时间(须与 --start-time 同传)
8764
- --json 输出原始 JSON
8915
+ --json 输出原始 JSON(完整信封 {code,msg,data})
8916
+ --dry-run 只打印将发送的 method/URL/body,不实际请求(无需登录)
8765
8917
  --token 覆盖已登录 token(默认用 bfi auth login 的)
8918
+
8919
+ 详细帮助:bfi ymc help <命令>(或 bfi ymc <命令> -h)——含参数说明/默认值/示例。
8766
8920
  `);
8767
8921
  }
8768
8922
  const __dirname = dirname(fileURLToPath(import.meta.url));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bfi-cli",
3
- "version": "0.1.69",
3
+ "version": "0.1.71",
4
4
  "description": "用友大业财BFI统一命令行工具,支持技能,技能包,元数据,UI元数据等",
5
5
  "type": "module",
6
6
  "bin": {