Skip to content

Add scout billing and scout usage --billing-period backed by the /usage API - #23

Merged
quinnmil merged 6 commits into
mainfrom
8-usage-billing-endpoint
Sep 10, 2026
Merged

quinnmil merged 6 commits into
mainfrom
8-usage-billing-endpoint

Conversation

@quinnmil

@quinnmil quinnmil commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Closes #8

Summary

Consumes the new org-level GET /api/v0/usage endpoint, which reports the exact figures Scout bills against for the current billing period.

  • scout billing — new command showing billing period dates (with days remaining), pricing style, APM transactions (with plan limit + usage bar when the plan has one), active nodes (per-node pricing), errors (when the add-on is enabled), and log bytes (when a logs integration is enabled). Sections the API omits are not shown. Supports --json, --toon, and auto-TOON when piped.
  • scout usage --billing-period — scopes any scout usage mode (--by-day, --by-app, --app) to the exact billing period dates from the API instead of --from/--to, prints the billing period in the header, and prints the server-reported billed total under the table.
  • scout usage columns are now labeled as web transactions (Web Transactions, % of Web, "Total: N web transactions"). The throughput metric the command is built on excludes background jobs, so the old % of Total header was misleading for job-heavy orgs. JSON/TOON field names are unchanged.

Builds on the earlier 8-billing-data branch (original commit preserved) and modernizes it for TOON output and the current usage code.

Examples

scout billing
scout billing --json
scout usage --billing-period
scout usage --by-day --by-app --billing-period

Sample output (illustrative values)

$ scout billing
Billing Period
  Mar 01, 2026 → Apr 01, 2026  (12 days remaining)
  Pricing: per node

APM Transactions
  Total: 12,345,678

Nodes
  Active: 4

Errors
  Count: 42
  Limit: 1,000,000
  [░░░░░░░░░░░░░░░░░░░░] 0.0%

Logs
  Used: 5.0 GB
  Limit: 2.0 TB
  [░░░░░░░░░░░░░░░░░░░░] 0.3%
$ scout usage --billing-period
Billing period: Mar 01, 2026 → Apr 01, 2026

┌────────────┬──────────────────┬──────────┐
│ Name       │ Web Transactions │ % of Web │
├────────────┼──────────────────┼──────────┤
│ Rails App  │ 2,400,000        │ 80.0%    │
│ Django App │ 500,000          │ 16.7%    │
│ Node API   │ 100,000          │ 3.3%     │
└────────────┴──────────────────┴──────────┘

Total: 3,000,000 web transactions
Billing period total (server, web + jobs): 12,345,678 transactions
Per-app totals above count web transactions only; the billed total also includes background jobs.

Why the two totals differ

The per-app numbers come from the app throughput metric, which Queries::Throughput hard-codes to metric_type = 'Controller' (web requests only). The /usage total counts web + background job transactions. Reconciled against a live org by adding per-job throughput × minutes to the web sum: within 0.1% of the server total. The footer labels this explicitly so the gap isn't read as a bug. A per-app breakdown that includes jobs needs an API change; tracked in scoutapp/apm#5686.

Implementation notes

  • /usage is fetched once per invocation and threaded through all usage modes via a small usageTimeframe struct.
  • The current period ends in the future, so the query window is clamped to now while the header still shows the full period. Billing periods exceed 14 days; the existing splitTimeframe chunking handles that.
  • --billing-period is mutually exclusive with --from/--to.
  • Structured output of scout usage --billing-period keeps the same shape as before (per-app list); use scout billing --json for the billing payload.
  • output.FormatBytes gained a TB tier.

Test plan

  • go test -race ./..., go vet, gofmt, golangci-lint run — clean
  • New TestGetOrgUsage (full payload), TestGetOrgUsageMinimal (optional sections nil), TestGetOrgUsageWithLimit
  • Unit tests for renderBillingSummary, renderUsageBar, formatBillingDate, parseBillingTime, daysRemaining, serverTotalLine, FormatBytes TB
  • Live: scout billing (human/JSON/TOON/piped), scout usage --billing-period (default, --by-day, --by-day --by-app), --billing-period --from rejected

🤖 Generated with Claude Code

https://claude.ai/code/session_01BK3fzED9ksTWsvoPfsEwpS

@quinnmil quinnmil linked an issue Sep 9, 2026 that may be closed by this pull request
@quinnmil

quinnmil commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

It would be nice to have per-app job throughput, but this is currently a limitation on the API side. One workaround would be to query /jobs per app per chunk and total the throughput on the client side, but I think it's a bit overly engineered when making the api change is cleaner and more accurate. I'll file an issue on the backend and try and get that API updated to support this better. It's a fairly narrow use case (having jobs take a significant percentage of your total transaction) but a nice to have.

quinnmil and others added 6 commits September 10, 2026 14:07
- `scout billing` now uses structuredOutput so --toon and piped output
  behave like every other command; the report renders one section per
  block the API returned (billing period, APM, nodes, errors, logs)
- `scout usage --billing-period` fetches /usage once, shows the billing
  period in the header, clamps the query window to now, and prints the
  server-reported billed total (web + jobs) under the per-app table so
  the throughput-based calculation can be compared against the exact
  figure
- Add httptest coverage for GetOrgUsage (live payload, minimal payload,
  plan limit) and unit tests for the billing renderers
- Document `scout billing` and `--billing-period` in README and CHANGELOG

Closes #8

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BK3fzED9ksTWsvoPfsEwpS
The logs limit reported by /usage is ~10.7 TB and rendered as
"10736.3 GB" in `scout billing`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BK3fzED9ksTWsvoPfsEwpS
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BK3fzED9ksTWsvoPfsEwpS
The per-app figures in `scout usage` come from the throughput metric,
which counts web requests only, while the billed total from /usage also
includes background jobs. Rename the table headers to "Web Transactions"
and "% of Web", say "web transactions" in the total footers, and explain
the distinction in the command's Long help and the README.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BK3fzED9ksTWsvoPfsEwpS
Replace the live billing period, transaction, node, error and log figures
captured from a real account with round synthetic values so the public
test suite does not carry account data.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BK3fzED9ksTWsvoPfsEwpS
@quinnmil
quinnmil force-pushed the 8-usage-billing-endpoint branch from f6fdb0b to 7119b07 Compare September 10, 2026 21:09
@quinnmil
quinnmil merged commit 5ea7ef5 into main Sep 10, 2026
2 checks passed
@quinnmil
quinnmil deleted the 8-usage-billing-endpoint branch September 10, 2026 21:12
This was referenced Sep 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Usage API Updates

2 participants