@tonbo/cli 0.23.0 → 0.25.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 +361 -4
  2. package/package.json +1 -1
package/dist/bin/tonbo.js CHANGED
@@ -613,6 +613,22 @@ var managementOperations = {
613
613
  "idempotencyKey": false,
614
614
  "cli": "tonbo database activity"
615
615
  },
616
+ "getDatabaseMetrics": {
617
+ "method": "GET",
618
+ "path": "/databases/{name}/metrics",
619
+ "pathParams": [
620
+ "name"
621
+ ],
622
+ "query": [
623
+ "series",
624
+ "window",
625
+ "granularity",
626
+ "from",
627
+ "to"
628
+ ],
629
+ "idempotencyKey": false,
630
+ "cli": "tonbo database metrics"
631
+ },
616
632
  "listDatabaseUsage": {
617
633
  "method": "GET",
618
634
  "path": "/usage/databases",
@@ -752,6 +768,34 @@ var managementOperations = {
752
768
  "idempotencyKey": false,
753
769
  "cli": "tonbo metrics machines"
754
770
  },
771
+ "getAccountDatabaseMetrics": {
772
+ "method": "GET",
773
+ "path": "/metrics/databases",
774
+ "pathParams": [],
775
+ "query": [
776
+ "series",
777
+ "window",
778
+ "granularity",
779
+ "from",
780
+ "to"
781
+ ],
782
+ "idempotencyKey": false,
783
+ "cli": "tonbo metrics databases"
784
+ },
785
+ "getAccountStreamMetrics": {
786
+ "method": "GET",
787
+ "path": "/metrics/streams",
788
+ "pathParams": [],
789
+ "query": [
790
+ "series",
791
+ "window",
792
+ "granularity",
793
+ "from",
794
+ "to"
795
+ ],
796
+ "idempotencyKey": false,
797
+ "cli": "tonbo metrics streams"
798
+ },
755
799
  "listMachineShapes": {
756
800
  "method": "GET",
757
801
  "path": "/machine-shapes",
@@ -1018,6 +1062,22 @@ var managementOperations = {
1018
1062
  "idempotencyKey": false,
1019
1063
  "cli": "tonbo volume delete"
1020
1064
  },
1065
+ "getVolumeNameMetrics": {
1066
+ "method": "GET",
1067
+ "path": "/volumes/{name}/metrics",
1068
+ "pathParams": [
1069
+ "name"
1070
+ ],
1071
+ "query": [
1072
+ "series",
1073
+ "window",
1074
+ "granularity",
1075
+ "from",
1076
+ "to"
1077
+ ],
1078
+ "idempotencyKey": false,
1079
+ "cli": "tonbo volume metrics"
1080
+ },
1021
1081
  "listStreams": {
1022
1082
  "method": "GET",
1023
1083
  "path": "/streams",
@@ -1083,6 +1143,22 @@ var managementOperations = {
1083
1143
  "idempotencyKey": false,
1084
1144
  "cli": "tonbo stream activity"
1085
1145
  },
1146
+ "getStreamMetrics": {
1147
+ "method": "GET",
1148
+ "path": "/streams/{name}/metrics",
1149
+ "pathParams": [
1150
+ "name"
1151
+ ],
1152
+ "query": [
1153
+ "series",
1154
+ "window",
1155
+ "granularity",
1156
+ "from",
1157
+ "to"
1158
+ ],
1159
+ "idempotencyKey": false,
1160
+ "cli": "tonbo stream metrics"
1161
+ },
1086
1162
  "listStreamUsage": {
1087
1163
  "method": "GET",
1088
1164
  "path": "/usage/streams",
@@ -2335,10 +2411,19 @@ var ManagementApi = class {
2335
2411
  deleteDatabase(key, name) {
2336
2412
  return this.call("deleteDatabase", key, { params: { name } });
2337
2413
  }
2338
- /** A database's writes per hour or day and its size at each step's end. */
2414
+ /** Deprecated (`getDatabaseMetrics`): a database's writes per hour or day
2415
+ * and its size at each step's end, for `tonbo database activity`. */
2339
2416
  getDatabaseActivity(key, name, query = {}) {
2340
2417
  return this.call("getDatabaseActivity", key, { params: { name }, query });
2341
2418
  }
2419
+ /** A live database's metrics per UTC hour or day. */
2420
+ getDatabaseMetrics(key, name, query = {}) {
2421
+ return this.call("getDatabaseMetrics", key, { params: { name }, query });
2422
+ }
2423
+ /** The account's databases' metrics, each and summed. */
2424
+ getAccountDatabaseMetrics(key, query = {}) {
2425
+ return this.call("getAccountDatabaseMetrics", key, { query });
2426
+ }
2342
2427
  /** The whole usage page: its rows, `other`, prices and checkpoint. */
2343
2428
  listDatabaseUsage(key, page, query = {}) {
2344
2429
  return this.page("listDatabaseUsage", key, page, query);
@@ -2363,10 +2448,19 @@ var ManagementApi = class {
2363
2448
  deleteStream(key, name) {
2364
2449
  return this.call("deleteStream", key, { params: { name } });
2365
2450
  }
2366
- /** A stream's appends per hour or day and its size at each step's end. */
2451
+ /** Deprecated (`getStreamMetrics`): a stream's appends per hour or day and
2452
+ * its size at each step's end, for `tonbo stream activity`. */
2367
2453
  getStreamActivity(key, name, query = {}) {
2368
2454
  return this.call("getStreamActivity", key, { params: { name }, query });
2369
2455
  }
2456
+ /** A live stream's metrics per UTC hour or day. */
2457
+ getStreamMetrics(key, name, query = {}) {
2458
+ return this.call("getStreamMetrics", key, { params: { name }, query });
2459
+ }
2460
+ /** The account's streams' metrics, each and summed. */
2461
+ getAccountStreamMetrics(key, query = {}) {
2462
+ return this.call("getAccountStreamMetrics", key, { query });
2463
+ }
2370
2464
  /** The whole usage page: its rows, `other`, prices and checkpoint. */
2371
2465
  listStreamUsage(key, page, query = {}) {
2372
2466
  return this.page("listStreamUsage", key, page, query);
@@ -2381,6 +2475,10 @@ var ManagementApi = class {
2381
2475
  getVolumeMetrics(key, query = {}) {
2382
2476
  return this.call("getVolumeMetrics", key, { query });
2383
2477
  }
2478
+ /** One Volume's guest I/O and stored bytes per UTC hour or day. */
2479
+ getVolumeNameMetrics(key, name, query = {}) {
2480
+ return this.call("getVolumeNameMetrics", key, { params: { name }, query });
2481
+ }
2384
2482
  /** The account's writes of yesterday and today, hourly, per lane. */
2385
2483
  getUsageToday(key) {
2386
2484
  return this.call("getUsageToday", key);
@@ -5234,6 +5332,128 @@ async function databaseActivityCommand(deps, name, options = {}) {
5234
5332
  );
5235
5333
  printActivity(deps, options.json, activity, "Database");
5236
5334
  }
5335
+ var REGISTRY_COLUMNS = {
5336
+ stored_bytes: ["STORED", (value) => bytes(value)],
5337
+ log_bytes: ["LOG", (value) => bytes(value)],
5338
+ snapshot_bytes: ["SNAPSHOT", (value) => bytes(value)],
5339
+ write_units: ["WRITE UNITS", String],
5340
+ write_bytes: ["WRITTEN", (value) => bytes(value)],
5341
+ records: ["RECORDS", String],
5342
+ reads: ["READS", String],
5343
+ read_bytes: ["READ", (value) => bytes(value)],
5344
+ live_reads: ["LIVE READS", String],
5345
+ live_read_bytes: ["LIVE READ", (value) => bytes(value)],
5346
+ server_write_latency_p50_ms: ["WRITE P50", (value) => `${value} ms`],
5347
+ server_write_latency_p99_ms: ["WRITE P99", (value) => `${value} ms`],
5348
+ server_read_latency_p50_ms: ["READ P50", (value) => `${value} ms`],
5349
+ server_read_latency_p99_ms: ["READ P99", (value) => `${value} ms`]
5350
+ };
5351
+ var SERVER_LATENCY = "Latency is server latency: measured at Tonbo's servers, from request to response headers; your network adds to this.";
5352
+ function registryMetricsTable(granularity, points) {
5353
+ const series = Object.keys(REGISTRY_COLUMNS).filter(
5354
+ (name) => points.some((point) => name in point)
5355
+ );
5356
+ return {
5357
+ latency: series.some((name) => name.startsWith("server_")),
5358
+ text: table(
5359
+ [
5360
+ granularity === "hour" ? "HOUR (UTC)" : "DAY (UTC)",
5361
+ ...series.map((name) => REGISTRY_COLUMNS[name][0])
5362
+ ],
5363
+ points.map((point) => [
5364
+ granularity === "hour" ? point.start.slice(0, 16).replace("T", " ") : point.start.slice(0, 10),
5365
+ ...series.map((name) => {
5366
+ const value = point[name];
5367
+ if (value === null || value === void 0)
5368
+ return Date.parse(point.start) > Date.now() ? "" : "-";
5369
+ return REGISTRY_COLUMNS[name][1](value);
5370
+ })
5371
+ ])
5372
+ )
5373
+ };
5374
+ }
5375
+ function printRegistryMetrics(deps, noun, metrics, options) {
5376
+ const rendered = registryMetricsTable(metrics.granularity, metrics.points);
5377
+ print(
5378
+ deps,
5379
+ options.json,
5380
+ metrics,
5381
+ [
5382
+ `${noun} ${metrics.name} in ${metrics.region} from ${metrics.from} to ${metrics.to} (UTC; metered up to ${when(metrics.as_of, "not yet metered")})`,
5383
+ rendered.text,
5384
+ ...rendered.latency ? [SERVER_LATENCY] : []
5385
+ ].join("\n")
5386
+ );
5387
+ }
5388
+ async function databaseMetricsCommand(deps, name, options = {}) {
5389
+ const metrics = await deps.api.getDatabaseMetrics(
5390
+ await deps.auth.apiKey(),
5391
+ name,
5392
+ metricsQuery(options)
5393
+ );
5394
+ printRegistryMetrics(deps, "Database", metrics, options);
5395
+ }
5396
+ async function streamMetricsCommand(deps, name, options = {}) {
5397
+ const metrics = await deps.api.getStreamMetrics(
5398
+ await deps.auth.apiKey(),
5399
+ name,
5400
+ metricsQuery(options)
5401
+ );
5402
+ printRegistryMetrics(deps, "Stream", metrics, options);
5403
+ }
5404
+ function printAccountRegistryMetrics(deps, noun, metrics, options) {
5405
+ const rendered = registryMetricsTable(metrics.granularity, metrics.total.points);
5406
+ const lines = [
5407
+ `The account's ${noun} from ${metrics.from} to ${metrics.to} (UTC; metered up to ${when(metrics.as_of, "not yet metered")})`,
5408
+ rendered.text
5409
+ ];
5410
+ const counted = ["write_units", "write_bytes", "records", "reads", "read_bytes"].filter((name) => metrics.total.points.some((point) => name in point));
5411
+ const sized = metrics.total.points.some((point) => "stored_bytes" in point);
5412
+ if (metrics.resources.length > 0 && (counted.length > 0 || sized)) {
5413
+ lines.push(
5414
+ "",
5415
+ table(
5416
+ [
5417
+ noun === "databases" ? "DATABASE" : "STREAM",
5418
+ "REGION",
5419
+ ...sized ? ["STORED"] : [],
5420
+ ...counted.map((name) => REGISTRY_COLUMNS[name][0])
5421
+ ],
5422
+ metrics.resources.map((resource) => {
5423
+ const stored = [...resource.points].reverse().find((point) => point.stored_bytes !== null && point.stored_bytes !== void 0);
5424
+ return [
5425
+ resource.name,
5426
+ resource.region,
5427
+ ...sized ? [stored ? bytes(stored.stored_bytes ?? 0) : "-"] : [],
5428
+ ...counted.map(
5429
+ (name) => REGISTRY_COLUMNS[name][1](
5430
+ resource.points.reduce((total, point) => total + (point[name] ?? 0), 0)
5431
+ )
5432
+ )
5433
+ ];
5434
+ })
5435
+ )
5436
+ );
5437
+ }
5438
+ if (rendered.latency) lines.push(SERVER_LATENCY);
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
+ }
5443
+ async function metricsDatabasesCommand(deps, options = {}) {
5444
+ const metrics = await deps.api.getAccountDatabaseMetrics(
5445
+ await deps.auth.apiKey(),
5446
+ metricsQuery(options)
5447
+ );
5448
+ printAccountRegistryMetrics(deps, "databases", metrics, options);
5449
+ }
5450
+ async function metricsStreamsCommand(deps, options = {}) {
5451
+ const metrics = await deps.api.getAccountStreamMetrics(
5452
+ await deps.auth.apiKey(),
5453
+ metricsQuery(options)
5454
+ );
5455
+ printAccountRegistryMetrics(deps, "streams", metrics, options);
5456
+ }
5237
5457
  function streamFields(stream) {
5238
5458
  return fields([
5239
5459
  ["Name", stream.name],
@@ -5409,14 +5629,14 @@ async function metricsVolumesCommand(deps, options = {}) {
5409
5629
  ["DAY", "STORED", ""],
5410
5630
  points.map((point) => [
5411
5631
  point.start.slice(0, 10),
5412
- bytes(point.stored_bytes),
5632
+ bytes(point.stored_bytes ?? 0),
5413
5633
  point.partial ? "so far" : ""
5414
5634
  ])
5415
5635
  )
5416
5636
  ];
5417
5637
  const complete = points.filter((point) => !point.partial);
5418
5638
  if (complete.length > 1) {
5419
- const change = complete[complete.length - 1].stored_bytes - complete[0].stored_bytes;
5639
+ const change = (complete[complete.length - 1].stored_bytes ?? 0) - (complete[0].stored_bytes ?? 0);
5420
5640
  lines.push(
5421
5641
  `Change over its complete days: ${change < 0 ? "-" : "+"}${bytes(Math.abs(change))}`
5422
5642
  );
@@ -5809,6 +6029,44 @@ async function resolveVolumeBinding(deps, key, spec) {
5809
6029
  region: volume.region
5810
6030
  };
5811
6031
  }
6032
+ var VOLUME_COLUMNS = {
6033
+ stored_bytes: ["STORED", (value) => bytes(value)],
6034
+ read_bytes: ["READ", (value) => bytes(value)],
6035
+ write_bytes: ["WRITTEN", (value) => bytes(value)],
6036
+ read_ops: ["READ OPS", String],
6037
+ write_ops: ["WRITE OPS", String],
6038
+ trim_ops: ["TRIMS", String]
6039
+ };
6040
+ async function volumeMetricsCommand(deps, name, options = {}) {
6041
+ const metrics = await deps.api.getVolumeNameMetrics(
6042
+ await deps.auth.apiKey(),
6043
+ name,
6044
+ metricsQuery(options)
6045
+ );
6046
+ const series = Object.keys(VOLUME_COLUMNS).filter(
6047
+ (key) => metrics.points.some((point) => key in point)
6048
+ );
6049
+ const hourly = metrics.granularity === "hour";
6050
+ print(
6051
+ deps,
6052
+ options.json,
6053
+ metrics,
6054
+ [
6055
+ `Volume ${metrics.name} in ${metrics.region} from ${metrics.from} to ${metrics.to} (UTC)`,
6056
+ table(
6057
+ [hourly ? "HOUR (UTC)" : "DAY (UTC)", ...series.map((key) => VOLUME_COLUMNS[key][0]), ""],
6058
+ metrics.points.map((point) => [
6059
+ hourly ? point.start.slice(0, 16).replace("T", " ") : point.start.slice(0, 10),
6060
+ ...series.map((key) => {
6061
+ const value = point[key];
6062
+ return value === null || value === void 0 ? "-" : VOLUME_COLUMNS[key][1](value);
6063
+ }),
6064
+ point.partial ? "so far" : ""
6065
+ ])
6066
+ )
6067
+ ].join("\n")
6068
+ );
6069
+ }
5812
6070
 
5813
6071
  // src/machine.ts
5814
6072
  var MACHINE_ERROR_HINTS = {
@@ -7263,6 +7521,18 @@ var COMMAND_HELP = {
7263
7521
  arguments: NAME("database"),
7264
7522
  defaults: ACTIVITY_DEFAULTS
7265
7523
  },
7524
+ "tonbo database metrics": {
7525
+ about: [
7526
+ "Prints the database's metrics, one row per UTC hour or day: its stored size at the step's end (the log and snapshots it keeps), the write units, bytes and records written, the successful reads and live (long-poll or SSE) reads and the bytes they streamed, and the median and 99th percentile server latency of its appends and catch-up reads. Server latency is measured at Tonbo's servers, from request to response headers; your network adds to this. A dash is a value not measured (a size before the meter's first sample, a latency with no request); the current step is still growing.",
7527
+ "Give `--window`, or `--from` and `--to` with `--granularity` (at most 31 days hourly, 92 days daily; server latency is kept 8 days hourly). `--series` prints only the series it names. It carries no money: `tonbo database usage` says what it cost."
7528
+ ],
7529
+ examples: [
7530
+ "tonbo database metrics notes --window 7d",
7531
+ "tonbo database metrics notes --series server_write_latency_p50_ms,server_write_latency_p99_ms"
7532
+ ],
7533
+ arguments: NAME("database"),
7534
+ defaults: { "--window": "24h" }
7535
+ },
7266
7536
  "tonbo database usage": {
7267
7537
  about: [
7268
7538
  "Prints each database's usage of one calendar month in UTC at list price, before the monthly allowance and credit: its write units, log and snapshot GiB-months and list value, then the account's other metered usage (its streams and everything else). The charges after allowance and credit are in `tonbo usage show`."
@@ -7321,6 +7591,18 @@ var COMMAND_HELP = {
7321
7591
  arguments: NAME("stream"),
7322
7592
  defaults: ACTIVITY_DEFAULTS
7323
7593
  },
7594
+ "tonbo stream metrics": {
7595
+ about: [
7596
+ "Prints the stream's metrics, one row per UTC hour or day: its stored size at the step's end (the log and snapshots it keeps), the write units, bytes and records written, the successful reads and live (long-poll or SSE) reads and the bytes they streamed, and the median and 99th percentile server latency of its appends and catch-up reads. Server latency is measured at Tonbo's servers, from request to response headers; your network adds to this. A dash is a value not measured (a size before the meter's first sample, a latency with no request); the current step is still growing.",
7597
+ "Give `--window`, or `--from` and `--to` with `--granularity` (at most 31 days hourly, 92 days daily; server latency is kept 8 days hourly). `--series` prints only the series it names. It carries no money: `tonbo stream usage` says what it cost."
7598
+ ],
7599
+ examples: [
7600
+ "tonbo stream metrics events --window 7d",
7601
+ "tonbo stream metrics events --series server_write_latency_p50_ms,server_write_latency_p99_ms"
7602
+ ],
7603
+ arguments: NAME("stream"),
7604
+ defaults: { "--window": "24h" }
7605
+ },
7324
7606
  "tonbo stream usage": {
7325
7607
  about: [
7326
7608
  "Prints each stream's usage of one calendar month in UTC at list price, before the monthly allowance and credit, then the account's other metered usage (its databases and everything else). The charges after allowance and credit are in `tonbo usage show`."
@@ -7642,6 +7924,18 @@ var COMMAND_HELP = {
7642
7924
  examples: ["tonbo volume show data"],
7643
7925
  arguments: NAME("Volume")
7644
7926
  },
7927
+ "tonbo volume metrics": {
7928
+ about: [
7929
+ "Prints the Volume's metrics, one row per UTC hour or day: the bytes and requests its Machine read, wrote and trimmed, as the Volume served them, and what its files held at the step's last sample, compressed. The I/O updates about every 30 seconds while the Volume is attached; the current step is marked `so far`.",
7930
+ "Give `--window` (24h hourly; 7d, 30d or 90d daily, 7d also hourly with `--granularity hour`), or `--from` and `--to` with `--granularity` (at most 8 days hourly, 92 days daily). `--series` prints only the series it names. It carries no money: `tonbo usage show` says what the Volume cost."
7931
+ ],
7932
+ examples: [
7933
+ "tonbo volume metrics data --window 24h",
7934
+ "tonbo volume metrics data --series read_bytes,write_bytes --window 7d"
7935
+ ],
7936
+ arguments: NAME("Volume"),
7937
+ defaults: { "--window": "30d" }
7938
+ },
7645
7939
  "tonbo volume move": {
7646
7940
  about: [
7647
7941
  "Moves the Volume to the Machine `--to`, taking it from the Machine that has it now in one write: the Volume is unbound there (that Machine's ETag changes and it boots without it) and bound to `--to`, which may be awake and gets it at its next boot. The CLI reads both Machines' ETags first, so a Machine changed since is refused, never overwritten. Without `--path` the Volume keeps the path it has now, or stays a whole disk; a whole disk moves only to a Machine on the same image.",
@@ -7681,6 +7975,22 @@ var COMMAND_HELP = {
7681
7975
  examples: ["tonbo metrics machines --window 30d"],
7682
7976
  defaults: { "--window": "7d" }
7683
7977
  },
7978
+ "tonbo metrics databases": {
7979
+ about: [
7980
+ "Prints the account's databases per UTC hour or day, summed over every region, with the same series as `tonbo database metrics`: the total's server latency comes from every database's merged histograms, never an average of percentiles. Server latency is measured at Tonbo's servers, from request to response headers; your network adds to this. Then each database's row over the window: its stored size at the last measured step and its counts summed.",
7981
+ "Give `--window`, or `--from` and `--to` with `--granularity` (at most 31 days hourly, 92 days daily)."
7982
+ ],
7983
+ examples: ["tonbo metrics databases --window 30d --series stored_bytes,write_units"],
7984
+ defaults: { "--window": "7d" }
7985
+ },
7986
+ "tonbo metrics streams": {
7987
+ about: [
7988
+ "Prints the account's streams per UTC hour or day, summed over every region, with the same series as `tonbo stream metrics`: the total's server latency comes from every stream's merged histograms, never an average of percentiles. Server latency is measured at Tonbo's servers, from request to response headers; your network adds to this. Then each stream's row over the window: its stored size at the last measured step and its counts summed.",
7989
+ "Give `--window`, or `--from` and `--to` with `--granularity` (at most 31 days hourly, 92 days daily)."
7990
+ ],
7991
+ examples: ["tonbo metrics streams --window 30d --series stored_bytes,write_units"],
7992
+ defaults: { "--window": "7d" }
7993
+ },
7684
7994
  "tonbo metrics volumes": {
7685
7995
  about: [
7686
7996
  "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.",
@@ -9323,6 +9633,15 @@ function createProgram(makeDependencies = createDependencies) {
9323
9633
  ).action(
9324
9634
  async (name, options) => databaseActivityCommand(dependencies(), name, options)
9325
9635
  );
9636
+ operationOptions(
9637
+ database.command("metrics <name>").description("show a database's writes, reads, stored size and server latency over time").option("--window <window>", "24h or 7d hourly, 30d or 90d daily; 24h when omitted").option(
9638
+ "--series <series>",
9639
+ "the series to print, comma-separated; every series when omitted"
9640
+ ).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"),
9641
+ "getDatabaseMetrics"
9642
+ ).action(
9643
+ async (name, options) => databaseMetricsCommand(dependencies(), name, options)
9644
+ );
9326
9645
  operationOptions(
9327
9646
  database.command("usage").description("each database's usage of one month at list price, before allowance and credit").option("--period <month>", "the calendar month in UTC, as YYYY-MM").option("--sort <order>", "list_value (highest first) or name", parseUsageSort).option("--prefix <prefix>", "only databases whose name starts with this").option("--names <names>", "only these databases, up to 100 names, comma-separated"),
9328
9647
  "listDatabaseUsage"
@@ -9384,6 +9703,15 @@ function createProgram(makeDependencies = createDependencies) {
9384
9703
  ).action(
9385
9704
  async (name, options) => streamActivityCommand(dependencies(), name, options)
9386
9705
  );
9706
+ operationOptions(
9707
+ stream.command("metrics <name>").description("show a stream's writes, reads, stored size and server latency over time").option("--window <window>", "24h or 7d hourly, 30d or 90d daily; 24h when omitted").option(
9708
+ "--series <series>",
9709
+ "the series to print, comma-separated; every series when omitted"
9710
+ ).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"),
9711
+ "getStreamMetrics"
9712
+ ).action(
9713
+ async (name, options) => streamMetricsCommand(dependencies(), name, options)
9714
+ );
9387
9715
  operationOptions(
9388
9716
  stream.command("usage").description("each stream's usage of one month at list price, before allowance and credit").option("--period <month>", "the calendar month in UTC, as YYYY-MM").option("--sort <order>", "list_value (highest first) or name", parseUsageSort).option("--prefix <prefix>", "only streams whose name starts with this").option("--names <names>", "only these streams, up to 100 names, comma-separated"),
9389
9717
  "listStreamUsage"
@@ -9642,6 +9970,17 @@ function createProgram(makeDependencies = createDependencies) {
9642
9970
  ).action(
9643
9971
  async (name, options) => volumeShowCommand(dependencies(), name, options)
9644
9972
  );
9973
+ operationOptions(
9974
+ volume.command("metrics <name>").description(
9975
+ "show what a Volume's Machine read, wrote and trimmed, and what it held, over time"
9976
+ ).option("--window <window>", "24h hourly, or 7d, 30d or 90d daily; 30d when omitted").option(
9977
+ "--series <series>",
9978
+ "the series to print, comma-separated; every series when omitted"
9979
+ ).option("--granularity <step>", "hour or day: with --from and --to, or with --window 7d").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"),
9980
+ "getVolumeNameMetrics"
9981
+ ).action(
9982
+ async (name, options) => volumeMetricsCommand(dependencies(), name, options)
9983
+ );
9645
9984
  operationOptions(
9646
9985
  volume.command("move <name>").description(
9647
9986
  "move a Volume to another Machine of its region, taking it from the asleep Machine that has it in the same write"
@@ -9692,6 +10031,24 @@ function createProgram(makeDependencies = createDependencies) {
9692
10031
  ).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"),
9693
10032
  "getAccountMachineMetrics"
9694
10033
  ).action(async (options) => metricsMachinesCommand(dependencies(), options));
10034
+ operationOptions(
10035
+ metrics.command("databases").description(
10036
+ "show the account's databases' writes, reads, stored size and server latency over time"
10037
+ ).option("--window <window>", "24h or 7d hourly, 30d or 90d daily; 7d when omitted").option(
10038
+ "--series <series>",
10039
+ "the series to print, comma-separated; every series when omitted"
10040
+ ).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"),
10041
+ "getAccountDatabaseMetrics"
10042
+ ).action(async (options) => metricsDatabasesCommand(dependencies(), options));
10043
+ operationOptions(
10044
+ metrics.command("streams").description(
10045
+ "show the account's streams' writes, reads, stored size and server latency over time"
10046
+ ).option("--window <window>", "24h or 7d hourly, 30d or 90d daily; 7d when omitted").option(
10047
+ "--series <series>",
10048
+ "the series to print, comma-separated; every series when omitted"
10049
+ ).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"),
10050
+ "getAccountStreamMetrics"
10051
+ ).action(async (options) => metricsStreamsCommand(dependencies(), options));
9695
10052
  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));
9696
10053
  ssh.command("config").description(
9697
10054
  "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.23.0",
3
+ "version": "0.25.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": {