@tonbo/cli 0.20.0 → 0.21.0

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/bin/tonbo.js +164 -0
  2. package/package.json +1 -1
package/dist/bin/tonbo.js CHANGED
@@ -710,6 +710,36 @@ var managementOperations = {
710
710
  "idempotencyKey": false,
711
711
  "cli": "tonbo machine activations"
712
712
  },
713
+ "getMachineMetrics": {
714
+ "method": "GET",
715
+ "path": "/machines/{name}/metrics",
716
+ "pathParams": [
717
+ "name"
718
+ ],
719
+ "query": [
720
+ "series",
721
+ "window",
722
+ "granularity",
723
+ "from",
724
+ "to"
725
+ ],
726
+ "idempotencyKey": false,
727
+ "cli": "tonbo machine metrics"
728
+ },
729
+ "getAccountMachineMetrics": {
730
+ "method": "GET",
731
+ "path": "/metrics/machines",
732
+ "pathParams": [],
733
+ "query": [
734
+ "series",
735
+ "window",
736
+ "granularity",
737
+ "from",
738
+ "to"
739
+ ],
740
+ "idempotencyKey": false,
741
+ "cli": "tonbo metrics machines"
742
+ },
713
743
  "listMachineShapes": {
714
744
  "method": "GET",
715
745
  "path": "/machine-shapes",
@@ -2499,6 +2529,14 @@ var ManagementApi = class {
2499
2529
  query: { limit, cursor }
2500
2530
  });
2501
2531
  }
2532
+ /** A managed Machine's metrics per UTC hour or day. */
2533
+ getMachineMetrics(key, name, query = {}) {
2534
+ return this.call("getMachineMetrics", key, { params: { name }, query });
2535
+ }
2536
+ /** The account's Machines' metrics per UTC hour or day, each and summed. */
2537
+ getAccountMachineMetrics(key, query = {}) {
2538
+ return this.call("getAccountMachineMetrics", key, { query });
2539
+ }
2502
2540
  /** The whole answer: the shapes and the default one. */
