@tonbo/cli 0.23.0 → 0.24.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 +278 -2
  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",
@@ -1083,6 +1127,22 @@ var managementOperations = {
1083
1127
  "idempotencyKey": false,
1084
1128
  "cli": "tonbo stream activity"
1085
1129
  },
1130
+ "getStreamMetrics": {
1131
+ "method": "GET",
1132
+ "path": "/streams/{name}/metrics",
1133
+ "pathParams": [
1134
+ "name"
1135
+ ],
1136
+ "query": [
1137
+ "series",
1138
+ "window",
1139
+ "granularity",
1140
+ "from",
1141
+ "to"
1142
+ ],
1143
+ "idempotencyKey": false,
1144
+ "cli": "tonbo stream metrics"
1145
+ },
1086
1146
  "listStreamUsage": {
1087
1147
  "method": "GET",
1088
1148
  "path": "/usage/streams",
@@ -2335,10 +2395,19 @@ var ManagementApi = class {
2335
2395
  deleteDatabase(key, name) {
2336
2396
  return this.call("deleteDatabase", key, { params: { name } });
2337
2397
  }
2338
- /** A database's writes per hour or day and its size at each step's end. */
2398
+ /** Deprecated (`getDatabaseMetrics`): a database's writes per hour or day
2399
+ * and its size at each step's end, for `tonbo database activity`. */
2339
2400
  getDatabaseActivity(key, name, query = {}) {
2340
2401
  return this.call("getDatabaseActivity", key, { params: { name }, query });
2341
2402
  }
2403
+ /** A live database's metrics per UTC hour or day. */
2404
+ getDatabaseMetrics(key, name, query = {}) {
2405
+ return this.call("getDatabaseMetrics", key, { params: { name }, query });
2406
+ }
2407
+ /** The account's databases' metrics, each and summed. */
2408
+ getAccountDatabaseMetrics(key, query = {}) {
2409
+ return this.call("getAccountDatabaseMetrics", key, { query });
2410
+ }
2342
2411
  /** The whole usage page: its rows, `other`, prices and checkpoint. */
2343
2412
  listDatabaseUsage(key, page, query = {}) {
2344
2413
  return this.page("listDatabaseUsage", key, page, query);
@@ -2363,10 +2432,19 @@ var ManagementApi = class {
2363
2432
  deleteStream(key, name) {
2364
2433
  return this.call("deleteStream", key, { params: { name } });
2365
2434
  }
2366
- /** A stream's appends per hour or day and its size at each step's end. */
2435
+ /** Deprecated (`getStreamMetrics`): a stream's appends per hour or day and
2436
+ * its size at each step's end, for `tonbo stream activity`. */
2367
2437
  getStreamActivity(key, name, query = {}) {
2368
2438
  return this.call("getStreamActivity", key, { params: { name }, query });
2369
2439
  }
2440
+ /** A live stream's metrics per UTC hour or day. */
2441
+ getStreamMetrics(key, name, query = {}) {
2442
+ return this.call("getStreamMetrics", key, { params: { name }, query });
2443
+ }
2444
+ /** The account's streams' metrics, each and summed. */
2445
+ getAccountStreamMetrics(key, query = {}) {
2446
+ return this.call("getAccountStreamMetrics", key, { query });
2447
+ }
2370
2448
  /** The whole usage page: its rows, `other`, prices and checkpoint. */
2371
2449
  listStreamUsage(key, page, query = {}) {
2372
2450
  return this.page("listStreamUsage", key, page, query);
@@ -5234,6 +5312,128 @@ async function databaseActivityCommand(deps, name, options = {}) {
5234
5312
  );
5235
5313
  printActivity(deps, options.json, activity, "Database");
5236
5314
  }
5315
+ var REGISTRY_COLUMNS = {
5316
+ stored_bytes: ["STORED", (value) => bytes(value)],
5317
+ log_bytes: ["LOG", (value) => bytes(value)],
5318
+ snapshot_bytes: ["SNAPSHOT", (value) => bytes(value)],
5319
+ write_units: ["WRITE UNITS", String],
5320
+ write_bytes: ["WRITTEN", (value) => bytes(value)],
5321
+ records: ["RECORDS", String],
5322
+ reads: ["READS", String],
5323
+ read_bytes: ["READ", (value) => bytes(value)],
5324
+ live_reads: ["LIVE READS", String],
5325
+ live_read_bytes: ["LIVE READ", (value) => bytes(value)],
5326
+ server_write_latency_p50_ms: ["WRITE P50", (value) => `${value} ms`],
5327
+ server_write_latency_p99_ms: ["WRITE P99", (value) => `${value} ms`],
5328
+ server_read_latency_p50_ms: ["READ P50", (value) => `${value} ms`],
5329
+ server_read_latency_p99_ms: ["READ P99", (value) => `${value} ms`]
5330
+ };
5331
+ var SERVER_LATENCY = "Latency is server latency: measured at Tonbo's servers, from request to response headers; your network adds to this.";
5332
+ function registryMetricsTable(granularity, points) {
5333
+ const series = Object.keys(REGISTRY_COLUMNS).filter(
5334
+ (name) => points.some((point) => name in point)
5335
+ );
5336
+ return {
5337
+ latency: series.some((name) => name.startsWith("server_")),
5338
+ text: table(
5339
+ [
5340
+ granularity === "hour" ? "HOUR (UTC)" : "DAY (UTC)",
5341
+ ...series.map((name) => REGISTRY_COLUMNS[name][0])
5342
+ ],
5343
+ points.map((point) => [
5344
+ granularity === "hour" ? point.start.slice(0, 16).replace("T", " ") : point.start.slice(0, 10),
5345
+ ...series.map((name) => {
5346
+ const value = point[name];
5347
+ if (value === null || value === void 0)
5348
+ return Date.parse(point.start) > Date.now() ? "" : "-";
5349
+ return REGISTRY_COLUMNS[name][1](value);
5350
+ })
5351
+ ])
5352
+ )
5353
+ };
5354
+ }
5355
+ function printRegistryMetrics(deps, noun, metrics, options) {
5356
+ const rendered = registryMetricsTable(metrics.granularity, metrics.points);
5357
+ print(
5358
+ deps,
5359
+ options.json,
5360
+ metrics,
5361
+ [
5362
+ `${noun} ${metrics.name} in ${metrics.region} from ${metrics.from} to ${metrics.to} (UTC; metered up to ${when(metrics.as_of, "not yet metered")})`,
5363
+ rendered.text,
5364
+ ...rendered.latency ? [SERVER_LATENCY] : []
5365
+ ].join("\n")
5366
+ );
5367
+ }
5368
+ async function databaseMetricsCommand(deps, name, options = {}) {
5369
+ const metrics = await deps.api.getDatabaseMetrics(
5370
+ await deps.auth.apiKey(),
5371
+ name,
5372
+ metricsQuery(options)
5373
+ );
5374
+ printRegistryMetrics(deps, "Database", metrics, options);
5375
+ }
5376
+ async function streamMetricsCommand(deps, name, options = {}) {
5377
+ const metrics = await deps.api.getStreamMetrics(
5378
+ await deps.auth.apiKey(),
5379
+ name,
5380
+ metricsQuery(options)
5381
+ );
5382
+ printRegistryMetrics(deps, "Stream", metrics, options);
5383
+ }
5384
+ function printAccountRegistryMetrics(deps, noun, metrics, options) {
5385
+ const rendered = registryMetricsTable(metrics.granularity, metrics.total.points);
5386
+ const lines = [
5387
+ `The account's ${noun} from ${metrics.from} to ${metrics.to} (UTC; metered up to ${when(metrics.as_of, "not yet metered")})`,
5388
+ rendered.text
5389
+ ];
5390
+ const counted = ["write_units", "write_bytes", "records", "reads", "read_bytes"].filter((name) => metrics.total.points.some((point) => name in point));
5391
+ const sized = metrics.total.points.some((point) => "stored_bytes" in point);
5392
+ if (metrics.resources.length > 0 && (counted.length > 0 || sized)) {
5393
+ lines.push(
5394
+ "",
5395
+ table(
5396
+ [
5397
+ noun === "databases" ? "DATABASE" : "STREAM",
5398
+ "REGION",
5399
+ ...sized ? ["STORED"] : [],
5400
+ ...counted.map((name) => REGISTRY_COLUMNS[name][0])
5401
+ ],
5402
+ metrics.resources.map((resource) => {
5403
+ const stored = [...resource.points].reverse().find((point) => point.stored_bytes !== null && point.stored_bytes !== void 0);
5404
+ return [
5405
+ resource.name,
5406
+ resource.region,
5407
+ ...sized ? [stored ? bytes(stored.stored_bytes ?? 0) : "-"] : [],
5408
+ ...counted.map(
5409
+ (name) => REGISTRY_COLUMNS[name][1](
5410
+ resource.points.reduce((total, point) => total + (point[name] ?? 0), 0)
5411
+ )
5412
+ )
5413
+ ];
5414
+ })
5415
+ )
5416
+ );
5417
+ }
5418
+ if (rendered.latency) lines.push(SERVER_LATENCY);
5419
+ if (metrics.unavailable_regions.length > 0)
5420
+ lines.push(`Not read: ${metrics.unavailable_regions.join(", ")}`);
5421
+ print(deps, options.json, metrics, lines.join("\n"));
5422
+ }
5423
+ async function metricsDatabasesCommand(deps, options = {}) {
5424
+ const metrics = await deps.api.getAccountDatabaseMetrics(
5425
+ await deps.auth.apiKey(),
5426
+ metricsQuery(options)
5427
+ );
5428
+ printAccountRegistryMetrics(deps, "databases", metrics, options);
5429
+ }
5430
+ async function metricsStreamsCommand(deps, options = {}) {
5431
+ const metrics = await deps.api.getAccountStreamMetrics(
5432
+ await deps.auth.apiKey(),
5433
+ metricsQuery(options)
5434
+ );
5435
+ printAccountRegistryMetrics(deps, "streams", metrics, options);
5436
+ }
5237
5437
  function streamFields(stream) {
5238
5438
  return fields([
5239
5439
  ["Name", stream.name],
@@ -7263,6 +7463,18 @@ var COMMAND_HELP = {
7263
7463
  arguments: NAME("database"),
7264
7464
  defaults: ACTIVITY_DEFAULTS
7265
7465
  },
7466
+ "tonbo database metrics": {
7467
+ about: [
7468
+ "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.",
7469
+ "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."
7470
+ ],
7471
+ examples: [
7472
+ "tonbo database metrics notes --window 7d",
7473
+ "tonbo database metrics notes --series server_write_latency_p50_ms,server_write_latency_p99_ms"
7474
+ ],
7475
+ arguments: NAME("database"),
7476
+ defaults: { "--window": "24h" }
7477
+ },
7266
7478
  "tonbo database usage": {
7267
7479
  about: [
7268
7480
  "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 +7533,18 @@ var COMMAND_HELP = {
7321
7533
  arguments: NAME("stream"),
7322
7534
  defaults: ACTIVITY_DEFAULTS
7323
7535
  },
7536
+ "tonbo stream metrics": {
7537
+ about: [
7538
+ "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.",
7539
+ "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."
7540
+ ],
7541
+ examples: [
7542
+ "tonbo stream metrics events --window 7d",
7543
+ "tonbo stream metrics events --series server_write_latency_p50_ms,server_write_latency_p99_ms"
7544
+ ],
7545
+ arguments: NAME("stream"),
7546
+ defaults: { "--window": "24h" }
7547
+ },
7324
7548
  "tonbo stream usage": {
7325
7549
  about: [
7326
7550
  "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`."
@@ -7681,6 +7905,22 @@ var COMMAND_HELP = {
7681
7905
  examples: ["tonbo metrics machines --window 30d"],
7682
7906
  defaults: { "--window": "7d" }
7683
7907
  },
7908
+ "tonbo metrics databases": {
7909
+ about: [
7910
+ "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.",
7911
+ "Give `--window`, or `--from` and `--to` with `--granularity` (at most 31 days hourly, 92 days daily)."
7912
+ ],
7913
+ examples: ["tonbo metrics databases --window 30d --series stored_bytes,write_units"],
7914
+ defaults: { "--window": "7d" }
7915
+ },
7916
+ "tonbo metrics streams": {
7917
+ about: [
7918
+ "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.",
7919
+ "Give `--window`, or `--from` and `--to` with `--granularity` (at most 31 days hourly, 92 days daily)."
7920
+ ],
7921
+ examples: ["tonbo metrics streams --window 30d --series stored_bytes,write_units"],
7922
+ defaults: { "--window": "7d" }
7923
+ },
7684
7924
  "tonbo metrics volumes": {
7685
7925
  about: [
7686
7926
  "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 +9563,15 @@ function createProgram(makeDependencies = createDependencies) {
9323
9563
  ).action(
9324
9564
  async (name, options) => databaseActivityCommand(dependencies(), name, options)
9325
9565
  );
9566
+ operationOptions(
9567
+ 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(
9568
+ "--series <series>",
9569
+ "the series to print, comma-separated; every series when omitted"
9570
+ ).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"),
9571
+ "getDatabaseMetrics"
9572
+ ).action(
9573
+ async (name, options) => databaseMetricsCommand(dependencies(), name, options)
9574
+ );
9326
9575
  operationOptions(
9327
9576
  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
9577
  "listDatabaseUsage"
@@ -9384,6 +9633,15 @@ function createProgram(makeDependencies = createDependencies) {
9384
9633
  ).action(
9385
9634
  async (name, options) => streamActivityCommand(dependencies(), name, options)
9386
9635
  );
9636
+ operationOptions(
9637
+ 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(
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
+ "getStreamMetrics"
9642
+ ).action(
9643
+ async (name, options) => streamMetricsCommand(dependencies(), name, options)
9644
+ );
9387
9645
  operationOptions(
9388
9646
  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
9647
  "listStreamUsage"
@@ -9692,6 +9950,24 @@ function createProgram(makeDependencies = createDependencies) {
9692
9950
  ).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
9951
  "getAccountMachineMetrics"
9694
9952
  ).action(async (options) => metricsMachinesCommand(dependencies(), options));
9953
+ operationOptions(
9954
+ metrics.command("databases").description(
9955
+ "show the account's databases' writes, reads, stored size and server latency over time"
9956
+ ).option("--window <window>", "24h or 7d hourly, 30d or 90d daily; 7d when omitted").option(
9957
+ "--series <series>",
9958
+ "the series to print, comma-separated; every series when omitted"
9959
+ ).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"),
9960
+ "getAccountDatabaseMetrics"
9961
+ ).action(async (options) => metricsDatabasesCommand(dependencies(), options));
9962
+ operationOptions(
9963
+ metrics.command("streams").description(
9964
+ "show the account's streams' writes, reads, stored size and server latency over time"
9965
+ ).option("--window <window>", "24h or 7d hourly, 30d or 90d daily; 7d when omitted").option(
9966
+ "--series <series>",
9967
+ "the series to print, comma-separated; every series when omitted"
9968
+ ).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"),
9969
+ "getAccountStreamMetrics"
9970
+ ).action(async (options) => metricsStreamsCommand(dependencies(), options));
9695
9971
  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
9972
  ssh.command("config").description(
9697
9973
  "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.24.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": {