@p-moon/yue-cli 0.1.6 → 0.1.8
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.
- package/README.md +297 -12
- package/dist/bin/yue.js +1484 -62
- package/package.json +1 -1
package/dist/bin/yue.js
CHANGED
|
@@ -145,6 +145,50 @@ async function withBrowser(fn, opts) {
|
|
|
145
145
|
});
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
+
async function withBrowserAutoDisconnect(fn, opts) {
|
|
149
|
+
return withBrowser(async (page) => {
|
|
150
|
+
const ac = new AbortController();
|
|
151
|
+
const trigger = () => {
|
|
152
|
+
if (!ac.signal.aborted) {
|
|
153
|
+
ac.abort(new Error("Browser connection lost (page closed or extension disconnected)"));
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
const attachers = [];
|
|
157
|
+
try {
|
|
158
|
+
const handler = () => trigger();
|
|
159
|
+
if (typeof page?.on === "function") {
|
|
160
|
+
page.on("close", handler);
|
|
161
|
+
page.on("disconnected", handler);
|
|
162
|
+
page.on("crash", handler);
|
|
163
|
+
attachers.push(() => {
|
|
164
|
+
try {
|
|
165
|
+
page.off?.("close", handler);
|
|
166
|
+
} catch {
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
page.off?.("disconnected", handler);
|
|
170
|
+
} catch {
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
page.off?.("crash", handler);
|
|
174
|
+
} catch {
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
} catch {
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
return await fn(page, trigger, ac.signal);
|
|
182
|
+
} finally {
|
|
183
|
+
while (attachers.length) {
|
|
184
|
+
try {
|
|
185
|
+
attachers.pop()();
|
|
186
|
+
} catch {
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}, opts);
|
|
191
|
+
}
|
|
148
192
|
|
|
149
193
|
// src/lib/mydb-api.ts
|
|
150
194
|
var BASE_URL = "https://mydb.jdfmgt.com";
|
|
@@ -210,11 +254,11 @@ async function executeSql(page, sql, dbId, pageNum = 1, limit = 25) {
|
|
|
210
254
|
|
|
211
255
|
// src/commands/datasources.ts
|
|
212
256
|
function registerDatasourcesCommand(program) {
|
|
213
|
-
program.command("datasources").description("
|
|
257
|
+
program.command("datasources").description("\u5217\u51FA mydb \u53EF\u7528\u6570\u636E\u6E90").option("--filter <keyword>", "\u6309\u5173\u952E\u5B57\u8FC7\u6EE4\u6570\u636E\u6E90").option("--output <format>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable\uFF08\u9ED8\u8BA4\uFF09/ json", "table").action(async (opts) => {
|
|
214
258
|
await withBrowser(async (page) => {
|
|
215
259
|
const sources = await fetchDatasources(page, opts.filter);
|
|
216
260
|
if (!sources || sources.length === 0) {
|
|
217
|
-
console.log("
|
|
261
|
+
console.log("\u672A\u627E\u5230\u6570\u636E\u6E90\u3002");
|
|
218
262
|
return;
|
|
219
263
|
}
|
|
220
264
|
if ((opts.output ?? "table").toLowerCase() === "json") {
|
|
@@ -231,7 +275,7 @@ function registerDatasourcesCommand(program) {
|
|
|
231
275
|
}
|
|
232
276
|
console.log(table.toString());
|
|
233
277
|
console.log(`
|
|
234
|
-
${sources.length}
|
|
278
|
+
\u5171 ${sources.length} \u4E2A\u6570\u636E\u6E90`);
|
|
235
279
|
});
|
|
236
280
|
});
|
|
237
281
|
}
|
|
@@ -239,7 +283,7 @@ ${sources.length} data source(s)`);
|
|
|
239
283
|
// src/commands/query.ts
|
|
240
284
|
import Table2 from "cli-table3";
|
|
241
285
|
function registerQueryCommand(program) {
|
|
242
|
-
program.command("query").description("
|
|
286
|
+
program.command("query").description("\u5728 mydb \u4E0A\u6267\u884C SQL \u67E5\u8BE2").requiredOption("--sql <sql>", "\u8981\u6267\u884C\u7684 SQL \u8BED\u53E5\uFF08\u5FC5\u586B\uFF09").option("--dbId <id>", "\u6570\u636E\u6E90 ID", parseInt).option("--dbName <name>", "\u6570\u636E\u6E90\u540D\u79F0\uFF08\u6A21\u7CCA\u5339\u914D\uFF0C\u53EF\u66FF\u4EE3 --dbId\uFF09").option("--page <n>", "\u9875\u7801\uFF08\u9ED8\u8BA4\uFF1A1\uFF09", parseInt, 1).option("--limit <n>", "\u6BCF\u9875\u884C\u6570\uFF08\u9ED8\u8BA4\uFF1A25\uFF09", parseInt, 25).option("--output <format>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable\uFF08\u9ED8\u8BA4\uFF09/ json", "table").action(async (opts) => {
|
|
243
287
|
const sql = opts.sql;
|
|
244
288
|
let dbId = opts.dbId;
|
|
245
289
|
const dbName = opts.dbName;
|
|
@@ -247,7 +291,7 @@ function registerQueryCommand(program) {
|
|
|
247
291
|
const limitNum = opts.limit ?? 25;
|
|
248
292
|
const format = (opts.output ?? "table").toLowerCase();
|
|
249
293
|
if (!sql?.trim()) {
|
|
250
|
-
console.error("
|
|
294
|
+
console.error("\u9519\u8BEF\uFF1A\u5FC5\u987B\u63D0\u4F9B --sql");
|
|
251
295
|
process.exit(1);
|
|
252
296
|
}
|
|
253
297
|
await withBrowser(async (page) => {
|
|
@@ -255,8 +299,8 @@ function registerQueryCommand(program) {
|
|
|
255
299
|
const sources = await fetchDatasources(page);
|
|
256
300
|
const match = resolveDbIdByName(sources, dbName);
|
|
257
301
|
if (!match) {
|
|
258
|
-
console.error(
|
|
259
|
-
console.error('
|
|
302
|
+
console.error(`\u9519\u8BEF\uFF1A\u672A\u627E\u5230\u6570\u636E\u6E90 "${dbName}"\u3002`);
|
|
303
|
+
console.error('\u8BF7\u8FD0\u884C "yue mydb datasources" \u67E5\u770B\u53EF\u7528\u6570\u636E\u6E90\u3002');
|
|
260
304
|
process.exit(1);
|
|
261
305
|
}
|
|
262
306
|
dbId = match.id;
|
|
@@ -264,16 +308,16 @@ function registerQueryCommand(program) {
|
|
|
264
308
|
if (!dbId) {
|
|
265
309
|
const sources = await fetchDatasources(page);
|
|
266
310
|
if (sources.length === 0) {
|
|
267
|
-
console.error("
|
|
311
|
+
console.error("\u6CA1\u6709\u53EF\u7528\u7684\u6570\u636E\u6E90\uFF0C\u8BF7\u786E\u8BA4\u4F60\u5DF2\u5728\u6D4F\u89C8\u5668\u4E2D\u767B\u5F55 mydb\u3002");
|
|
268
312
|
process.exit(1);
|
|
269
313
|
}
|
|
270
314
|
const listText = sources.map((s, i) => ` ${i + 1}. [${s.id}] ${s.name}`).join("\n");
|
|
271
315
|
const answer = await page.evaluate((msg) => {
|
|
272
316
|
return window.prompt(msg, "");
|
|
273
|
-
},
|
|
317
|
+
}, `\u8BF7\u9009\u62E9\u4E00\u4E2A\u6570\u636E\u6E90\uFF08\u8F93\u5165\u5E8F\u53F7 / dbId / \u540D\u79F0\uFF09\uFF1A
|
|
274
318
|
${listText}`);
|
|
275
319
|
if (!answer) {
|
|
276
|
-
console.error("
|
|
320
|
+
console.error("\u672A\u9009\u62E9\u6570\u636E\u6E90\u3002");
|
|
277
321
|
process.exit(1);
|
|
278
322
|
}
|
|
279
323
|
const trimmed = String(answer).trim();
|
|
@@ -285,7 +329,7 @@ ${listText}`);
|
|
|
285
329
|
} else {
|
|
286
330
|
const match = resolveDbIdByName(sources, trimmed);
|
|
287
331
|
if (!match) {
|
|
288
|
-
console.error(
|
|
332
|
+
console.error(`\u672A\u627E\u5230\u5339\u914D\u7684\u6570\u636E\u6E90 "${trimmed}"\u3002`);
|
|
289
333
|
process.exit(1);
|
|
290
334
|
}
|
|
291
335
|
dbId = match.id;
|
|
@@ -323,7 +367,6 @@ ${result.tip}`);
|
|
|
323
367
|
import Table3 from "cli-table3";
|
|
324
368
|
|
|
325
369
|
// src/lib/digger-api.ts
|
|
326
|
-
import * as crypto2 from "node:crypto";
|
|
327
370
|
var BASE_URL2 = "https://digger.jd.com";
|
|
328
371
|
function diggerXhr(page, method, url, body) {
|
|
329
372
|
return page.evaluate((args) => {
|
|
@@ -366,52 +409,133 @@ async function fuzzySearchApps(page, appFuzzy) {
|
|
|
366
409
|
online: r.online ?? true
|
|
367
410
|
}));
|
|
368
411
|
}
|
|
369
|
-
async function
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
endTime: now,
|
|
376
|
-
keyword: opts.keyword,
|
|
377
|
-
exclude: "",
|
|
378
|
-
filePaths: [],
|
|
379
|
-
logLevel: opts.logLevel ?? "ALL",
|
|
380
|
-
limit: opts.limit ?? 50,
|
|
381
|
-
logSize: "",
|
|
382
|
-
station: "chinaStation",
|
|
383
|
-
searchType: opts.searchType ?? "exact",
|
|
384
|
-
productName: "app",
|
|
385
|
-
direction: "backward",
|
|
386
|
-
rentionPolicy: "LOKI",
|
|
387
|
-
dirEnabled: false,
|
|
388
|
-
showPlain: false,
|
|
389
|
-
searchId: crypto2.randomUUID(),
|
|
390
|
-
searchIndex: 0,
|
|
391
|
-
searchEndTimeStr: null,
|
|
392
|
-
coefficient: null
|
|
393
|
-
};
|
|
394
|
-
const url = `${BASE_URL2}/log/search/all`;
|
|
395
|
-
const result = await diggerXhr(page, "POST", url, body);
|
|
412
|
+
async function listAppIpsV2(page, appName, sTime, eTime) {
|
|
413
|
+
const params = new URLSearchParams({ appName, ipOrPodName: "" });
|
|
414
|
+
if (sTime !== void 0) params.set("sTime", String(sTime));
|
|
415
|
+
if (eTime !== void 0) params.set("eTime", String(eTime));
|
|
416
|
+
const url = `${BASE_URL2}/app/ip?${params.toString()}`;
|
|
417
|
+
const result = await diggerXhr(page, "GET", url);
|
|
396
418
|
if (!result.ok) {
|
|
397
|
-
throw new Error(`Digger
|
|
419
|
+
throw new Error(`Digger app/ip error: HTTP ${result.status} \u2014 ${JSON.stringify(result.body)}`);
|
|
398
420
|
}
|
|
399
|
-
const
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
host: item.host ?? "",
|
|
408
|
-
filePath: item.filePath ?? "",
|
|
409
|
-
app: item.app ?? "",
|
|
410
|
-
thread: item.t_h_r ?? "",
|
|
411
|
-
className: item.c_l_s ?? "",
|
|
412
|
-
traceId: item.traceId ?? item.pfinderTraceId ?? null
|
|
421
|
+
const list = Array.isArray(result.body) ? result.body : [];
|
|
422
|
+
return list.map((r) => ({
|
|
423
|
+
ip: r.ip ?? "",
|
|
424
|
+
type: r.type ?? "",
|
|
425
|
+
podName: r.podName ?? "",
|
|
426
|
+
show: r.show ?? "",
|
|
427
|
+
ipOrPodName: r.ipOrPodName ?? "",
|
|
428
|
+
groupName: r.groupName ?? ""
|
|
413
429
|
}));
|
|
414
|
-
|
|
430
|
+
}
|
|
431
|
+
async function listAppFiles(page, appName, containAll = false) {
|
|
432
|
+
const url = `${BASE_URL2}/app/files/new?appName=${encodeURIComponent(appName)}&containAll=${containAll}`;
|
|
433
|
+
const result = await diggerXhr(page, "GET", url);
|
|
434
|
+
if (!result.ok) {
|
|
435
|
+
throw new Error(`Digger app/files/new error: HTTP ${result.status} \u2014 ${JSON.stringify(result.body)}`);
|
|
436
|
+
}
|
|
437
|
+
return Array.isArray(result.body) ? result.body : [];
|
|
438
|
+
}
|
|
439
|
+
async function localLogTaskCommit(page, opts) {
|
|
440
|
+
const params = new URLSearchParams();
|
|
441
|
+
params.set("appName", opts.appName);
|
|
442
|
+
params.set("file", opts.file);
|
|
443
|
+
params.set("grep", opts.grep ?? "");
|
|
444
|
+
params.set("grep_v", opts.grepV ?? "");
|
|
445
|
+
params.set("maxMatchRow", String(opts.maxMatchRow ?? 50));
|
|
446
|
+
params.set("lineOffsetBefore", String(opts.lineOffsetBefore ?? 0));
|
|
447
|
+
params.set("lineOffsetAfter", String(opts.lineOffsetAfter ?? 0));
|
|
448
|
+
params.set("grepDirection", String(opts.grepDirection ?? true));
|
|
449
|
+
params.set("searchScope", opts.searchScope ?? "100M");
|
|
450
|
+
params.set("showPlain", String(opts.showPlain ?? false));
|
|
451
|
+
if (opts.selectIp) params.set("selectIp", opts.selectIp);
|
|
452
|
+
const url = `${BASE_URL2}/log/local/task/commit`;
|
|
453
|
+
const result = await page.evaluate((args) => {
|
|
454
|
+
return new Promise((resolve) => {
|
|
455
|
+
const xhr = new XMLHttpRequest();
|
|
456
|
+
xhr.open("POST", args.url, true);
|
|
457
|
+
xhr.withCredentials = true;
|
|
458
|
+
xhr.setRequestHeader("Accept", "application/json, text/plain, */*");
|
|
459
|
+
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
|
460
|
+
xhr.onload = () => {
|
|
461
|
+
try {
|
|
462
|
+
resolve({ ok: xhr.status >= 200 && xhr.status < 300, status: xhr.status, body: JSON.parse(xhr.responseText) });
|
|
463
|
+
} catch {
|
|
464
|
+
resolve({ ok: xhr.status >= 200 && xhr.status < 300, status: xhr.status, body: xhr.responseText });
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
xhr.onerror = () => resolve({ ok: false, status: 0, body: "Network error" });
|
|
468
|
+
xhr.send(args.body);
|
|
469
|
+
});
|
|
470
|
+
}, { url, body: params.toString() });
|
|
471
|
+
if (!result.ok) {
|
|
472
|
+
throw new Error(`Digger local task commit error: HTTP ${result.status} \u2014 ${JSON.stringify(result.body)}`);
|
|
473
|
+
}
|
|
474
|
+
return result.body;
|
|
475
|
+
}
|
|
476
|
+
async function localLogTaskResult(page, taskId) {
|
|
477
|
+
const url = `${BASE_URL2}/log/local/task/result?task_id=${taskId}`;
|
|
478
|
+
const result = await diggerXhr(page, "GET", url);
|
|
479
|
+
if (!result.ok) {
|
|
480
|
+
throw new Error(`Digger local task result error: HTTP ${result.status} \u2014 ${JSON.stringify(result.body)}`);
|
|
481
|
+
}
|
|
482
|
+
return result.body;
|
|
483
|
+
}
|
|
484
|
+
async function localLogTaskContent(page, taskId, ip, fileName, showPlain = false) {
|
|
485
|
+
const params = new URLSearchParams({
|
|
486
|
+
task_id: String(taskId),
|
|
487
|
+
ip,
|
|
488
|
+
fileName,
|
|
489
|
+
showPlain: String(showPlain)
|
|
490
|
+
});
|
|
491
|
+
const url = `${BASE_URL2}/log/local/task/content?${params.toString()}`;
|
|
492
|
+
const result = await diggerXhr(page, "GET", url);
|
|
493
|
+
if (!result.ok) {
|
|
494
|
+
throw new Error(`Digger local task content error: HTTP ${result.status} \u2014 ${JSON.stringify(result.body)}`);
|
|
495
|
+
}
|
|
496
|
+
return Array.isArray(result.body) ? result.body : [];
|
|
497
|
+
}
|
|
498
|
+
async function localLogSearch(page, opts, maxPollMs = 3e4) {
|
|
499
|
+
const task = await localLogTaskCommit(page, opts);
|
|
500
|
+
const start = Date.now();
|
|
501
|
+
let taskResult = {};
|
|
502
|
+
while (Date.now() - start < maxPollMs) {
|
|
503
|
+
taskResult = await localLogTaskResult(page, task.id);
|
|
504
|
+
const allDone = Object.values(taskResult).every(
|
|
505
|
+
(entries2) => entries2.every((e) => e.taskStatus === 0 || e.success)
|
|
506
|
+
);
|
|
507
|
+
if (allDone) break;
|
|
508
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
509
|
+
}
|
|
510
|
+
let bestIp = "";
|
|
511
|
+
let bestCount = 0;
|
|
512
|
+
for (const [ip, entries2] of Object.entries(taskResult)) {
|
|
513
|
+
for (const e of entries2) {
|
|
514
|
+
if (e.success && e.logCount > bestCount) {
|
|
515
|
+
bestCount = e.logCount;
|
|
516
|
+
bestIp = ip;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
let entries = [];
|
|
521
|
+
if (bestIp) {
|
|
522
|
+
entries = await localLogTaskContent(
|
|
523
|
+
page,
|
|
524
|
+
task.id,
|
|
525
|
+
bestIp,
|
|
526
|
+
opts.file,
|
|
527
|
+
opts.showPlain ?? false
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
return { entries, ip: bestIp, taskResult };
|
|
531
|
+
}
|
|
532
|
+
async function listAppIps(page, opts) {
|
|
533
|
+
const url = `${BASE_URL2}/overview/appIp/list?productName=${encodeURIComponent(opts.productName)}&instanceName=${encodeURIComponent(opts.instanceName)}&start=${encodeURIComponent(String(opts.start))}&end=${encodeURIComponent(String(opts.end))}`;
|
|
534
|
+
const result = await diggerXhr(page, "GET", url);
|
|
535
|
+
if (!result.ok) {
|
|
536
|
+
throw new Error(`Digger appIp list error: HTTP ${result.status} \u2014 ${JSON.stringify(result.body)}`);
|
|
537
|
+
}
|
|
538
|
+
return result.body;
|
|
415
539
|
}
|
|
416
540
|
|
|
417
541
|
// src/commands/digger.ts
|
|
@@ -447,18 +571,61 @@ function colorizeLevel(level) {
|
|
|
447
571
|
}
|
|
448
572
|
}
|
|
449
573
|
function registerDiggerCommand(program) {
|
|
450
|
-
const digger = program.command("digger").description("Digger
|
|
451
|
-
digger.command("history").description("
|
|
574
|
+
const digger = program.command("digger").description("Digger\uFF08joywatch.jd.com\uFF09\u65E5\u5FD7\u76F8\u5173\u64CD\u4F5C");
|
|
575
|
+
digger.command("history").description("\u67E5\u8BE2 Digger \u5386\u53F2\u65E5\u5FD7\uFF08\u57FA\u4E8E Loki \u7D22\u5F15\uFF09").addHelpText("after", `
|
|
576
|
+
\u4F7F\u7528\u793A\u4F8B\uFF1A
|
|
577
|
+
# \u5217\u51FA\u5339\u914D\u7684\u5E94\u7528
|
|
578
|
+
yue digger history --appName baoxian
|
|
579
|
+
|
|
580
|
+
# \u5173\u952E\u5B57\u641C\u7D22\uFF08\u5B8C\u5168\u5339\u914D\uFF09
|
|
581
|
+
yue digger history --appName baoxian-mall-trade --keyWord getUserAuthInfo
|
|
582
|
+
|
|
583
|
+
# \u6B63\u5219\u5339\u914D
|
|
584
|
+
yue digger history --appName baoxian-mall-trade --keyWord "getUserAuthInfo.*req" --searchType regular
|
|
585
|
+
|
|
586
|
+
# \u6307\u5B9A\u65F6\u95F4\u8303\u56F4
|
|
587
|
+
yue digger history --appName baoxian-mall-trade --keyWord getUserAuthInfo \\
|
|
588
|
+
--startTime "2026-07-01 09:00:00" --endTime "2026-07-01 18:00:00"
|
|
589
|
+
|
|
590
|
+
# \u8FC7\u6EE4\u65E5\u5FD7\u7EA7\u522B
|
|
591
|
+
yue digger history --appName baoxian-mall-trade --keyWord getUserAuthInfo --logLevel ERROR
|
|
592
|
+
|
|
593
|
+
# \u6392\u9664\u5173\u952E\u5B57
|
|
594
|
+
yue digger history --appName baoxian-mall-trade --keyWord Exception --exclude "pfinder,sgm"
|
|
595
|
+
|
|
596
|
+
# \u9650\u5236\u8FD4\u56DE\u6761\u6570
|
|
597
|
+
yue digger history --appName baoxian-mall-trade --keyWord getUserAuthInfo --limit 20
|
|
598
|
+
|
|
599
|
+
# JSON \u8F93\u51FA
|
|
600
|
+
yue digger history --appName baoxian-mall-trade --keyWord getUserAuthInfo --output json
|
|
601
|
+
`).option("--appName <prefix>", "\u5E94\u7528\u540D\u79F0/\u524D\u7F00\uFF08\u6A21\u7CCA\u5339\u914D\uFF0C\u7528\u4E8E\u9009\u62E9\u5E94\u7528\uFF09").option("--keyWord <keyword>", "\u641C\u7D22\u5173\u952E\u5B57\uFF08\u6216\u6B63\u5219\u8868\u8FBE\u5F0F\uFF0C\u53D6\u51B3\u4E8E --searchType\uFF09").option("--limit <n>", "\u8FD4\u56DE\u6761\u6570\uFF08\u9ED8\u8BA4\uFF1A50\uFF09", parseInt, 50).option("--logLevel <level>", "\u65E5\u5FD7\u7EA7\u522B\uFF08\u9ED8\u8BA4\uFF1AALL\uFF09", "ALL").option("--searchType <type>", "\u641C\u7D22\u7C7B\u578B\uFF1Aexact\uFF08\u5173\u952E\u5B57\u5339\u914D\uFF0C\u9ED8\u8BA4\uFF09/ regular\uFF08\u6B63\u5219\u5339\u914D\uFF09", "exact").option("--exclude <text>", "\u6392\u9664\u5173\u952E\u5B57\uFF08exclude\uFF09").option("--filePaths <paths>", "\u65E5\u5FD7\u6587\u4EF6\u8DEF\u5F84\u8FC7\u6EE4\uFF0C\u9017\u53F7\u5206\u9694\uFF08filePaths\uFF09").option("--logSize <size>", "\u65E5\u5FD7\u5927\u5C0F\u8FC7\u6EE4\uFF08logSize\uFF0C\u900F\u4F20\uFF09").option("--station <name>", "\u7AD9\u70B9\uFF08station\uFF0C\u9ED8\u8BA4\uFF1AchinaStation\uFF09", "chinaStation").option("--productName <name>", "\u4EA7\u54C1\u540D\uFF08productName\uFF0C\u9ED8\u8BA4\uFF1Aapp\uFF09", "app").option("--direction <dir>", "\u65B9\u5411\uFF08direction\uFF09\uFF1Abackward\uFF08\u9ED8\u8BA4\uFF09/ forward", "backward").option("--rentionPolicy <policy>", "\u5B58\u50A8\u7B56\u7565\uFF08rentionPolicy\uFF0C\u9ED8\u8BA4\uFF1ALOKI\uFF09", "LOKI").option("--dirEnabled <bool>", "dirEnabled\uFF08\u9ED8\u8BA4\uFF1Afalse\uFF09", "false").option("--showPlain <bool>", "showPlain\uFF08\u9ED8\u8BA4\uFF1Afalse\uFF09", "false").option("--searchId <id>", "searchId\uFF08\u53EF\u9009\uFF1B\u9ED8\u8BA4\u81EA\u52A8\u751F\u6210 uuid\uFF09").option("--searchIndex <n>", "searchIndex\uFF08\u9ED8\u8BA4\uFF1A0\uFF09", parseInt, 0).option("--searchEndTimeStr <str>", "searchEndTimeStr\uFF08\u9ED8\u8BA4\uFF1Anull\uFF09").option("--coefficient <n>", "coefficient\uFF08\u9ED8\u8BA4\uFF1Anull\uFF09", parseFloat).option("--startTime <datetime>", '\u5F00\u59CB\u65F6\u95F4\uFF08\u4F8B\u5982\uFF1A"2026-07-01 09:00:00" \u6216 "2026-07-01T09:00"\uFF09').option("--endTime <datetime>", '\u7ED3\u675F\u65F6\u95F4\uFF08\u4F8B\u5982\uFF1A"2026-07-01 18:00:00" \u6216 "2026-07-01T18:00"\uFF09').option("--output <format>", "\u8F93\u51FA\u683C\u5F0F\uFF1Aplain\uFF08\u9ED8\u8BA4\uFF09/ json", "plain").action(async (opts) => {
|
|
452
602
|
const appFuzzy = opts.appName;
|
|
453
603
|
const keyword = opts.keyWord;
|
|
454
604
|
const limit = opts.limit ?? 50;
|
|
455
605
|
const logLevel = opts.logLevel ?? "ALL";
|
|
456
606
|
const searchType = (opts.searchType ?? "exact").toLowerCase();
|
|
457
607
|
const format = (opts.output ?? "plain").toLowerCase();
|
|
608
|
+
const exclude = opts.exclude ?? "";
|
|
609
|
+
const filePaths = typeof opts.filePaths === "string" && opts.filePaths.trim() ? String(opts.filePaths).split(",").map((s) => s.trim()).filter(Boolean) : void 0;
|
|
610
|
+
const logSize = opts.logSize ?? "";
|
|
611
|
+
const station = opts.station ?? "chinaStation";
|
|
612
|
+
const productName = opts.productName ?? "app";
|
|
613
|
+
const direction = opts.direction ?? "backward";
|
|
614
|
+
const rentionPolicy = opts.rentionPolicy ?? "LOKI";
|
|
615
|
+
const dirEnabled = String(opts.dirEnabled ?? "false").toLowerCase() === "true";
|
|
616
|
+
const showPlain = String(opts.showPlain ?? "false").toLowerCase() === "true";
|
|
617
|
+
const searchId = opts.searchId ?? void 0;
|
|
618
|
+
const searchIndex = opts.searchIndex ?? 0;
|
|
619
|
+
const searchEndTimeStr = opts.searchEndTimeStr === void 0 ? void 0 : opts.searchEndTimeStr;
|
|
620
|
+
const coefficient = opts.coefficient === void 0 || opts.coefficient === null || Number.isNaN(opts.coefficient) ? void 0 : opts.coefficient;
|
|
458
621
|
if (searchType !== "exact" && searchType !== "regular") {
|
|
459
622
|
console.error(`\u274C Invalid --searchType: "${opts.searchType}". Use "exact" or "regular".`);
|
|
460
623
|
process.exit(1);
|
|
461
624
|
}
|
|
625
|
+
if (direction !== "backward" && direction !== "forward") {
|
|
626
|
+
console.error(`\u274C Invalid --direction: "${opts.direction}". Use "backward" or "forward".`);
|
|
627
|
+
process.exit(1);
|
|
628
|
+
}
|
|
462
629
|
const startTime = opts.startTime ? new Date(opts.startTime).getTime() : void 0;
|
|
463
630
|
const endTime = opts.endTime ? new Date(opts.endTime).getTime() : void 0;
|
|
464
631
|
if (opts.startTime && isNaN(startTime)) {
|
|
@@ -543,7 +710,7 @@ function registerDiggerCommand(program) {
|
|
|
543
710
|
}
|
|
544
711
|
const desc = selectedApp.appDesc ? ` (${selectedApp.appDesc})` : "";
|
|
545
712
|
console.log(`\u2705 Using app: ${selectedApp.appName}${desc}`);
|
|
546
|
-
const logAppName = selectedApp.appName
|
|
713
|
+
const logAppName = selectedApp.appName;
|
|
547
714
|
const timeDesc = startTime || endTime ? ` from ${opts.startTime || "1h ago"} to ${opts.endTime || "now"}` : "";
|
|
548
715
|
console.log(`\u{1F50E} Searching logs for "${keyword}" in ${logAppName}${timeDesc}...`);
|
|
549
716
|
let result;
|
|
@@ -551,9 +718,22 @@ function registerDiggerCommand(program) {
|
|
|
551
718
|
result = await searchLogs(page, {
|
|
552
719
|
appName: logAppName,
|
|
553
720
|
keyword,
|
|
554
|
-
limit,
|
|
555
|
-
logLevel,
|
|
556
721
|
searchType,
|
|
722
|
+
exclude,
|
|
723
|
+
filePaths,
|
|
724
|
+
logLevel,
|
|
725
|
+
limit,
|
|
726
|
+
logSize,
|
|
727
|
+
station,
|
|
728
|
+
productName,
|
|
729
|
+
direction,
|
|
730
|
+
rentionPolicy,
|
|
731
|
+
dirEnabled,
|
|
732
|
+
showPlain,
|
|
733
|
+
searchId,
|
|
734
|
+
searchIndex,
|
|
735
|
+
searchEndTimeStr: searchEndTimeStr === void 0 ? null : searchEndTimeStr,
|
|
736
|
+
coefficient: coefficient === void 0 ? null : coefficient,
|
|
557
737
|
startTime,
|
|
558
738
|
endTime
|
|
559
739
|
});
|
|
@@ -582,16 +762,1258 @@ function registerDiggerCommand(program) {
|
|
|
582
762
|
\u{1F4C4} ${result.entries.length} log entry(s) shown (total: ${result.total ?? result.entries.length})`);
|
|
583
763
|
}, { targetUrl: "https://joywatch.jd.com/digger/techApp/overview" });
|
|
584
764
|
});
|
|
765
|
+
digger.command("realtime").description("\u62C9\u53D6 Digger \u5B9E\u65F6\u65E5\u5FD7\uFF08\u6D41\u5F0F\u8F93\u51FA\uFF09").addHelpText("after", `
|
|
766
|
+
\u4F7F\u7528\u793A\u4F8B\uFF1A
|
|
767
|
+
# \u6D41\u5F0F\u62C9\u53D6\u5B9E\u65F6\u65E5\u5FD7\uFF08Ctrl+C \u505C\u6B62\uFF09
|
|
768
|
+
yue digger realtime --appName baoxian-bridgehead \\
|
|
769
|
+
--ip 100.99.232.222 \\
|
|
770
|
+
--file /export/log/jdos_kj_baoxian-bridgehead/catalina.out
|
|
771
|
+
|
|
772
|
+
# \u6307\u5B9A\u6700\u5927\u884C\u6570
|
|
773
|
+
yue digger realtime --appName baoxian-bridgehead \\
|
|
774
|
+
--ip 100.99.232.222 \\
|
|
775
|
+
--file /export/log/jdos_kj_baoxian-bridgehead/catalina.out \\
|
|
776
|
+
--maxLines 200
|
|
777
|
+
|
|
778
|
+
# JSON \u8F93\u51FA\uFF08\u4E00\u6B21\u6027\u83B7\u53D6\uFF09
|
|
779
|
+
yue digger realtime --appName baoxian-bridgehead \\
|
|
780
|
+
--ip 100.99.232.222 \\
|
|
781
|
+
--file /export/log/jdos_kj_baoxian-bridgehead/catalina.out \\
|
|
782
|
+
--output json
|
|
783
|
+
`).option("--appName <name>", "\u5E94\u7528\u540D\u79F0\uFF08\u4F8B\u5982\uFF1Abaoxian-bridgehead\uFF09").option("--ip <ip>", "\u5B9E\u4F8B IP\uFF08\u4F8B\u5982\uFF1A100.99.232.222\uFF09").option("--file <path>", "\u65E5\u5FD7\u6587\u4EF6\u8DEF\u5F84\uFF08\u4F8B\u5982\uFF1A/export/log/.../catalina.out\uFF09").option("--fileSizeByte <n>", "\u6587\u4EF6\u5927\u5C0F\uFF08fileSizeByte\uFF0C\u900F\u4F20\uFF09", (v) => parseInt(v, 10)).option("--maxLines <n>", "\u6700\u5927\u884C\u6570\uFF08maxLines\uFF0C\u9ED8\u8BA4\uFF1A100\uFF09", (v) => parseInt(v, 10), 100).option("--showPlain <bool>", "\u662F\u5426 plain \u8F93\u51FA\uFF08showPlain\uFF0C\u9ED8\u8BA4\uFF1Afalse\uFF09", "false").option("--productName <name>", "\u4EA7\u54C1\u540D\uFF08productName\uFF0C\u9ED8\u8BA4\uFF1Aapp\uFF09", "app").option("--source <name>", "\u6765\u6E90\uFF08source\uFF0C\u9ED8\u8BA4\uFF1Ajdos_kj\uFF09", "jdos_kj").option("--resourceSection <name>", "\u8D44\u6E90\u533A\uFF08resourceSection\uFF0C\u9ED8\u8BA4\uFF1AJDT\uFF09", "JDT").option("--output <format>", "\u8F93\u51FA\u683C\u5F0F\uFF1Aplain\uFF08\u9ED8\u8BA4\uFF09/ json", "plain").action(async (opts) => {
|
|
784
|
+
const format = (opts.output ?? "plain").toLowerCase();
|
|
785
|
+
const appName = opts.appName;
|
|
786
|
+
const ip = opts.ip;
|
|
787
|
+
const file = opts.file;
|
|
788
|
+
if (!appName || !ip || !file) {
|
|
789
|
+
console.error("\u274C \u53C2\u6570\u4E0D\u8DB3\uFF1A\u5FC5\u987B\u63D0\u4F9B --appName\u3001--ip\u3001--file");
|
|
790
|
+
process.exit(1);
|
|
791
|
+
}
|
|
792
|
+
const fileSizeByte = opts.fileSizeByte === void 0 || Number.isNaN(opts.fileSizeByte) ? void 0 : Number(opts.fileSizeByte);
|
|
793
|
+
const maxLines = opts.maxLines === void 0 || Number.isNaN(opts.maxLines) ? 100 : Number(opts.maxLines);
|
|
794
|
+
const showPlain = String(opts.showPlain ?? "false").toLowerCase() === "true";
|
|
795
|
+
const productName = opts.productName ?? "app";
|
|
796
|
+
const source = opts.source ?? "jdos_kj";
|
|
797
|
+
const resourceSection = opts.resourceSection ?? "JDT";
|
|
798
|
+
await withBrowserAutoDisconnect(async (page, _onDisconnect, signal) => {
|
|
799
|
+
try {
|
|
800
|
+
await page.waitForNetworkIdle?.();
|
|
801
|
+
} catch {
|
|
802
|
+
}
|
|
803
|
+
if (format === "json") {
|
|
804
|
+
const r = await realtimeLogs(page, {
|
|
805
|
+
appName,
|
|
806
|
+
ip,
|
|
807
|
+
file,
|
|
808
|
+
fileSizeByte,
|
|
809
|
+
maxLines,
|
|
810
|
+
showPlain,
|
|
811
|
+
productName,
|
|
812
|
+
source,
|
|
813
|
+
resourceSection
|
|
814
|
+
});
|
|
815
|
+
console.log(JSON.stringify(r ?? null, null, 2));
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
console.log(`\u{1F534} Realtime logs: ${appName} ${ip} ${file}`);
|
|
819
|
+
console.log(`${DIM}\u6309 Ctrl+C \u7ED3\u675F\uFF08\u6216\u5173\u95ED\u6D4F\u89C8\u5668 tab \u81EA\u52A8\u505C\u6B62\uFF09${RESET}`);
|
|
820
|
+
try {
|
|
821
|
+
await realtimeLogs(
|
|
822
|
+
page,
|
|
823
|
+
{
|
|
824
|
+
appName,
|
|
825
|
+
ip,
|
|
826
|
+
file,
|
|
827
|
+
fileSizeByte,
|
|
828
|
+
maxLines,
|
|
829
|
+
showPlain,
|
|
830
|
+
productName,
|
|
831
|
+
source,
|
|
832
|
+
resourceSection
|
|
833
|
+
},
|
|
834
|
+
signal,
|
|
835
|
+
(chunk) => {
|
|
836
|
+
if (chunk.startsWith("__meta__:")) {
|
|
837
|
+
try {
|
|
838
|
+
const meta = JSON.parse(chunk.slice("__meta__:".length));
|
|
839
|
+
console.log(`${GRAY}HTTP ${meta.status} ${meta.contentType}${RESET}`);
|
|
840
|
+
} catch {
|
|
841
|
+
console.log(`${GRAY}${chunk}${RESET}`);
|
|
842
|
+
}
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
process.stdout.write(chunk);
|
|
846
|
+
if (!chunk.endsWith("\n")) process.stdout.write("\n");
|
|
847
|
+
}
|
|
848
|
+
);
|
|
849
|
+
} catch (err) {
|
|
850
|
+
if (signal.aborted) {
|
|
851
|
+
console.log(`
|
|
852
|
+
${GRAY}\u23F9 \u6D4F\u89C8\u5668 tab \u5DF2\u5173\u95ED/\u8FDE\u63A5\u65AD\u5F00\uFF0C\u5DF2\u505C\u6B62\u62C9\u53D6\u3002${RESET}`);
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
throw err;
|
|
856
|
+
}
|
|
857
|
+
}, { targetUrl: "https://joywatch.jd.com/digger/techApp/overview" });
|
|
858
|
+
});
|
|
859
|
+
digger.command("app-ips").description("\u67E5\u8BE2\u5E94\u7528\u5B9E\u4F8B IP \u5217\u8868\u53CA\u5206\u7EC4\u4FE1\u606F\uFF08\u65E7\u7248\uFF0C\u63A8\u8350\u4F7F\u7528 ips\uFF09").addHelpText("after", `
|
|
860
|
+
\u4F7F\u7528\u793A\u4F8B\uFF1A
|
|
861
|
+
# \u67E5\u8BE2\u5B9E\u4F8B IP\uFF08\u9ED8\u8BA4\u6700\u8FD11\u5C0F\u65F6\uFF09
|
|
862
|
+
yue digger app-ips --appName baoxian-bridgehead
|
|
863
|
+
|
|
864
|
+
# \u6307\u5B9A\u4EA7\u54C1\u540D
|
|
865
|
+
yue digger app-ips --appName baoxian-bridgehead --productName _jdosApp_
|
|
866
|
+
|
|
867
|
+
# \u6307\u5B9A\u65F6\u95F4\u8303\u56F4\uFF08\u6BEB\u79D2\u65F6\u95F4\u6233\uFF09
|
|
868
|
+
yue digger app-ips --appName baoxian-bridgehead --start 1782891564642 --end 1782895164642
|
|
869
|
+
|
|
870
|
+
# JSON \u8F93\u51FA
|
|
871
|
+
yue digger app-ips --appName baoxian-bridgehead --output json
|
|
872
|
+
`).option("--appName <name>", "\u5E94\u7528\u540D\u79F0\uFF08\u5BF9\u5E94 instanceName\uFF0C\u4F8B\u5982\uFF1Abaoxian-bridgehead\uFF09").option("--productName <name>", "\u4EA7\u54C1\u540D\uFF08\u9ED8\u8BA4\uFF1A_jdosApp_\uFF09", "_jdosApp_").option("--start <ms>", "\u5F00\u59CB\u65F6\u95F4\uFF08\u6BEB\u79D2\u65F6\u95F4\u6233\uFF1B\u9ED8\u8BA4\uFF1A\u5F53\u524D\u65F6\u95F4-1\u5C0F\u65F6\uFF09", (v) => parseInt(v, 10)).option("--end <ms>", "\u7ED3\u675F\u65F6\u95F4\uFF08\u6BEB\u79D2\u65F6\u95F4\u6233\uFF1B\u9ED8\u8BA4\uFF1A\u5F53\u524D\u65F6\u95F4\uFF09", (v) => parseInt(v, 10)).option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable\uFF08\u9ED8\u8BA4\uFF09/ json", "table").action(async (opts) => {
|
|
873
|
+
const appName = opts.appName;
|
|
874
|
+
const productName = opts.productName ?? "_jdosApp_";
|
|
875
|
+
const output = (opts.output ?? "table").toLowerCase();
|
|
876
|
+
if (!appName) {
|
|
877
|
+
console.error("\u274C \u53C2\u6570\u4E0D\u8DB3\uFF1A\u5FC5\u987B\u63D0\u4F9B --appName");
|
|
878
|
+
process.exit(1);
|
|
879
|
+
}
|
|
880
|
+
const now = Date.now();
|
|
881
|
+
const start = Number.isFinite(opts.start) ? Number(opts.start) : now - 60 * 60 * 1e3;
|
|
882
|
+
const end = Number.isFinite(opts.end) ? Number(opts.end) : now;
|
|
883
|
+
await withBrowser(async (page) => {
|
|
884
|
+
try {
|
|
885
|
+
await page.waitForNetworkIdle?.();
|
|
886
|
+
} catch {
|
|
887
|
+
}
|
|
888
|
+
let data;
|
|
889
|
+
try {
|
|
890
|
+
data = await listAppIps(page, {
|
|
891
|
+
productName,
|
|
892
|
+
instanceName: appName,
|
|
893
|
+
start,
|
|
894
|
+
end
|
|
895
|
+
});
|
|
896
|
+
} catch (err) {
|
|
897
|
+
console.error(`\u274C \u67E5\u8BE2\u5931\u8D25: ${err.message}`);
|
|
898
|
+
process.exit(1);
|
|
899
|
+
}
|
|
900
|
+
if (output === "json") {
|
|
901
|
+
console.log(JSON.stringify(data, null, 2));
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
const list = Array.isArray(data) ? data : data?.data ?? data?.result ?? data?.list ?? [];
|
|
905
|
+
if (!Array.isArray(list) || list.length === 0) {
|
|
906
|
+
console.log("\u{1F4ED} \u672A\u67E5\u8BE2\u5230\u5B9E\u4F8B IP\u3002");
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
909
|
+
const table = new Table3({
|
|
910
|
+
head: ["ip", "group", "instanceName", "productName"],
|
|
911
|
+
style: { head: ["cyan"], border: ["gray"] },
|
|
912
|
+
wordWrap: true,
|
|
913
|
+
colWidths: [18, 24, 28, 16]
|
|
914
|
+
});
|
|
915
|
+
for (const item of list) {
|
|
916
|
+
const ip = item.ip ?? item.host ?? item.instanceIp ?? item.instanceIP ?? item.ipAddr ?? item.ipAddress ?? item.privateIp ?? item.privateIP ?? item.address ?? item.addr ?? item.nodeIp ?? item.nodeIP ?? item.podIp ?? item.podIP ?? item.machineIp ?? item.machineIP ?? "-";
|
|
917
|
+
table.push([
|
|
918
|
+
ip,
|
|
919
|
+
item.group ?? item.groupName ?? item.section ?? item.resourceSection ?? "-",
|
|
920
|
+
item.instanceName ?? item.appName ?? appName,
|
|
921
|
+
item.productName ?? productName
|
|
922
|
+
]);
|
|
923
|
+
}
|
|
924
|
+
console.log(table.toString());
|
|
925
|
+
console.log(`
|
|
926
|
+
\u{1F4CB} \u5171 ${list.length} \u6761\u8BB0\u5F55\uFF08${new Date(start).toLocaleString("zh-CN", { hour12: false })} ~ ${new Date(end).toLocaleString("zh-CN", { hour12: false })}\uFF09`);
|
|
927
|
+
}, { targetUrl: "https://joywatch.jd.com/digger/techApp/overview" });
|
|
928
|
+
});
|
|
929
|
+
digger.command("local").description("\u67E5\u8BE2 Digger \u672C\u5730\u65E5\u5FD7\uFF08grep \u672C\u5730\u6587\u4EF6\uFF09").addHelpText("after", `
|
|
930
|
+
\u4F7F\u7528\u793A\u4F8B\uFF1A
|
|
931
|
+
# \u57FA\u672C\u641C\u7D22\uFF08\u81EA\u52A8\u68C0\u6D4B\u4E3B\u65E5\u5FD7\u6587\u4EF6\uFF09
|
|
932
|
+
yue digger local --appName baoxian-bridgehead-zx --grep error
|
|
933
|
+
|
|
934
|
+
# \u6307\u5B9A\u65E5\u5FD7\u6587\u4EF6
|
|
935
|
+
yue digger local --appName baoxian-bridgehead-zx \\
|
|
936
|
+
--file /export/log/baoxian-bridgehead-zx/catalina.out \\
|
|
937
|
+
--grep error
|
|
938
|
+
|
|
939
|
+
# \u6392\u9664\u5173\u952E\u5B57\uFF08\u9017\u53F7\u5206\u9694\uFF09
|
|
940
|
+
yue digger local --appName baoxian-bridgehead-zx --grep Exception --grep-v "pfinder,sgm"
|
|
941
|
+
|
|
942
|
+
# \u589E\u5927\u5339\u914D\u884C\u6570 + JSON \u8F93\u51FA
|
|
943
|
+
yue digger local --appName baoxian-bridgehead-zx --grep error --maxMatchRow 100 --output json
|
|
944
|
+
|
|
945
|
+
# \u53EA\u67E5\u7279\u5B9A IP
|
|
946
|
+
yue digger local --appName baoxian-bridgehead-zx --grep error --ip 100.99.57.237
|
|
947
|
+
`).option("--appName <name>", "\u5E94\u7528\u540D\u79F0\uFF08\u4F8B\u5982\uFF1Abaoxian-bridgehead-zx\uFF09").option("--file <path>", "\u65E5\u5FD7\u6587\u4EF6\u8DEF\u5F84\uFF08\u4F8B\u5982\uFF1A/export/log/baoxian-bridgehead-zx/catalina.out\uFF09\uFF1B\u4E0D\u6307\u5B9A\u65F6\u81EA\u52A8\u9009\u62E9\u4E3B\u65E5\u5FD7\u6587\u4EF6").option("--grep <keyword>", "grep \u5173\u952E\u8BCD\uFF08\u5927\u4E8E3\u4E2A\u5B57\u7B26\uFF09").option("--grep-v <keywords>", "grep -v \u6392\u9664\u5173\u952E\u8BCD\uFF08\u9017\u53F7\u5206\u9694\uFF09").option("--maxMatchRow <n>", "\u6700\u5927\u5339\u914D\u884C\u6570\uFF08\u9ED8\u8BA4\uFF1A50\uFF09", (v) => parseInt(v, 10), 50).option("--lineOffsetBefore <n>", "\u5339\u914D\u884C\u524D\u504F\u79FB\u884C\u6570\uFF08\u9ED8\u8BA4\uFF1A0\uFF09", (v) => parseInt(v, 10), 0).option("--lineOffsetAfter <n>", "\u5339\u914D\u884C\u540E\u504F\u79FB\u884C\u6570\uFF08\u9ED8\u8BA4\uFF1A0\uFF09", (v) => parseInt(v, 10), 0).option("--searchScope <scope>", "\u641C\u7D22\u8303\u56F4\uFF08\u9ED8\u8BA4\uFF1A100M\uFF09", "100M").option("--showPlain <bool>", "\u662F\u5426 plain \u8F93\u51FA\uFF08\u9ED8\u8BA4\uFF1Afalse\uFF09", "false").option("--ip <ip>", "\u6307\u5B9A IP \u67E5\u8BE2\uFF08\u4E0D\u6307\u5B9A\u5219\u67E5\u8BE2\u6240\u6709\u4E3B\u673A\uFF09").option("--output <format>", "\u8F93\u51FA\u683C\u5F0F\uFF1Aplain\uFF08\u9ED8\u8BA4\uFF09/ json", "plain").action(async (opts) => {
|
|
948
|
+
const appName = opts.appName;
|
|
949
|
+
const grep = opts.grep;
|
|
950
|
+
const format = (opts.output ?? "plain").toLowerCase();
|
|
951
|
+
if (!appName) {
|
|
952
|
+
console.error("\u274C \u53C2\u6570\u4E0D\u8DB3\uFF1A\u5FC5\u987B\u63D0\u4F9B --appName");
|
|
953
|
+
process.exit(1);
|
|
954
|
+
}
|
|
955
|
+
if (!grep) {
|
|
956
|
+
console.error("\u274C \u53C2\u6570\u4E0D\u8DB3\uFF1A\u5FC5\u987B\u63D0\u4F9B --grep\uFF08grep \u5173\u952E\u8BCD\uFF09");
|
|
957
|
+
process.exit(1);
|
|
958
|
+
}
|
|
959
|
+
if (grep.length < 3) {
|
|
960
|
+
console.error("\u274C --grep \u5173\u952E\u8BCD\u957F\u5EA6\u5FC5\u987B\u5927\u4E8E3\u4E2A\u5B57\u7B26");
|
|
961
|
+
process.exit(1);
|
|
962
|
+
}
|
|
963
|
+
const file = opts.file;
|
|
964
|
+
const grepV = opts.grepV ?? "";
|
|
965
|
+
const maxMatchRow = opts.maxMatchRow ?? 50;
|
|
966
|
+
const lineOffsetBefore = opts.lineOffsetBefore ?? 0;
|
|
967
|
+
const lineOffsetAfter = opts.lineOffsetAfter ?? 0;
|
|
968
|
+
const searchScope = opts.searchScope ?? "100M";
|
|
969
|
+
const showPlain = String(opts.showPlain ?? "false").toLowerCase() === "true";
|
|
970
|
+
const selectIp = opts.ip ?? "";
|
|
971
|
+
await withBrowser(async (page) => {
|
|
972
|
+
try {
|
|
973
|
+
await page.waitForNetworkIdle?.();
|
|
974
|
+
} catch {
|
|
975
|
+
}
|
|
976
|
+
let logFile = file;
|
|
977
|
+
if (!logFile) {
|
|
978
|
+
console.log(`\u{1F4C2} \u672A\u6307\u5B9A\u65E5\u5FD7\u6587\u4EF6\uFF0C\u6B63\u5728\u83B7\u53D6\u6587\u4EF6\u5217\u8868...`);
|
|
979
|
+
let files;
|
|
980
|
+
try {
|
|
981
|
+
files = await listAppFiles(page, appName, false);
|
|
982
|
+
} catch (err) {
|
|
983
|
+
console.error(`\u274C \u83B7\u53D6\u6587\u4EF6\u5217\u8868\u5931\u8D25: ${err.message}`);
|
|
984
|
+
process.exit(1);
|
|
985
|
+
}
|
|
986
|
+
const mainFile = files.find((f) => f.endsWith("/catalina.out") || f.endsWith(".out"));
|
|
987
|
+
logFile = mainFile ?? files[0];
|
|
988
|
+
if (!logFile) {
|
|
989
|
+
console.error("\u274C \u672A\u627E\u5230\u53EF\u7528\u7684\u65E5\u5FD7\u6587\u4EF6\uFF0C\u8BF7\u4F7F\u7528 --file \u624B\u52A8\u6307\u5B9A\u3002");
|
|
990
|
+
process.exit(1);
|
|
991
|
+
}
|
|
992
|
+
console.log(`\u{1F4C2} \u81EA\u52A8\u9009\u62E9\u65E5\u5FD7\u6587\u4EF6: ${logFile}`);
|
|
993
|
+
}
|
|
994
|
+
console.log(`\u{1F50E} \u672C\u5730\u641C\u7D22: ${appName} ${logFile} grep="${grep}"`);
|
|
995
|
+
let result;
|
|
996
|
+
try {
|
|
997
|
+
result = await localLogSearch(page, {
|
|
998
|
+
appName,
|
|
999
|
+
file: logFile,
|
|
1000
|
+
grep,
|
|
1001
|
+
grepV,
|
|
1002
|
+
maxMatchRow,
|
|
1003
|
+
lineOffsetBefore,
|
|
1004
|
+
lineOffsetAfter,
|
|
1005
|
+
grepDirection: true,
|
|
1006
|
+
searchScope,
|
|
1007
|
+
showPlain,
|
|
1008
|
+
selectIp
|
|
1009
|
+
});
|
|
1010
|
+
} catch (err) {
|
|
1011
|
+
console.error(`\u274C \u672C\u5730\u65E5\u5FD7\u641C\u7D22\u5931\u8D25: ${err.message}`);
|
|
1012
|
+
process.exit(1);
|
|
1013
|
+
}
|
|
1014
|
+
const { entries, ip: bestIp, taskResult } = result;
|
|
1015
|
+
if (format !== "json") {
|
|
1016
|
+
const ipSummary = Object.entries(taskResult).map(([ip, entries2]) => {
|
|
1017
|
+
const e = Array.isArray(entries2) ? entries2[0] : entries2;
|
|
1018
|
+
const count = e?.logCount ?? 0;
|
|
1019
|
+
const ok = e?.success ? "\u2705" : "\u274C";
|
|
1020
|
+
return ` ${ok} ${ip}: ${count} \u6761`;
|
|
1021
|
+
}).join("\n");
|
|
1022
|
+
console.log(`
|
|
1023
|
+
\u{1F4CA} \u5404\u4E3B\u673A\u7ED3\u679C:
|
|
1024
|
+
${ipSummary}`);
|
|
1025
|
+
if (bestIp) {
|
|
1026
|
+
console.log(`
|
|
1027
|
+
\u{1F4C4} \u663E\u793A ${bestIp} \u7684\u65E5\u5FD7\u5185\u5BB9:`);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
if (!entries || entries.length === 0) {
|
|
1031
|
+
console.log("\u{1F4ED} \u672A\u627E\u5230\u5339\u914D\u7684\u65E5\u5FD7\u5185\u5BB9\u3002");
|
|
1032
|
+
return;
|
|
1033
|
+
}
|
|
1034
|
+
if (format === "json") {
|
|
1035
|
+
console.log(JSON.stringify(entries, null, 2));
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
for (let i = 0; i < entries.length; i++) {
|
|
1039
|
+
const entry = entries[i];
|
|
1040
|
+
const content = entry.content ?? "";
|
|
1041
|
+
const levelMatch = content.match(/\b(ERROR|WARN|INFO|DEBUG|FATAL)\b/);
|
|
1042
|
+
const level = levelMatch ? colorizeLevel(levelMatch[1]) : "";
|
|
1043
|
+
console.log("");
|
|
1044
|
+
console.log(`${DIM}[${i + 1}]${RESET} ${level}`);
|
|
1045
|
+
console.log(content);
|
|
1046
|
+
}
|
|
1047
|
+
console.log(`
|
|
1048
|
+
\u{1F4C4} ${entries.length} \u6761\u5339\u914D\u7ED3\u679C`);
|
|
1049
|
+
}, { targetUrl: "https://joywatch.jd.com/digger/techApp/overview" });
|
|
1050
|
+
});
|
|
1051
|
+
digger.command("files").description("\u67E5\u8BE2\u5E94\u7528\u53EF\u7528\u7684\u65E5\u5FD7\u6587\u4EF6\u5217\u8868").addHelpText("after", `
|
|
1052
|
+
\u4F7F\u7528\u793A\u4F8B\uFF1A
|
|
1053
|
+
# \u5217\u51FA\u4E3B\u65E5\u5FD7\u6587\u4EF6
|
|
1054
|
+
yue digger files --appName baoxian-bridgehead-zx
|
|
1055
|
+
|
|
1056
|
+
# \u5305\u542B\u6240\u6709\u6587\u4EF6\uFF08\u542B\u5386\u53F2\u5F52\u6863\uFF09
|
|
1057
|
+
yue digger files --appName baoxian-bridgehead-zx --containAll
|
|
1058
|
+
|
|
1059
|
+
# JSON \u8F93\u51FA
|
|
1060
|
+
yue digger files --appName baoxian-bridgehead-zx --output json
|
|
1061
|
+
`).option("--appName <name>", "\u5E94\u7528\u540D\u79F0").option("--containAll", "\u662F\u5426\u5305\u542B\u6240\u6709\u6587\u4EF6\uFF08\u542B\u5386\u53F2\u5F52\u6863\uFF09\uFF0C\u9ED8\u8BA4\u53EA\u8FD4\u56DE\u4E3B\u65E5\u5FD7\u6587\u4EF6", false).option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Alist\uFF08\u9ED8\u8BA4\uFF09/ json", "list").action(async (opts) => {
|
|
1062
|
+
const appName = opts.appName;
|
|
1063
|
+
const containAll = !!opts.containAll;
|
|
1064
|
+
const output = (opts.output ?? "list").toLowerCase();
|
|
1065
|
+
if (!appName) {
|
|
1066
|
+
console.error("\u274C \u53C2\u6570\u4E0D\u8DB3\uFF1A\u5FC5\u987B\u63D0\u4F9B --appName");
|
|
1067
|
+
process.exit(1);
|
|
1068
|
+
}
|
|
1069
|
+
await withBrowser(async (page) => {
|
|
1070
|
+
try {
|
|
1071
|
+
await page.waitForNetworkIdle?.();
|
|
1072
|
+
} catch {
|
|
1073
|
+
}
|
|
1074
|
+
let files;
|
|
1075
|
+
try {
|
|
1076
|
+
files = await listAppFiles(page, appName, containAll);
|
|
1077
|
+
} catch (err) {
|
|
1078
|
+
console.error(`\u274C \u67E5\u8BE2\u5931\u8D25: ${err.message}`);
|
|
1079
|
+
process.exit(1);
|
|
1080
|
+
}
|
|
1081
|
+
if (output === "json") {
|
|
1082
|
+
console.log(JSON.stringify(files, null, 2));
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
if (!files || files.length === 0) {
|
|
1086
|
+
console.log("\u{1F4ED} \u672A\u627E\u5230\u53EF\u7528\u7684\u65E5\u5FD7\u6587\u4EF6\u3002");
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
1090
|
+
for (const f of files) {
|
|
1091
|
+
const lastSlash = f.lastIndexOf("/");
|
|
1092
|
+
const dir = f.substring(0, lastSlash) || "/";
|
|
1093
|
+
const name = f.substring(lastSlash + 1);
|
|
1094
|
+
if (!grouped.has(dir)) grouped.set(dir, []);
|
|
1095
|
+
grouped.get(dir).push(name);
|
|
1096
|
+
}
|
|
1097
|
+
for (const [dir, names] of grouped) {
|
|
1098
|
+
console.log(`
|
|
1099
|
+
${CYAN}${dir}/${RESET}`);
|
|
1100
|
+
for (const name of names) {
|
|
1101
|
+
console.log(` ${name}`);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
console.log(`
|
|
1105
|
+
\u{1F4CB} \u5171 ${files.length} \u4E2A\u6587\u4EF6`);
|
|
1106
|
+
}, { targetUrl: "https://joywatch.jd.com/digger/techApp/overview" });
|
|
1107
|
+
});
|
|
1108
|
+
digger.command("ips").description("\u67E5\u8BE2\u5E94\u7528\u5B9E\u4F8B IP \u5217\u8868\uFF08\u542B Pod \u540D\u3001\u5206\u7EC4\uFF09").addHelpText("after", `
|
|
1109
|
+
\u4F7F\u7528\u793A\u4F8B\uFF1A
|
|
1110
|
+
# \u67E5\u8BE2\u5B9E\u4F8B IP\uFF08\u542B Pod \u540D\u548C\u5206\u7EC4\uFF09
|
|
1111
|
+
yue digger ips --appName baoxian-bridgehead-zx
|
|
1112
|
+
|
|
1113
|
+
# JSON \u8F93\u51FA
|
|
1114
|
+
yue digger ips --appName baoxian-bridgehead-zx --output json
|
|
1115
|
+
`).option("--appName <name>", "\u5E94\u7528\u540D\u79F0").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable\uFF08\u9ED8\u8BA4\uFF09/ json", "table").action(async (opts) => {
|
|
1116
|
+
const appName = opts.appName;
|
|
1117
|
+
const output = (opts.output ?? "table").toLowerCase();
|
|
1118
|
+
if (!appName) {
|
|
1119
|
+
console.error("\u274C \u53C2\u6570\u4E0D\u8DB3\uFF1A\u5FC5\u987B\u63D0\u4F9B --appName");
|
|
1120
|
+
process.exit(1);
|
|
1121
|
+
}
|
|
1122
|
+
await withBrowser(async (page) => {
|
|
1123
|
+
try {
|
|
1124
|
+
await page.waitForNetworkIdle?.();
|
|
1125
|
+
} catch {
|
|
1126
|
+
}
|
|
1127
|
+
let ips;
|
|
1128
|
+
try {
|
|
1129
|
+
ips = await listAppIpsV2(page, appName);
|
|
1130
|
+
} catch (err) {
|
|
1131
|
+
console.error(`\u274C \u67E5\u8BE2\u5931\u8D25: ${err.message}`);
|
|
1132
|
+
process.exit(1);
|
|
1133
|
+
}
|
|
1134
|
+
if (output === "json") {
|
|
1135
|
+
console.log(JSON.stringify(ips, null, 2));
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
if (!ips || ips.length === 0) {
|
|
1139
|
+
console.log("\u{1F4ED} \u672A\u67E5\u8BE2\u5230\u5B9E\u4F8B IP\u3002");
|
|
1140
|
+
return;
|
|
1141
|
+
}
|
|
1142
|
+
const table = new Table3({
|
|
1143
|
+
head: ["ip", "podName", "group", "type"],
|
|
1144
|
+
style: { head: ["cyan"], border: ["gray"] },
|
|
1145
|
+
wordWrap: true,
|
|
1146
|
+
colWidths: [18, 36, 16, 8]
|
|
1147
|
+
});
|
|
1148
|
+
for (const ip of ips) {
|
|
1149
|
+
table.push([ip.ip, ip.podName, ip.groupName, ip.type]);
|
|
1150
|
+
}
|
|
1151
|
+
console.log(table.toString());
|
|
1152
|
+
console.log(`
|
|
1153
|
+
\u{1F4CB} \u5171 ${ips.length} \u4E2A\u5B9E\u4F8B`);
|
|
1154
|
+
}, { targetUrl: "https://joywatch.jd.com/digger/techApp/overview" });
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
// src/commands/jmq.ts
|
|
1159
|
+
import Table4 from "cli-table3";
|
|
1160
|
+
|
|
1161
|
+
// src/lib/jmq-api.ts
|
|
1162
|
+
var SITE_BASE_URL = {
|
|
1163
|
+
cn: "https://taishan.jd.com",
|
|
1164
|
+
test: "http://test.taishan.jd.com",
|
|
1165
|
+
th: "http://th.taishan.jd.com",
|
|
1166
|
+
hl: "http://hl.taishan.jd.com",
|
|
1167
|
+
intl: "http://joybuy.taishan.jd.com",
|
|
1168
|
+
"intl-test": "http://test-intl.taishan.jd.com"
|
|
1169
|
+
};
|
|
1170
|
+
var ENV_TO_SITE = {
|
|
1171
|
+
prod: "cn",
|
|
1172
|
+
test: "test",
|
|
1173
|
+
th: "th",
|
|
1174
|
+
hl: "hl",
|
|
1175
|
+
intl: "intl",
|
|
1176
|
+
"intl-test": "intl-test"
|
|
1177
|
+
};
|
|
1178
|
+
var ENV_JMQ_HEADER = {
|
|
1179
|
+
prod: "prod",
|
|
1180
|
+
test: "prod",
|
|
1181
|
+
th: "prod",
|
|
1182
|
+
hl: "prod",
|
|
1183
|
+
intl: "prod",
|
|
1184
|
+
"intl-test": "prod"
|
|
1185
|
+
};
|
|
1186
|
+
var ENV_LABEL = {
|
|
1187
|
+
prod: "\u4E2D\u56FD\u7AD9-\u751F\u4EA7",
|
|
1188
|
+
test: "\u6D4B\u8BD5\u7AD9",
|
|
1189
|
+
th: "\u65B0\u52A0\u5761-\u751F\u4EA7",
|
|
1190
|
+
hl: "\u8377\u5170\u7AD9-\u751F\u4EA7",
|
|
1191
|
+
intl: "\u56FD\u9645\u7AD9-\u751F\u4EA7",
|
|
1192
|
+
"intl-test": "\u56FD\u9645\u6D4B\u8BD5\u7AD9"
|
|
1193
|
+
};
|
|
1194
|
+
function envJmqHeader(env) {
|
|
1195
|
+
return ENV_JMQ_HEADER[env];
|
|
1196
|
+
}
|
|
1197
|
+
function envLabel(env) {
|
|
1198
|
+
return ENV_LABEL[env];
|
|
1199
|
+
}
|
|
1200
|
+
function getEnvBaseUrl(env) {
|
|
1201
|
+
return SITE_BASE_URL[ENV_TO_SITE[env]];
|
|
1202
|
+
}
|
|
1203
|
+
function taishanXhr(page, method, url, body, env) {
|
|
1204
|
+
const jmqEnvHeader = envJmqHeader(env);
|
|
1205
|
+
return page.evaluate(
|
|
1206
|
+
(args) => {
|
|
1207
|
+
return new Promise((resolve) => {
|
|
1208
|
+
const xhr = new XMLHttpRequest();
|
|
1209
|
+
xhr.open(args.method, args.url, true);
|
|
1210
|
+
xhr.withCredentials = true;
|
|
1211
|
+
xhr.setRequestHeader("Accept", "application/json, text/plain, */*");
|
|
1212
|
+
xhr.setRequestHeader("Content-Type", "application/json");
|
|
1213
|
+
xhr.setRequestHeader("jmq_env", args.jmqEnv);
|
|
1214
|
+
xhr.setRequestHeader(
|
|
1215
|
+
"x-proxy-opts",
|
|
1216
|
+
'{"target":"http://origin.jmq.jd.com","pathRewrite":{"^/api/jmqApi":"/"}}'
|
|
1217
|
+
);
|
|
1218
|
+
xhr.onload = () => {
|
|
1219
|
+
try {
|
|
1220
|
+
resolve({
|
|
1221
|
+
ok: xhr.status >= 200 && xhr.status < 300,
|
|
1222
|
+
status: xhr.status,
|
|
1223
|
+
body: JSON.parse(xhr.responseText)
|
|
1224
|
+
});
|
|
1225
|
+
} catch {
|
|
1226
|
+
resolve({
|
|
1227
|
+
ok: xhr.status >= 200 && xhr.status < 300,
|
|
1228
|
+
status: xhr.status,
|
|
1229
|
+
body: xhr.responseText
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
};
|
|
1233
|
+
xhr.onerror = () => resolve({ ok: false, status: 0, body: "Network error" });
|
|
1234
|
+
xhr.send(args.body || null);
|
|
1235
|
+
});
|
|
1236
|
+
},
|
|
1237
|
+
{ method, url, body: body ? JSON.stringify(body) : void 0, jmqEnv: jmqEnvHeader }
|
|
1238
|
+
);
|
|
1239
|
+
}
|
|
1240
|
+
var MSG_TYPE_MAP = {
|
|
1241
|
+
0: "\u666E\u901A\u6D88\u606F",
|
|
1242
|
+
1: "\u987A\u5E8F\u6D88\u606F",
|
|
1243
|
+
2: "\u5EF6\u65F6\u6D88\u606F",
|
|
1244
|
+
3: "\u4E8B\u52A1\u6D88\u606F"
|
|
1245
|
+
};
|
|
1246
|
+
function msgTypeLabel(type) {
|
|
1247
|
+
return MSG_TYPE_MAP[type] ?? `\u7C7B\u578B${type}`;
|
|
1248
|
+
}
|
|
1249
|
+
async function searchGroups(page, keyword, env = "prod", pageNum, pageSize = 50) {
|
|
1250
|
+
const baseUrl = getEnvBaseUrl(env);
|
|
1251
|
+
const url = `${baseUrl}/api/jmqApi/v1/application/search`;
|
|
1252
|
+
const fetchAll = pageNum === void 0 || pageNum === null;
|
|
1253
|
+
const startPage = fetchAll ? 1 : pageNum;
|
|
1254
|
+
let allData = [];
|
|
1255
|
+
let pagination = { page: startPage, size: pageSize };
|
|
1256
|
+
let currentPage = startPage;
|
|
1257
|
+
let totalPages = 1;
|
|
1258
|
+
while (true) {
|
|
1259
|
+
const body = {
|
|
1260
|
+
pagination: { page: currentPage, size: pageSize },
|
|
1261
|
+
query: {
|
|
1262
|
+
keyword: keyword ?? "",
|
|
1263
|
+
fuzzy: 1,
|
|
1264
|
+
full: 0
|
|
1265
|
+
}
|
|
1266
|
+
};
|
|
1267
|
+
const result = await taishanXhr(page, "POST", url, body, env);
|
|
1268
|
+
if (!result.ok) {
|
|
1269
|
+
throw new Error(
|
|
1270
|
+
`JMQ group search error: HTTP ${result.status} \u2014 ${JSON.stringify(result.body)}`
|
|
1271
|
+
);
|
|
1272
|
+
}
|
|
1273
|
+
const json = result.body;
|
|
1274
|
+
const data = json.data ?? [];
|
|
1275
|
+
pagination = {
|
|
1276
|
+
page: json.pagination?.page ?? currentPage,
|
|
1277
|
+
size: json.pagination?.size ?? pageSize,
|
|
1278
|
+
totalRecord: json.pagination?.totalRecord ?? 0,
|
|
1279
|
+
pages: json.pagination?.pages
|
|
1280
|
+
};
|
|
1281
|
+
totalPages = pagination.pages ?? (Math.ceil((pagination.totalRecord ?? 0) / pageSize) || 1);
|
|
1282
|
+
allData = allData.concat(data);
|
|
1283
|
+
if (!fetchAll || currentPage >= totalPages) break;
|
|
1284
|
+
currentPage++;
|
|
1285
|
+
}
|
|
1286
|
+
const groups = allData.map((item) => ({
|
|
1287
|
+
id: item.id ?? 0,
|
|
1288
|
+
code: item.code ?? item.appId ?? "",
|
|
1289
|
+
name: item.name ?? item.description ?? "",
|
|
1290
|
+
env,
|
|
1291
|
+
department: item.department ?? item.dept ?? "",
|
|
1292
|
+
owner: typeof item.owner === "object" ? item.owner?.code ?? "" : item.owner ?? "",
|
|
1293
|
+
source: item.source != null ? String(item.source) : "",
|
|
1294
|
+
aliasCode: item.aliasCode ?? "",
|
|
1295
|
+
system: item.system ?? "",
|
|
1296
|
+
description: item.description ?? ""
|
|
1297
|
+
}));
|
|
1298
|
+
return { data: groups, pagination };
|
|
1299
|
+
}
|
|
1300
|
+
async function searchTopics(page, keyword, env = "prod", pageNum, pageSize = 50, personal = false) {
|
|
1301
|
+
const baseUrl = getEnvBaseUrl(env);
|
|
1302
|
+
const url = `${baseUrl}/api/jmqApi/v1/topicWiki/searchTopicWithWiki`;
|
|
1303
|
+
const fetchAll = pageNum === void 0 || pageNum === null;
|
|
1304
|
+
const startPage = fetchAll ? 1 : pageNum;
|
|
1305
|
+
let allData = [];
|
|
1306
|
+
let pagination = { page: startPage, size: pageSize };
|
|
1307
|
+
let currentPage = startPage;
|
|
1308
|
+
let totalPages = 1;
|
|
1309
|
+
while (true) {
|
|
1310
|
+
const body = {
|
|
1311
|
+
query: {
|
|
1312
|
+
type: "-1",
|
|
1313
|
+
keyword: keyword ?? "",
|
|
1314
|
+
fuzzy: 1,
|
|
1315
|
+
personal: personal ? 1 : 0
|
|
1316
|
+
},
|
|
1317
|
+
pagination: { page: currentPage, size: pageSize }
|
|
1318
|
+
};
|
|
1319
|
+
const result = await taishanXhr(page, "POST", url, body, env);
|
|
1320
|
+
if (!result.ok) {
|
|
1321
|
+
throw new Error(
|
|
1322
|
+
`JMQ topic search error: HTTP ${result.status} \u2014 ${JSON.stringify(result.body)}`
|
|
1323
|
+
);
|
|
1324
|
+
}
|
|
1325
|
+
const json = result.body;
|
|
1326
|
+
const data = json.data ?? [];
|
|
1327
|
+
pagination = {
|
|
1328
|
+
page: json.pagination?.page ?? currentPage,
|
|
1329
|
+
size: json.pagination?.size ?? pageSize,
|
|
1330
|
+
totalRecord: json.pagination?.totalRecord ?? 0,
|
|
1331
|
+
pages: json.pagination?.pages
|
|
1332
|
+
};
|
|
1333
|
+
totalPages = pagination.pages ?? (Math.ceil((pagination.totalRecord ?? 0) / pageSize) || 1);
|
|
1334
|
+
allData = allData.concat(data);
|
|
1335
|
+
if (!fetchAll || currentPage >= totalPages) break;
|
|
1336
|
+
currentPage++;
|
|
1337
|
+
}
|
|
1338
|
+
const topics = allData.map((item) => ({
|
|
1339
|
+
id: item.id ?? item.code ?? "",
|
|
1340
|
+
partitions: item.partitions ?? 0,
|
|
1341
|
+
type: item.type ?? 0,
|
|
1342
|
+
typeLabel: msgTypeLabel(item.type ?? 0),
|
|
1343
|
+
description: item.wiki?.description ?? item.description ?? "",
|
|
1344
|
+
clusters: (item.clusters ?? []).map((c) => c.code ?? c.name ?? "").filter(Boolean),
|
|
1345
|
+
archive: item.archive ?? false,
|
|
1346
|
+
retentionTime: "",
|
|
1347
|
+
preserveUnconsumed: false,
|
|
1348
|
+
createTime: item.wiki?.createTime ? new Date(item.wiki.createTime).toLocaleDateString("zh-CN") : ""
|
|
1349
|
+
}));
|
|
1350
|
+
return { data: topics, pagination };
|
|
1351
|
+
}
|
|
1352
|
+
async function getGroupDetail(page, groupCode, groupId, env = "prod") {
|
|
1353
|
+
const baseUrl = getEnvBaseUrl(env);
|
|
1354
|
+
const appRef = { id: String(groupId), code: groupCode };
|
|
1355
|
+
const consumerUrl = `${baseUrl}/api/jmqApi/v1/consumer/search-with-pagination`;
|
|
1356
|
+
let allConsumers = [];
|
|
1357
|
+
let consumerPage = 1;
|
|
1358
|
+
while (true) {
|
|
1359
|
+
const consumerBody = {
|
|
1360
|
+
pagination: { page: consumerPage, size: 50 },
|
|
1361
|
+
query: { keyword: "", app: appRef }
|
|
1362
|
+
};
|
|
1363
|
+
const consumerResult = await taishanXhr(page, "POST", consumerUrl, consumerBody, env);
|
|
1364
|
+
if (!consumerResult.ok) {
|
|
1365
|
+
throw new Error(`JMQ consumer search error: HTTP ${consumerResult.status}`);
|
|
1366
|
+
}
|
|
1367
|
+
const cJson = consumerResult.body;
|
|
1368
|
+
const cData = cJson.data ?? [];
|
|
1369
|
+
allConsumers = allConsumers.concat(cData);
|
|
1370
|
+
const cPages = cJson.pagination?.pages ?? 1;
|
|
1371
|
+
if (consumerPage >= cPages) break;
|
|
1372
|
+
consumerPage++;
|
|
1373
|
+
}
|
|
1374
|
+
const producerUrl = `${baseUrl}/api/jmqApi/v1/producer/search-with-pagination`;
|
|
1375
|
+
let allProducers = [];
|
|
1376
|
+
let producerPage = 1;
|
|
1377
|
+
while (true) {
|
|
1378
|
+
const producerBody = {
|
|
1379
|
+
pagination: { page: producerPage, size: 50 },
|
|
1380
|
+
query: { keyword: "", app: appRef }
|
|
1381
|
+
};
|
|
1382
|
+
const producerResult = await taishanXhr(page, "POST", producerUrl, producerBody, env);
|
|
1383
|
+
if (!producerResult.ok) {
|
|
1384
|
+
throw new Error(`JMQ producer search error: HTTP ${producerResult.status}`);
|
|
1385
|
+
}
|
|
1386
|
+
const pJson = producerResult.body;
|
|
1387
|
+
const pData = pJson.data ?? [];
|
|
1388
|
+
allProducers = allProducers.concat(pData);
|
|
1389
|
+
const pPages = pJson.pagination?.pages ?? 1;
|
|
1390
|
+
if (producerPage >= pPages) break;
|
|
1391
|
+
producerPage++;
|
|
1392
|
+
}
|
|
1393
|
+
const monitorUrl = `${baseUrl}/api/jmqApi/v1/monitor/find`;
|
|
1394
|
+
const consumerMonitors = /* @__PURE__ */ new Map();
|
|
1395
|
+
for (const consumer of allConsumers) {
|
|
1396
|
+
const topicCode = consumer.topic?.code ?? "";
|
|
1397
|
+
if (!topicCode) continue;
|
|
1398
|
+
const monitorBody = {
|
|
1399
|
+
topic: { code: topicCode },
|
|
1400
|
+
namespace: { id: "", code: "" },
|
|
1401
|
+
app: { id: groupId, code: groupCode },
|
|
1402
|
+
subscribeGroup: consumer.subscribeGroup ?? "",
|
|
1403
|
+
type: 2
|
|
1404
|
+
// consumer
|
|
1405
|
+
};
|
|
1406
|
+
try {
|
|
1407
|
+
const mResult = await taishanXhr(page, "POST", monitorUrl, monitorBody, env);
|
|
1408
|
+
if (mResult.ok && mResult.body?.data) {
|
|
1409
|
+
consumerMonitors.set(topicCode, mResult.body.data);
|
|
1410
|
+
}
|
|
1411
|
+
} catch {
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
const producerMonitors = /* @__PURE__ */ new Map();
|
|
1415
|
+
for (const producer of allProducers) {
|
|
1416
|
+
const topicCode = producer.topic?.code ?? "";
|
|
1417
|
+
if (!topicCode) continue;
|
|
1418
|
+
const monitorBody = {
|
|
1419
|
+
topic: { code: topicCode },
|
|
1420
|
+
namespace: { id: "", code: "" },
|
|
1421
|
+
app: { id: groupId, code: groupCode },
|
|
1422
|
+
subscribeGroup: producer.subscribeGroup ?? "",
|
|
1423
|
+
type: 1
|
|
1424
|
+
// producer
|
|
1425
|
+
};
|
|
1426
|
+
try {
|
|
1427
|
+
const mResult = await taishanXhr(page, "POST", monitorUrl, monitorBody, env);
|
|
1428
|
+
if (mResult.ok && mResult.body?.data) {
|
|
1429
|
+
producerMonitors.set(topicCode, mResult.body.data);
|
|
1430
|
+
}
|
|
1431
|
+
} catch {
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
const subscriptions = allConsumers.map((c) => {
|
|
1435
|
+
const topicCode = c.topic?.code ?? "";
|
|
1436
|
+
const m = consumerMonitors.get(topicCode);
|
|
1437
|
+
return {
|
|
1438
|
+
topic: topicCode,
|
|
1439
|
+
envName: c.envName ?? "",
|
|
1440
|
+
connections: m?.connections ?? 0,
|
|
1441
|
+
pendingCount: m?.pending?.count ?? 0,
|
|
1442
|
+
dequeueCount: m?.deQuence?.count ?? 0,
|
|
1443
|
+
retryCount: m?.retry?.count ?? 0,
|
|
1444
|
+
retryCurrent: m?.retry?.current ?? 0,
|
|
1445
|
+
concurrent: c.config?.concurrent ?? 1,
|
|
1446
|
+
retry: c.config?.retry ?? false,
|
|
1447
|
+
paused: c.config?.paused ?? false
|
|
1448
|
+
};
|
|
1449
|
+
});
|
|
1450
|
+
const productions = allProducers.map((p) => {
|
|
1451
|
+
const topicCode = p.topic?.code ?? "";
|
|
1452
|
+
const m = producerMonitors.get(topicCode);
|
|
1453
|
+
return {
|
|
1454
|
+
topic: topicCode,
|
|
1455
|
+
envName: p.envName ?? "",
|
|
1456
|
+
connections: m?.connections ?? 0,
|
|
1457
|
+
enqueueCount: m?.enQuence?.count ?? m?.deQuence?.count ?? 0
|
|
1458
|
+
};
|
|
1459
|
+
});
|
|
1460
|
+
return {
|
|
1461
|
+
group: groupCode,
|
|
1462
|
+
groupId,
|
|
1463
|
+
subscriptions,
|
|
1464
|
+
productions
|
|
1465
|
+
};
|
|
1466
|
+
}
|
|
1467
|
+
async function getTopicDetail(page, topicCode, env = "prod") {
|
|
1468
|
+
const baseUrl = getEnvBaseUrl(env);
|
|
1469
|
+
const topicRef = { id: topicCode, code: topicCode, namespace: { code: "" } };
|
|
1470
|
+
const consumerUrl = `${baseUrl}/api/jmqApi/v1/consumer/search-with-pagination`;
|
|
1471
|
+
let allConsumers = [];
|
|
1472
|
+
let consumerPage = 1;
|
|
1473
|
+
while (true) {
|
|
1474
|
+
const consumerBody = {
|
|
1475
|
+
pagination: { page: consumerPage, size: 50 },
|
|
1476
|
+
query: { keyword: "", topic: topicRef }
|
|
1477
|
+
};
|
|
1478
|
+
const consumerResult = await taishanXhr(page, "POST", consumerUrl, consumerBody, env);
|
|
1479
|
+
if (!consumerResult.ok) {
|
|
1480
|
+
throw new Error(`JMQ consumer search error: HTTP ${consumerResult.status}`);
|
|
1481
|
+
}
|
|
1482
|
+
const cJson = consumerResult.body;
|
|
1483
|
+
const cData = cJson.data ?? [];
|
|
1484
|
+
allConsumers = allConsumers.concat(cData);
|
|
1485
|
+
const cPages = cJson.pagination?.pages ?? 1;
|
|
1486
|
+
if (consumerPage >= cPages) break;
|
|
1487
|
+
consumerPage++;
|
|
1488
|
+
}
|
|
1489
|
+
const producerUrl = `${baseUrl}/api/jmqApi/v1/producer/search-with-pagination`;
|
|
1490
|
+
let allProducers = [];
|
|
1491
|
+
let producerPage = 1;
|
|
1492
|
+
while (true) {
|
|
1493
|
+
const producerBody = {
|
|
1494
|
+
pagination: { page: producerPage, size: 50 },
|
|
1495
|
+
query: { keyword: "", topic: topicRef }
|
|
1496
|
+
};
|
|
1497
|
+
const producerResult = await taishanXhr(page, "POST", producerUrl, producerBody, env);
|
|
1498
|
+
if (!producerResult.ok) {
|
|
1499
|
+
throw new Error(`JMQ producer search error: HTTP ${producerResult.status}`);
|
|
1500
|
+
}
|
|
1501
|
+
const pJson = producerResult.body;
|
|
1502
|
+
const pData = pJson.data ?? [];
|
|
1503
|
+
allProducers = allProducers.concat(pData);
|
|
1504
|
+
const pPages = pJson.pagination?.pages ?? 1;
|
|
1505
|
+
if (producerPage >= pPages) break;
|
|
1506
|
+
producerPage++;
|
|
1507
|
+
}
|
|
1508
|
+
const monitorUrl = `${baseUrl}/api/jmqApi/v1/monitor/find`;
|
|
1509
|
+
const consumerMonitors = /* @__PURE__ */ new Map();
|
|
1510
|
+
for (const consumer of allConsumers) {
|
|
1511
|
+
const groupCode = consumer.app?.code ?? "";
|
|
1512
|
+
const groupId = consumer.app?.id ?? 0;
|
|
1513
|
+
if (!groupCode) continue;
|
|
1514
|
+
const monitorBody = {
|
|
1515
|
+
topic: { code: topicCode },
|
|
1516
|
+
namespace: { id: "", code: "" },
|
|
1517
|
+
app: { id: groupId, code: groupCode },
|
|
1518
|
+
subscribeGroup: consumer.subscribeGroup ?? "",
|
|
1519
|
+
type: 2
|
|
1520
|
+
// consumer
|
|
1521
|
+
};
|
|
1522
|
+
try {
|
|
1523
|
+
const mResult = await taishanXhr(page, "POST", monitorUrl, monitorBody, env);
|
|
1524
|
+
if (mResult.ok && mResult.body?.data) {
|
|
1525
|
+
consumerMonitors.set(groupCode, mResult.body.data);
|
|
1526
|
+
}
|
|
1527
|
+
} catch {
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
const producerMonitors = /* @__PURE__ */ new Map();
|
|
1531
|
+
for (const producer of allProducers) {
|
|
1532
|
+
const groupCode = producer.app?.code ?? "";
|
|
1533
|
+
const groupId = producer.app?.id ?? 0;
|
|
1534
|
+
if (!groupCode) continue;
|
|
1535
|
+
const monitorBody = {
|
|
1536
|
+
topic: { code: topicCode },
|
|
1537
|
+
namespace: { id: "", code: "" },
|
|
1538
|
+
app: { id: groupId, code: groupCode },
|
|
1539
|
+
subscribeGroup: producer.subscribeGroup ?? "",
|
|
1540
|
+
type: 1
|
|
1541
|
+
// producer
|
|
1542
|
+
};
|
|
1543
|
+
try {
|
|
1544
|
+
const mResult = await taishanXhr(page, "POST", monitorUrl, monitorBody, env);
|
|
1545
|
+
if (mResult.ok && mResult.body?.data) {
|
|
1546
|
+
producerMonitors.set(groupCode, mResult.body.data);
|
|
1547
|
+
}
|
|
1548
|
+
} catch {
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
const consumers = allConsumers.map((c) => {
|
|
1552
|
+
const groupCode = c.app?.code ?? "";
|
|
1553
|
+
const m = consumerMonitors.get(groupCode);
|
|
1554
|
+
return {
|
|
1555
|
+
group: groupCode,
|
|
1556
|
+
groupId: c.app?.id ?? 0,
|
|
1557
|
+
envName: c.envName ?? "",
|
|
1558
|
+
connections: m?.connections ?? 0,
|
|
1559
|
+
pendingCount: m?.pending?.count ?? 0,
|
|
1560
|
+
dequeueCount: m?.deQuence?.count ?? 0,
|
|
1561
|
+
retryCount: m?.retry?.count ?? 0,
|
|
1562
|
+
timerRetryCount: m?.timerRetry?.count ?? 0,
|
|
1563
|
+
deadMessages: m?.deadMessages ?? 0,
|
|
1564
|
+
concurrent: c.config?.concurrent ?? 1,
|
|
1565
|
+
retry: c.config?.retry ?? false,
|
|
1566
|
+
paused: c.config?.paused ?? false
|
|
1567
|
+
};
|
|
1568
|
+
});
|
|
1569
|
+
const producers = allProducers.map((p) => {
|
|
1570
|
+
const groupCode = p.app?.code ?? "";
|
|
1571
|
+
const m = producerMonitors.get(groupCode);
|
|
1572
|
+
return {
|
|
1573
|
+
group: groupCode,
|
|
1574
|
+
groupId: p.app?.id ?? 0,
|
|
1575
|
+
envName: p.envName ?? "",
|
|
1576
|
+
connections: m?.connections ?? 0,
|
|
1577
|
+
enqueueCount: m?.enQuence?.count ?? m?.deQuence?.count ?? 0
|
|
1578
|
+
};
|
|
1579
|
+
});
|
|
1580
|
+
return {
|
|
1581
|
+
topic: topicCode,
|
|
1582
|
+
consumers,
|
|
1583
|
+
producers
|
|
1584
|
+
};
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
// src/commands/jmq.ts
|
|
1588
|
+
var CYAN2 = "\x1B[36m";
|
|
1589
|
+
var GREEN2 = "\x1B[32m";
|
|
1590
|
+
var YELLOW2 = "\x1B[33m";
|
|
1591
|
+
var RED2 = "\x1B[31m";
|
|
1592
|
+
var DIM2 = "\x1B[2m";
|
|
1593
|
+
var RESET2 = "\x1B[0m";
|
|
1594
|
+
function jmqTargetUrl(env) {
|
|
1595
|
+
return `${getEnvBaseUrl(env)}/jmq/application?JMQ_ENV=prod`;
|
|
1596
|
+
}
|
|
1597
|
+
function parseEnv(val) {
|
|
1598
|
+
const lower = val.toLowerCase();
|
|
1599
|
+
const envMap = {
|
|
1600
|
+
prod: "prod",
|
|
1601
|
+
\u751F\u4EA7: "prod",
|
|
1602
|
+
\u4E2D\u56FD\u7AD9: "prod",
|
|
1603
|
+
test: "test",
|
|
1604
|
+
\u6D4B\u8BD5\u7AD9: "test",
|
|
1605
|
+
th: "th",
|
|
1606
|
+
\u65B0\u52A0\u5761: "th",
|
|
1607
|
+
hl: "hl",
|
|
1608
|
+
\u8377\u5170\u7AD9: "hl",
|
|
1609
|
+
intl: "intl",
|
|
1610
|
+
\u56FD\u9645\u7AD9: "intl",
|
|
1611
|
+
"intl-test": "intl-test",
|
|
1612
|
+
\u56FD\u9645\u6D4B\u8BD5\u7AD9: "intl-test"
|
|
1613
|
+
};
|
|
1614
|
+
if (envMap[lower]) return envMap[lower];
|
|
1615
|
+
console.error(`\u274C Invalid --env: "${val}". Use "prod", "test", "th", "hl", "intl", or "intl-test".`);
|
|
1616
|
+
process.exit(1);
|
|
1617
|
+
}
|
|
1618
|
+
function renderGroupsTable(groups, env) {
|
|
1619
|
+
const table = new Table4({
|
|
1620
|
+
head: ["Group", "\u540D\u79F0", "\u73AF\u5883", "\u8D1F\u8D23\u4EBA", "\u6765\u6E90"],
|
|
1621
|
+
style: { head: ["cyan"], border: ["gray"] },
|
|
1622
|
+
wordWrap: true,
|
|
1623
|
+
colWidths: [30, 30, 8, 16, 40]
|
|
1624
|
+
});
|
|
1625
|
+
for (const g of groups) {
|
|
1626
|
+
const source = g.system && g.aliasCode ? `${g.system}/${g.aliasCode}` : g.source || "-";
|
|
1627
|
+
table.push([g.code, g.name || "-", envLabel(env), g.owner || "-", source]);
|
|
1628
|
+
}
|
|
1629
|
+
console.log("");
|
|
1630
|
+
console.log(table.toString());
|
|
1631
|
+
}
|
|
1632
|
+
function renderTopicsTable(topics) {
|
|
1633
|
+
const table = new Table4({
|
|
1634
|
+
head: ["Topic", "\u96C6\u7FA4", "\u5206\u533A\u6570", "\u6D88\u606F\u7C7B\u578B", "\u63CF\u8FF0"],
|
|
1635
|
+
style: { head: ["cyan"], border: ["gray"] },
|
|
1636
|
+
wordWrap: true,
|
|
1637
|
+
colWidths: [38, 28, 8, 10, 36]
|
|
1638
|
+
});
|
|
1639
|
+
for (const t of topics) {
|
|
1640
|
+
const cluster = t.clusters.length > 0 ? t.clusters.join(", ") : "-";
|
|
1641
|
+
table.push([t.id, cluster, String(t.partitions), t.typeLabel, t.description || "-"]);
|
|
1642
|
+
}
|
|
1643
|
+
console.log("");
|
|
1644
|
+
console.log(table.toString());
|
|
1645
|
+
}
|
|
1646
|
+
function formatNumber(n) {
|
|
1647
|
+
if (n === 0) return "0";
|
|
1648
|
+
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
1649
|
+
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
|
|
1650
|
+
return String(n);
|
|
1651
|
+
}
|
|
1652
|
+
function colorizePending(count) {
|
|
1653
|
+
if (count > 1e3) return `${RED2}${formatNumber(count)}${RESET2}`;
|
|
1654
|
+
if (count > 0) return `${YELLOW2}${formatNumber(count)}${RESET2}`;
|
|
1655
|
+
return `${GREEN2}0${RESET2}`;
|
|
1656
|
+
}
|
|
1657
|
+
function colorizeRetry(count) {
|
|
1658
|
+
if (count > 0) return `${RED2}${formatNumber(count)}${RESET2}`;
|
|
1659
|
+
return `${GREEN2}0${RESET2}`;
|
|
1660
|
+
}
|
|
1661
|
+
function renderGroupDetail(detail) {
|
|
1662
|
+
if (detail.subscriptions.length > 0) {
|
|
1663
|
+
const table = new Table4({
|
|
1664
|
+
head: ["Topic", "\u8FDE\u63A5\u6570", "\u79EF\u538B\u6570", "\u51FA\u961F\u6570", "\u91CD\u8BD5\u6570", "\u8BA2\u9605\u7EBF\u7A0B", "\u6D88\u8D39\u72B6\u6001"],
|
|
1665
|
+
style: { head: ["cyan"], border: ["gray"] },
|
|
1666
|
+
wordWrap: true,
|
|
1667
|
+
colWidths: [32, 8, 10, 12, 8, 8, 10]
|
|
1668
|
+
});
|
|
1669
|
+
for (const s of detail.subscriptions) {
|
|
1670
|
+
const status = s.paused ? `${YELLOW2}\u5DF2\u6682\u505C${RESET2}` : `${GREEN2}\u6B63\u5E38\u6D88\u8D39${RESET2}`;
|
|
1671
|
+
table.push([
|
|
1672
|
+
s.topic,
|
|
1673
|
+
String(s.connections),
|
|
1674
|
+
colorizePending(s.pendingCount),
|
|
1675
|
+
formatNumber(s.dequeueCount),
|
|
1676
|
+
colorizeRetry(s.retryCount),
|
|
1677
|
+
String(s.concurrent),
|
|
1678
|
+
status
|
|
1679
|
+
]);
|
|
1680
|
+
}
|
|
1681
|
+
console.log(`
|
|
1682
|
+
${CYAN2}\u{1F4CB} \u6D88\u8D39\u8005\u8BA2\u9605${RESET2}`);
|
|
1683
|
+
console.log(table.toString());
|
|
1684
|
+
} else {
|
|
1685
|
+
console.log(`
|
|
1686
|
+
${DIM2}\u{1F4CB} \u6D88\u8D39\u8005\u8BA2\u9605\uFF1A\u6682\u65E0${RESET2}`);
|
|
1687
|
+
}
|
|
1688
|
+
if (detail.productions.length > 0) {
|
|
1689
|
+
const table = new Table4({
|
|
1690
|
+
head: ["Topic", "\u8FDE\u63A5\u6570", "\u5165\u961F\u6570"],
|
|
1691
|
+
style: { head: ["cyan"], border: ["gray"] },
|
|
1692
|
+
wordWrap: true,
|
|
1693
|
+
colWidths: [32, 8, 14]
|
|
1694
|
+
});
|
|
1695
|
+
for (const p of detail.productions) {
|
|
1696
|
+
table.push([p.topic, String(p.connections), formatNumber(p.enqueueCount)]);
|
|
1697
|
+
}
|
|
1698
|
+
console.log(`
|
|
1699
|
+
${CYAN2}\u{1F4E4} \u751F\u4EA7\u8005\u8BA2\u9605${RESET2}`);
|
|
1700
|
+
console.log(table.toString());
|
|
1701
|
+
} else {
|
|
1702
|
+
console.log(`
|
|
1703
|
+
${DIM2}\u{1F4E4} \u751F\u4EA7\u8005\u8BA2\u9605\uFF1A\u6682\u65E0${RESET2}`);
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
function renderTopicDetail(detail) {
|
|
1707
|
+
if (detail.consumers.length > 0) {
|
|
1708
|
+
const table = new Table4({
|
|
1709
|
+
head: ["Group", "\u8FDE\u63A5\u6570", "\u79EF\u538B\u6570", "\u51FA\u961F\u6570", "\u91CD\u8BD5\u6570", "\u9AD8\u6027\u80FD\u91CD\u8BD5", "\u6B7B\u4FE1\u6D88\u606F", "\u6D88\u8D39\u72B6\u6001"],
|
|
1710
|
+
style: { head: ["cyan"], border: ["gray"] },
|
|
1711
|
+
wordWrap: true,
|
|
1712
|
+
colWidths: [28, 8, 10, 12, 8, 10, 10, 10]
|
|
1713
|
+
});
|
|
1714
|
+
for (const c of detail.consumers) {
|
|
1715
|
+
const status = c.paused ? `${YELLOW2}\u5DF2\u6682\u505C${RESET2}` : `${GREEN2}\u6B63\u5E38\u6D88\u8D39${RESET2}`;
|
|
1716
|
+
table.push([
|
|
1717
|
+
c.group,
|
|
1718
|
+
String(c.connections),
|
|
1719
|
+
colorizePending(c.pendingCount),
|
|
1720
|
+
formatNumber(c.dequeueCount),
|
|
1721
|
+
colorizeRetry(c.retryCount),
|
|
1722
|
+
colorizeRetry(c.timerRetryCount),
|
|
1723
|
+
String(c.deadMessages),
|
|
1724
|
+
status
|
|
1725
|
+
]);
|
|
1726
|
+
}
|
|
1727
|
+
console.log(`
|
|
1728
|
+
${CYAN2}\u{1F4CB} \u6D88\u8D39\u7EC4${RESET2}`);
|
|
1729
|
+
console.log(table.toString());
|
|
1730
|
+
} else {
|
|
1731
|
+
console.log(`
|
|
1732
|
+
${DIM2}\u{1F4CB} \u6D88\u8D39\u7EC4\uFF1A\u6682\u65E0${RESET2}`);
|
|
1733
|
+
}
|
|
1734
|
+
if (detail.producers.length > 0) {
|
|
1735
|
+
const table = new Table4({
|
|
1736
|
+
head: ["Group", "\u8FDE\u63A5\u6570", "\u5165\u961F\u6570"],
|
|
1737
|
+
style: { head: ["cyan"], border: ["gray"] },
|
|
1738
|
+
wordWrap: true,
|
|
1739
|
+
colWidths: [28, 8, 14]
|
|
1740
|
+
});
|
|
1741
|
+
for (const p of detail.producers) {
|
|
1742
|
+
table.push([p.group, String(p.connections), formatNumber(p.enqueueCount)]);
|
|
1743
|
+
}
|
|
1744
|
+
console.log(`
|
|
1745
|
+
${CYAN2}\u{1F4E4} \u751F\u4EA7\u7EC4${RESET2}`);
|
|
1746
|
+
console.log(table.toString());
|
|
1747
|
+
} else {
|
|
1748
|
+
console.log(`
|
|
1749
|
+
${DIM2}\u{1F4E4} \u751F\u4EA7\u7EC4\uFF1A\u6682\u65E0${RESET2}`);
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
function registerJmqCommand(program) {
|
|
1753
|
+
const jmq = program.command("jmq").description("Taishan JMQ\uFF08taishan.jd.com\uFF09\u6D88\u606F\u961F\u5217\u7BA1\u7406");
|
|
1754
|
+
jmq.command("groups").description("\u641C\u7D22 JMQ Group\uFF08\u5373\u539F\u6765\u7684\u5E94\u7528\uFF09\uFF0C\u9ED8\u8BA4\u8FD4\u56DE\u5168\u90E8\u7ED3\u679C").addHelpText("after", `
|
|
1755
|
+
\u73AF\u5883\u8BF4\u660E\uFF08--env\uFF09\uFF1A
|
|
1756
|
+
prod \u4E2D\u56FD\u7AD9\u751F\u4EA7\uFF08taishan.jd.com\uFF09
|
|
1757
|
+
test \u6D4B\u8BD5\u7AD9\uFF08test.taishan.jd.com\uFF09
|
|
1758
|
+
th \u65B0\u52A0\u5761\u751F\u4EA7\uFF08th.taishan.jd.com\uFF09
|
|
1759
|
+
hl \u8377\u5170\u7AD9\u751F\u4EA7\uFF08hl.taishan.jd.com\uFF09
|
|
1760
|
+
intl \u56FD\u9645\u7AD9\u751F\u4EA7\uFF08joybuy.taishan.jd.com\uFF09
|
|
1761
|
+
intl-test \u56FD\u9645\u6D4B\u8BD5\u7AD9\uFF08test-intl.taishan.jd.com\uFF09
|
|
1762
|
+
|
|
1763
|
+
\u4F7F\u7528\u793A\u4F8B\uFF1A
|
|
1764
|
+
# \u67E5\u8BE2\u6240\u6709 Group\uFF08\u4E2D\u56FD\u7AD9\u751F\u4EA7\uFF09
|
|
1765
|
+
yue jmq groups
|
|
1766
|
+
|
|
1767
|
+
# \u6309 Group \u540D\u79F0\u6A21\u7CCA\u641C\u7D22
|
|
1768
|
+
yue jmq groups --name baoxian
|
|
1769
|
+
|
|
1770
|
+
# \u6D4B\u8BD5\u7AD9
|
|
1771
|
+
yue jmq groups --name baoxian --env test
|
|
1772
|
+
|
|
1773
|
+
# \u8377\u5170\u7AD9
|
|
1774
|
+
yue jmq groups --name baoxian --env hl
|
|
1775
|
+
|
|
1776
|
+
# \u53EA\u770B\u67D0\u4E00\u9875
|
|
1777
|
+
yue jmq groups --name baoxian --page 2
|
|
1778
|
+
|
|
1779
|
+
# JSON \u8F93\u51FA
|
|
1780
|
+
yue jmq groups --name baoxian --output json
|
|
1781
|
+
`).option("--name <keyword>", "Group \u540D\u79F0\u5173\u952E\u5B57\uFF08\u6A21\u7CCA\u641C\u7D22\uFF09\uFF0C\u4E0D\u4F20\u5219\u67E5\u8BE2\u6240\u6709").option("--env <env>", "\u73AF\u5883\uFF1Aprod\uFF08\u9ED8\u8BA4\uFF09/ test / th / hl / intl / intl-test", "prod").option("--page <n>", "\u9875\u7801\uFF08\u4E0D\u6307\u5B9A\u5219\u8FD4\u56DE\u5168\u90E8\uFF09", parseInt).option("--output <format>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable\uFF08\u9ED8\u8BA4\uFF09/ json", "table").action(async (opts) => {
|
|
1782
|
+
const env = parseEnv(opts.env ?? "prod");
|
|
1783
|
+
const pageNum = opts.page;
|
|
1784
|
+
const keyword = opts.name ?? "";
|
|
1785
|
+
const output = (opts.output ?? "table").toLowerCase();
|
|
1786
|
+
await withBrowser(async (pageCtx) => {
|
|
1787
|
+
try {
|
|
1788
|
+
await pageCtx.waitForNetworkIdle?.();
|
|
1789
|
+
} catch {
|
|
1790
|
+
}
|
|
1791
|
+
const searchDesc = keyword ? `"${keyword}"` : "\u5168\u90E8";
|
|
1792
|
+
console.log(`\u{1F50D} \u641C\u7D22 JMQ Group: ${searchDesc} (${envLabel(env)})...`);
|
|
1793
|
+
let result;
|
|
1794
|
+
try {
|
|
1795
|
+
result = await searchGroups(pageCtx, keyword, env, pageNum, 50);
|
|
1796
|
+
} catch (err) {
|
|
1797
|
+
console.error(`\u274C \u641C\u7D22\u5931\u8D25: ${err.message}`);
|
|
1798
|
+
console.error(` \u8BF7\u786E\u4FDD\u6D4F\u89C8\u5668\u5DF2\u767B\u5F55 ${getEnvBaseUrl(env)}`);
|
|
1799
|
+
process.exit(1);
|
|
1800
|
+
}
|
|
1801
|
+
if (output === "json") {
|
|
1802
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1803
|
+
return;
|
|
1804
|
+
}
|
|
1805
|
+
if (!result.data || result.data.length === 0) {
|
|
1806
|
+
console.log("\u{1F4ED} \u672A\u627E\u5230\u5339\u914D\u7684 Group\u3002");
|
|
1807
|
+
return;
|
|
1808
|
+
}
|
|
1809
|
+
renderGroupsTable(result.data, env);
|
|
1810
|
+
const total = result.pagination.totalRecord ?? result.data.length;
|
|
1811
|
+
console.log(`
|
|
1812
|
+
\u{1F4CB} \u5171 ${result.data.length} \u6761\u7ED3\u679C\uFF08\u603B\u8BA1 ${total} \u6761\uFF09`);
|
|
1813
|
+
}, { targetUrl: jmqTargetUrl(env) });
|
|
1814
|
+
});
|
|
1815
|
+
jmq.command("topics").description("\u641C\u7D22 JMQ Topic\uFF0C\u9ED8\u8BA4\u8FD4\u56DE\u5168\u90E8\u7ED3\u679C").addHelpText("after", `
|
|
1816
|
+
\u73AF\u5883\u8BF4\u660E\uFF08--env\uFF09\uFF1A
|
|
1817
|
+
prod \u4E2D\u56FD\u7AD9\u751F\u4EA7\uFF08taishan.jd.com\uFF09
|
|
1818
|
+
test \u6D4B\u8BD5\u7AD9\uFF08test.taishan.jd.com\uFF09
|
|
1819
|
+
th \u65B0\u52A0\u5761\u751F\u4EA7\uFF08th.taishan.jd.com\uFF09
|
|
1820
|
+
hl \u8377\u5170\u7AD9\u751F\u4EA7\uFF08hl.taishan.jd.com\uFF09
|
|
1821
|
+
intl \u56FD\u9645\u7AD9\u751F\u4EA7\uFF08joybuy.taishan.jd.com\uFF09
|
|
1822
|
+
intl-test \u56FD\u9645\u6D4B\u8BD5\u7AD9\uFF08test-intl.taishan.jd.com\uFF09
|
|
1823
|
+
|
|
1824
|
+
\u4F7F\u7528\u793A\u4F8B\uFF1A
|
|
1825
|
+
# \u67E5\u8BE2\u6240\u6709 Topic\uFF08\u4E2D\u56FD\u7AD9\u751F\u4EA7\uFF09
|
|
1826
|
+
yue jmq topics
|
|
1827
|
+
|
|
1828
|
+
# \u6309 Topic \u540D\u79F0\u6A21\u7CCA\u641C\u7D22
|
|
1829
|
+
yue jmq topics --name baoxian
|
|
1830
|
+
|
|
1831
|
+
# \u53EA\u770B\u6211\u7684\u4E3B\u9898
|
|
1832
|
+
yue jmq topics --name baoxian --personal
|
|
1833
|
+
|
|
1834
|
+
# \u6D4B\u8BD5\u7AD9
|
|
1835
|
+
yue jmq topics --name baoxian --env test
|
|
1836
|
+
|
|
1837
|
+
# \u8377\u5170\u7AD9
|
|
1838
|
+
yue jmq topics --name baoxian --env hl
|
|
1839
|
+
|
|
1840
|
+
# \u53EA\u770B\u67D0\u4E00\u9875
|
|
1841
|
+
yue jmq topics --name baoxian --page 2
|
|
1842
|
+
|
|
1843
|
+
# JSON \u8F93\u51FA
|
|
1844
|
+
yue jmq topics --name baoxian --output json
|
|
1845
|
+
`).option("--name <keyword>", "Topic \u540D\u79F0\u5173\u952E\u5B57\uFF08\u6A21\u7CCA\u641C\u7D22\uFF09\uFF0C\u4E0D\u4F20\u5219\u67E5\u8BE2\u6240\u6709").option("--env <env>", "\u73AF\u5883\uFF1Aprod\uFF08\u9ED8\u8BA4\uFF09/ test / th / hl / intl / intl-test", "prod").option("--personal", "\u53EA\u770B\u6211\u7684\u4E3B\u9898", false).option("--page <n>", "\u9875\u7801\uFF08\u4E0D\u6307\u5B9A\u5219\u8FD4\u56DE\u5168\u90E8\uFF09", parseInt).option("--output <format>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable\uFF08\u9ED8\u8BA4\uFF09/ json", "table").action(async (opts) => {
|
|
1846
|
+
const env = parseEnv(opts.env ?? "prod");
|
|
1847
|
+
const pageNum = opts.page;
|
|
1848
|
+
const keyword = opts.name ?? "";
|
|
1849
|
+
const personal = !!opts.personal;
|
|
1850
|
+
const output = (opts.output ?? "table").toLowerCase();
|
|
1851
|
+
await withBrowser(async (pageCtx) => {
|
|
1852
|
+
try {
|
|
1853
|
+
await pageCtx.waitForNetworkIdle?.();
|
|
1854
|
+
} catch {
|
|
1855
|
+
}
|
|
1856
|
+
const searchDesc = keyword ? `"${keyword}"` : "\u5168\u90E8";
|
|
1857
|
+
const personalTag = personal ? " (\u6211\u7684\u4E3B\u9898)" : "";
|
|
1858
|
+
console.log(`\u{1F50D} \u641C\u7D22 JMQ Topic: ${searchDesc} (${envLabel(env)})${personalTag}...`);
|
|
1859
|
+
let result;
|
|
1860
|
+
try {
|
|
1861
|
+
result = await searchTopics(pageCtx, keyword, env, pageNum, 50, personal);
|
|
1862
|
+
} catch (err) {
|
|
1863
|
+
console.error(`\u274C \u641C\u7D22\u5931\u8D25: ${err.message}`);
|
|
1864
|
+
console.error(` \u8BF7\u786E\u4FDD\u6D4F\u89C8\u5668\u5DF2\u767B\u5F55 ${getEnvBaseUrl(env)}`);
|
|
1865
|
+
process.exit(1);
|
|
1866
|
+
}
|
|
1867
|
+
if (output === "json") {
|
|
1868
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1869
|
+
return;
|
|
1870
|
+
}
|
|
1871
|
+
if (!result.data || result.data.length === 0) {
|
|
1872
|
+
console.log("\u{1F4ED} \u672A\u627E\u5230\u5339\u914D\u7684 Topic\u3002");
|
|
1873
|
+
return;
|
|
1874
|
+
}
|
|
1875
|
+
renderTopicsTable(result.data);
|
|
1876
|
+
const total = result.pagination.totalRecord ?? result.data.length;
|
|
1877
|
+
console.log(`
|
|
1878
|
+
\u{1F4CB} \u5171 ${result.data.length} \u6761\u7ED3\u679C\uFF08\u603B\u8BA1 ${total} \u6761\uFF09`);
|
|
1879
|
+
}, { targetUrl: jmqTargetUrl(env) });
|
|
1880
|
+
});
|
|
1881
|
+
jmq.command("group").description("\u67E5\u770B Group \u8BE6\u60C5\uFF1A\u6D88\u8D39\u91CD\u8BD5\u3001\u79EF\u538B\u6570\u3001\u8BA2\u9605/\u751F\u4EA7\u7EBF\u7A0B\u6570\u7B49\u8FD0\u884C\u65F6\u6570\u636E").addHelpText("after", `
|
|
1882
|
+
\u73AF\u5883\u8BF4\u660E\uFF08--env\uFF09\uFF1A
|
|
1883
|
+
prod \u4E2D\u56FD\u7AD9\u751F\u4EA7\uFF08taishan.jd.com\uFF09
|
|
1884
|
+
test \u6D4B\u8BD5\u7AD9\uFF08test.taishan.jd.com\uFF09
|
|
1885
|
+
th \u65B0\u52A0\u5761\u751F\u4EA7\uFF08th.taishan.jd.com\uFF09
|
|
1886
|
+
hl \u8377\u5170\u7AD9\u751F\u4EA7\uFF08hl.taishan.jd.com\uFF09
|
|
1887
|
+
intl \u56FD\u9645\u7AD9\u751F\u4EA7\uFF08joybuy.taishan.jd.com\uFF09
|
|
1888
|
+
intl-test \u56FD\u9645\u6D4B\u8BD5\u7AD9\uFF08test-intl.taishan.jd.com\uFF09
|
|
1889
|
+
|
|
1890
|
+
\u4F7F\u7528\u793A\u4F8B\uFF1A
|
|
1891
|
+
# \u67E5\u770B Group \u8BE6\u60C5\uFF08\u4E2D\u56FD\u7AD9\u751F\u4EA7\uFF09
|
|
1892
|
+
yue jmq group baoxianMessageMall
|
|
1893
|
+
|
|
1894
|
+
# \u6D4B\u8BD5\u7AD9
|
|
1895
|
+
yue jmq group baoxianMessageMall --env test
|
|
1896
|
+
|
|
1897
|
+
# \u8377\u5170\u7AD9
|
|
1898
|
+
yue jmq group baoxianMessageMall --env hl
|
|
1899
|
+
|
|
1900
|
+
# JSON \u8F93\u51FA
|
|
1901
|
+
yue jmq group baoxianMessageMall --output json
|
|
1902
|
+
`).argument("<groupCode>", "Group \u540D\u79F0").option("--env <env>", "\u73AF\u5883\uFF1Aprod\uFF08\u9ED8\u8BA4\uFF09/ test / th / hl / intl / intl-test", "prod").option("--output <format>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable\uFF08\u9ED8\u8BA4\uFF09/ json", "table").action(async (groupCode, opts) => {
|
|
1903
|
+
const env = parseEnv(opts.env ?? "prod");
|
|
1904
|
+
const output = (opts.output ?? "table").toLowerCase();
|
|
1905
|
+
await withBrowser(async (pageCtx) => {
|
|
1906
|
+
try {
|
|
1907
|
+
await pageCtx.waitForNetworkIdle?.();
|
|
1908
|
+
} catch {
|
|
1909
|
+
}
|
|
1910
|
+
console.log(`\u{1F50D} \u641C\u7D22 Group: "${groupCode}" (${envLabel(env)})...`);
|
|
1911
|
+
let searchResult;
|
|
1912
|
+
try {
|
|
1913
|
+
searchResult = await searchGroups(pageCtx, groupCode, env, void 0, 50);
|
|
1914
|
+
} catch (err) {
|
|
1915
|
+
console.error(`\u274C \u641C\u7D22\u5931\u8D25: ${err.message}`);
|
|
1916
|
+
console.error(` \u8BF7\u786E\u4FDD\u6D4F\u89C8\u5668\u5DF2\u767B\u5F55 ${getEnvBaseUrl(env)}`);
|
|
1917
|
+
process.exit(1);
|
|
1918
|
+
}
|
|
1919
|
+
let selectedGroup;
|
|
1920
|
+
selectedGroup = searchResult.data.find((g) => g.code === groupCode);
|
|
1921
|
+
if (!selectedGroup) {
|
|
1922
|
+
selectedGroup = searchResult.data.find((g) => g.code.toLowerCase() === groupCode.toLowerCase());
|
|
1923
|
+
}
|
|
1924
|
+
if (!selectedGroup && searchResult.data.length > 0) {
|
|
1925
|
+
selectedGroup = searchResult.data[0];
|
|
1926
|
+
}
|
|
1927
|
+
if (!selectedGroup) {
|
|
1928
|
+
console.error(`\u274C \u672A\u627E\u5230 Group: "${groupCode}"`);
|
|
1929
|
+
process.exit(1);
|
|
1930
|
+
}
|
|
1931
|
+
if (selectedGroup.code !== groupCode) {
|
|
1932
|
+
console.log(`${YELLOW2}\u26A0 \u672A\u7CBE\u786E\u5339\u914D\uFF0C\u4F7F\u7528: ${selectedGroup.code}${RESET2}`);
|
|
1933
|
+
}
|
|
1934
|
+
console.log(`\u{1F4CA} \u83B7\u53D6 ${selectedGroup.code} \u7684\u8FD0\u884C\u65F6\u6570\u636E...`);
|
|
1935
|
+
let detail;
|
|
1936
|
+
try {
|
|
1937
|
+
detail = await getGroupDetail(pageCtx, selectedGroup.code, selectedGroup.id, env);
|
|
1938
|
+
} catch (err) {
|
|
1939
|
+
console.error(`\u274C \u83B7\u53D6\u8BE6\u60C5\u5931\u8D25: ${err.message}`);
|
|
1940
|
+
process.exit(1);
|
|
1941
|
+
}
|
|
1942
|
+
if (output === "json") {
|
|
1943
|
+
console.log(JSON.stringify(detail, null, 2));
|
|
1944
|
+
return;
|
|
1945
|
+
}
|
|
1946
|
+
console.log(`
|
|
1947
|
+
${CYAN2}\u2501\u2501\u2501 ${detail.group} \u2501\u2501\u2501${RESET2}`);
|
|
1948
|
+
renderGroupDetail(detail);
|
|
1949
|
+
const totalSubs = detail.subscriptions.length;
|
|
1950
|
+
const totalProds = detail.productions.length;
|
|
1951
|
+
console.log(`
|
|
1952
|
+
\u{1F4CB} \u6D88\u8D39 ${totalSubs} \u4E2A Topic\uFF0C\u751F\u4EA7 ${totalProds} \u4E2A Topic`);
|
|
1953
|
+
}, { targetUrl: jmqTargetUrl(env) });
|
|
1954
|
+
});
|
|
1955
|
+
jmq.command("topic").description("\u67E5\u770B Topic \u8BE6\u60C5\uFF1A\u6D88\u8D39\u7EC4\u3001\u751F\u4EA7\u7EC4\u3001\u79EF\u538B\u3001\u91CD\u8BD5\u7B49\u8FD0\u884C\u65F6\u6570\u636E").addHelpText("after", `
|
|
1956
|
+
\u73AF\u5883\u8BF4\u660E\uFF08--env\uFF09\uFF1A
|
|
1957
|
+
prod \u4E2D\u56FD\u7AD9\u751F\u4EA7\uFF08taishan.jd.com\uFF09
|
|
1958
|
+
test \u6D4B\u8BD5\u7AD9\uFF08test.taishan.jd.com\uFF09
|
|
1959
|
+
th \u65B0\u52A0\u5761\u751F\u4EA7\uFF08th.taishan.jd.com\uFF09
|
|
1960
|
+
hl \u8377\u5170\u7AD9\u751F\u4EA7\uFF08hl.taishan.jd.com\uFF09
|
|
1961
|
+
intl \u56FD\u9645\u7AD9\u751F\u4EA7\uFF08joybuy.taishan.jd.com\uFF09
|
|
1962
|
+
intl-test \u56FD\u9645\u6D4B\u8BD5\u7AD9\uFF08test-intl.taishan.jd.com\uFF09
|
|
1963
|
+
|
|
1964
|
+
\u4F7F\u7528\u793A\u4F8B\uFF1A
|
|
1965
|
+
# \u67E5\u770B Topic \u8BE6\u60C5\uFF08\u4E2D\u56FD\u7AD9\u751F\u4EA7\uFF09
|
|
1966
|
+
yue jmq topic baoxianMessageMall_Order_Submit
|
|
1967
|
+
|
|
1968
|
+
# \u6D4B\u8BD5\u7AD9
|
|
1969
|
+
yue jmq topic baoxianMessageMall_Order_Submit --env test
|
|
1970
|
+
|
|
1971
|
+
# \u8377\u5170\u7AD9
|
|
1972
|
+
yue jmq topic baoxianMessageMall_Order_Submit --env hl
|
|
1973
|
+
|
|
1974
|
+
# JSON \u8F93\u51FA
|
|
1975
|
+
yue jmq topic baoxianMessageMall_Order_Submit --output json
|
|
1976
|
+
`).argument("<topicCode>", "Topic \u540D\u79F0").option("--env <env>", "\u73AF\u5883\uFF1Aprod\uFF08\u9ED8\u8BA4\uFF09/ test / th / hl / intl / intl-test", "prod").option("--output <format>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable\uFF08\u9ED8\u8BA4\uFF09/ json", "table").action(async (topicCode, opts) => {
|
|
1977
|
+
const env = parseEnv(opts.env ?? "prod");
|
|
1978
|
+
const output = (opts.output ?? "table").toLowerCase();
|
|
1979
|
+
await withBrowser(async (pageCtx) => {
|
|
1980
|
+
try {
|
|
1981
|
+
await pageCtx.waitForNetworkIdle?.();
|
|
1982
|
+
} catch {
|
|
1983
|
+
}
|
|
1984
|
+
console.log(`\u{1F4CA} \u83B7\u53D6 Topic "${topicCode}" \u7684\u8BE6\u60C5 (${envLabel(env)})...`);
|
|
1985
|
+
let detail;
|
|
1986
|
+
try {
|
|
1987
|
+
detail = await getTopicDetail(pageCtx, topicCode, env);
|
|
1988
|
+
} catch (err) {
|
|
1989
|
+
console.error(`\u274C \u83B7\u53D6\u8BE6\u60C5\u5931\u8D25: ${err.message}`);
|
|
1990
|
+
console.error(` \u8BF7\u786E\u4FDD\u6D4F\u89C8\u5668\u5DF2\u767B\u5F55 ${getEnvBaseUrl(env)}`);
|
|
1991
|
+
process.exit(1);
|
|
1992
|
+
}
|
|
1993
|
+
if (output === "json") {
|
|
1994
|
+
console.log(JSON.stringify(detail, null, 2));
|
|
1995
|
+
return;
|
|
1996
|
+
}
|
|
1997
|
+
console.log(`
|
|
1998
|
+
${CYAN2}\u2501\u2501\u2501 ${detail.topic} \u2501\u2501\u2501${RESET2}`);
|
|
1999
|
+
renderTopicDetail(detail);
|
|
2000
|
+
const totalConsumers = detail.consumers.length;
|
|
2001
|
+
const totalProducers = detail.producers.length;
|
|
2002
|
+
console.log(`
|
|
2003
|
+
\u{1F4CB} ${totalConsumers} \u4E2A\u6D88\u8D39\u7EC4\uFF0C${totalProducers} \u4E2A\u751F\u4EA7\u7EC4`);
|
|
2004
|
+
}, { targetUrl: jmqTargetUrl(env) });
|
|
2005
|
+
});
|
|
585
2006
|
}
|
|
586
2007
|
|
|
587
2008
|
// src/cli.ts
|
|
588
2009
|
function run() {
|
|
589
2010
|
const program = new Command();
|
|
590
|
-
program.name("yue").description("
|
|
591
|
-
const mydb = program.command("mydb").description("mydb.jdfmgt.com
|
|
2011
|
+
program.name("yue").description("yue-cli\uFF1Amydb \u67E5\u8BE2\u4E0E Digger \u65E5\u5FD7\u68C0\u7D22").version("0.1.5");
|
|
2012
|
+
const mydb = program.command("mydb").description("mydb\uFF08mydb.jdfmgt.com\uFF09\u76F8\u5173\u64CD\u4F5C");
|
|
592
2013
|
registerDatasourcesCommand(mydb);
|
|
593
2014
|
registerQueryCommand(mydb);
|
|
594
2015
|
registerDiggerCommand(program);
|
|
2016
|
+
registerJmqCommand(program);
|
|
595
2017
|
program.parse();
|
|
596
2018
|
}
|
|
597
2019
|
|