2503
2541
  listMachineShapes(key) {
2504
2542
  return this.request("listMachineShapes", key, {});
@@ -5330,6 +5368,78 @@ async function metricsVolumesCommand(deps, options = {}) {
5330
5368
  lines.push(`Not read: ${metrics.unavailable_regions.join(", ")}`);
5331
5369
  print(deps, options.json, metrics, lines.join("\n"));
5332
5370
  }
5371
+ function metricsQuery(options) {
5372
+ return {
5373
+ series: options.series,
5374
+ window: options.window,
5375
+ granularity: options.granularity,
5376
+ from: options.from,
5377
+ to: options.to
5378
+ };
5379
+ }
5380
+ var MACHINE_COLUMNS = {
5381
+ awake_seconds: ["AWAKE", (value) => `${Math.round(value / 60)} min`],
5382
+ wakes: ["WAKES", String],
5383
+ refused_wakes: ["REFUSED", String],
5384
+ wake_ms_p50: ["WAKE P50", (value) => `${(value / 1e3).toFixed(1)} s`],
5385
+ wake_ms_max: ["WAKE MAX", (value) => `${(value / 1e3).toFixed(1)} s`],
5386
+ cpu_cores_avg: ["CPU", (value) => `${value} cores`],
5387
+ memory_mib_avg: ["MEMORY", (value) => bytes(value * 1024 * 1024)],
5388
+ network_rx_bytes: ["NET IN", (value) => bytes(value)],
5389
+ network_tx_bytes: ["NET OUT", (value) => bytes(value)],
5390
+ internet_rx_bytes: ["INTERNET IN", (value) => bytes(value)],
5391
+ internet_tx_bytes: ["INTERNET OUT", (value) => bytes(value)]
5392
+ };
5393
+ function machineMetricsTable(granularity, points) {
5394
+ const series = Object.keys(MACHINE_COLUMNS).filter(
5395
+ (name) => points.some((point) => name in point)
5396
+ );
5397
+ return table(
5398
+ [
5399
+ granularity === "hour" ? "HOUR (UTC)" : "DAY (UTC)",
5400
+ ...series.map((name) => MACHINE_COLUMNS[name][0])
5401
+ ],
5402
+ points.map((point) => [
5403
+ granularity === "hour" ? point.start.slice(0, 16).replace("T", " ") : point.start.slice(0, 10),
5404
+ ...series.map((name) => {
5405
+ const value = point[name];
5406
+ if (value === null || value === void 0)
5407
+ return Date.parse(point.start) > Date.now() ? "" : "-";
5408
+ return MACHINE_COLUMNS[name][1](value);
5409
+ })
5410
+ ])
5411
+ );
5412
+ }
5413
+ async function metricsMachinesCommand(deps, options = {}) {
5414
+ const metrics = await deps.api.getAccountMachineMetrics(
5415
+ await deps.auth.apiKey(),
5416
+ metricsQuery(options)
5417
+ );
5418
+ const lines = [
5419
+ `The account's Machines from ${metrics.from} to ${metrics.to} (UTC)`,
5420
+ machineMetricsTable(metrics.granularity, metrics.total.points)
5421
+ ];
5422
+ if (metrics.resources.length > 0) {
5423
+ const sum = (points, name) => points.reduce((total, point) => total + (point[name] ?? 0), 0);
5424
+ const series = Object.keys(MACHINE_COLUMNS).filter(
5425
+ (name) => metrics.total.points.some((point) => name in point)
5426
+ );
5427
+ lines.push(
5428
+ "",
5429
+ table(
5430
+ ["MACHINE", "REGION", ...series.map((name) => MACHINE_COLUMNS[name][0])],
5431
+ metrics.resources.map((resource) => [
5432
+ resource.name,
5433
+ resource.region,
5434
+ ...series.map((name) => MACHINE_COLUMNS[name][1](sum(resource.points, name)))
5435
+ ])
5436
+ )
5437
+ );
5438
+ }
5439
+ if (metrics.unavailable_regions.length > 0)
5440
+ lines.push(`Not read: ${metrics.unavailable_regions.join(", ")}`);
5441
+ print(deps, options.json, metrics, lines.join("\n"));
5442
+ }
5333
5443
  async function streamActivityCommand(deps, name, options = {}) {
5334
5444
  const activity = await deps.api.getStreamActivity(
5335
5445
  await deps.auth.apiKey(),
@@ -6390,6 +6500,24 @@ async function machineActivationsCommand(deps, name, options = {}) {
6390
6500
  );
6391
6501
  });
6392
6502
  }
6503
+ async function machineMetricsCommand(deps, name, options = {}) {
6504
+ await machineCommand(async () => {
6505
+ const metrics = await deps.api.getMachineMetrics(
6506
+ await deps.auth.apiKey(),
6507
+ name,
6508
+ metricsQuery(options)
6509
+ );
6510
+ print(
6511
+ deps,
6512
+ options.json,
6513
+ metrics,
6514
+ [
6515
+ `Machine ${metrics.name} in ${metrics.region} from ${metrics.from} to ${metrics.to} (UTC)`,
6516
+ machineMetricsTable(metrics.granularity, metrics.points)
6517
+ ].join("\n")
6518
+ );
6519
+ });
6520
+ }
6393
6521
  function appliesText(name, change) {
6394
6522
  const lines = [];
6395
6523
  if (change.ports !== void 0 || change.sleep_after_seconds !== void 0)
@@ -7247,6 +7375,18 @@ var COMMAND_HELP = {
7247
7375
  arguments: NAME("Machine"),
7248
7376
  defaults: { "--limit": LIMIT_DEFAULT }
7249
7377
  },
7378
+ "tonbo machine metrics": {
7379
+ about: [
7380
+ "Prints the Machine's metrics, one row per UTC hour or day: how long it was awake, its wakes and refused wakes and how long they took (the median and the longest), its average CPU (in cores) and memory while awake, the bytes on its network interface, Tonbo's traffic included, and the bytes it exchanged with the internet. A dash is a step it was never awake in; the current step is still growing.",
7381
+ "Give `--window`, or `--from` and `--to` with `--granularity` (at most 32 days hourly, 92 days daily). `--series` prints only the series it names. It carries no money: `tonbo usage show` says what it cost."
7382
+ ],
7383
+ examples: [
7384
+ "tonbo machine metrics web --window 7d",
7385
+ "tonbo machine metrics web --series cpu_cores_avg,memory_mib_avg"
7386
+ ],
7387
+ arguments: NAME("Machine"),
7388
+ defaults: { "--window": "24h" }
7389
+ },
7250
7390
  "tonbo machine shapes": {
7251
7391
  about: [
7252
7392
  "Lists the shapes a Machine may have, each with its vCPUs, memory, scratch disk, whether it is offered and can suspend, and its list price for an hour at full use, and marks the default."
@@ -7340,6 +7480,14 @@ var COMMAND_HELP = {
7340
7480
  examples: ["tonbo usage series --days 7 --compare"],
7341
7481
  defaults: { "--days": "30" }
7342
7482
  },
7483
+ "tonbo metrics machines": {
7484
+ about: [
7485
+ "Prints the account's Machines per UTC hour or day, summed over every region: how long they were awake, their wakes and refused wakes, and the bytes they exchanged with the internet. Then each Machine's totals over the window, most first by the first series printed. `tonbo machine metrics` prints one Machine's CPU, memory and network too.",
7486
+ "Give `--window`, or `--from` and `--to` with `--granularity` (at most 32 days hourly, 92 days daily)."
7487
+ ],
7488
+ examples: ["tonbo metrics machines --window 30d"],
7489
+ defaults: { "--window": "7d" }
7490
+ },
7343
7491
  "tonbo metrics volumes": {
7344
7492
  about: [
7345
7493
  "Prints what the account's Volumes stored, one line per UTC day of the window: the average bytes their files held that day, compressed, summed over every region, which is what they are billed for. Today, and a day not fully rated yet, is marked `so far`. Then the change between the window's first and last complete days.",
@@ -9253,6 +9401,15 @@ function createProgram(makeDependencies = createDependencies) {
9253
9401
  ).action(
9254
9402
  async (name, options) => machineActivationsCommand(dependencies(), name, options)
9255
9403
  );
9404
+ operationOptions(
9405
+ machine.command("metrics <name>").description("show a Machine's awake time, wakes, CPU, memory and network over time").option("--window <window>", "24h or 7d hourly, 30d or 90d daily; 24h when omitted").option(
9406
+ "--series <series>",
9407
+ "the series to print, comma-separated; every series when omitted"
9408
+ ).option("--granularity <step>", "with --from and --to, hour or day").option("--from <time>", "with --to, the window's start, on a UTC hour or day").option("--to <time>", "with --from, the window's end, exclusive"),
9409
+ "getMachineMetrics"
9410
+ ).action(
9411
+ async (name, options) => machineMetricsCommand(dependencies(), name, options)
9412
+ );
9256
9413
  operationOptions(
9257
9414
  machine.command("shapes").description("list the shapes a Machine may have"),
9258
9415
  "listMachineShapes"
@@ -9320,6 +9477,13 @@ function createProgram(makeDependencies = createDependencies) {
9320
9477
  ).action(
9321
9478
  async (options) => metricsVolumesCommand(dependencies(), options)
9322
9479
  );
9480
+ operationOptions(
9481
+ metrics.command("machines").description("show the account's Machines' awake time, wakes and internet bytes over time").option("--window <window>", "24h or 7d hourly, 30d or 90d daily; 7d when omitted").option(
9482
+ "--series <series>",
9483
+ "the series to print, comma-separated; every series when omitted"
9484
+ ).option("--granularity <step>", "with --from and --to, hour or day").option("--from <time>", "with --to, the window's start, on a UTC hour or day").option("--to <time>", "with --from, the window's end, exclusive"),
9485
+ "getAccountMachineMetrics"
9486
+ ).action(async (options) => metricsMachinesCommand(dependencies(), options));
9323
9487
  const ssh = program.command("ssh").description("open a terminal on a Machine, or run a command there, over SSH").argument("<machine>", "the Machine's name").argument("[command...]", "a command to run instead of a shell, after --").action(async (name, command) => sshCommand(dependencies(), name, command));
9324
9488
  ssh.command("config").description(
9325
9489
  "print the ssh_config block that lets ssh, scp, sftp and Remote-SSH reach every Machine"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tonbo/cli",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "description": "The Tonbo CLI. Compute, disks, databases and streams for AI agents: your agent picks what it needs, sets it up, and knows what it costs, from the command line.",
5
5
  "homepage": "https://tonbo.dev",
6
6
  "bugs": {