Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion skills/apitally-cli/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ All commands are run via `npx @apitally/cli <command>`. For full details, see [r
```

4. **Fetch data** — choose based on the question. Always read the [command reference](references/commands.md) for available options.
- **Metrics** — for questions that can be answered with aggregated metrics: traffic volume, error rates, response time trends, throughput, endpoint comparisons. Use `--group-by` and `--interval` to break down by environment, endpoint, consumer, status code, or time period.
- **Metrics** — for questions that can be answered with aggregated metrics: traffic volume, error rates, response time trends, throughput, distinct consumers, endpoint comparisons. Use `--group-by` and `--interval` to break down by environment, endpoint, consumer, status code, or time period.

```
npx @apitally/cli metrics <app-id> --since "<since>" \
Expand Down
1 change: 1 addition & 0 deletions skills/apitally-cli/references/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ Fetch aggregated metrics for an app. Outputs NDJSON to stdout by default.
| --------------------- | ------- | -------------------------------------- |
| `requests` | integer | Total request count |
| `requests_per_minute` | float | Requests per minute |
| `consumers` | integer | Number of distinct consumers |

@cubic-dev-ai cubic-dev-ai Bot Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The new consumers documentation omits that this distinct count cannot be summed across periods or groups. Users aggregating the DuckDB rows or NDJSON output can therefore double-count consumers; restore the caveat in the command reference, CLI help, and schema reference.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At skills/apitally-cli/references/commands.md, line 115:

<comment>The new `consumers` documentation omits that this distinct count cannot be summed across periods or groups. Users aggregating the DuckDB rows or NDJSON output can therefore double-count consumers; restore the caveat in the command reference, CLI help, and schema reference.</comment>

<file context>
@@ -108,21 +108,21 @@ Fetch aggregated metrics for an app. Outputs NDJSON to stdout by default.
+| --------------------- | ------- | -------------------------------------- |
+| `requests`            | integer | Total request count                    |
+| `requests_per_minute` | float   | Requests per minute                    |
+| `consumers`           | integer | Number of distinct consumers           |
+| `bytes_received`      | integer | Total bytes received                   |
+| `bytes_sent`          | integer | Total bytes sent                       |
</file context>
Fix with cubic

| `bytes_received` | integer | Total bytes received |
| `bytes_sent` | integer | Total bytes sent |
| `client_errors` | integer | 4xx errors (excluding expected errors) |
Expand Down
1 change: 1 addition & 0 deletions skills/apitally-cli/references/duckdb_tables.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ CREATE TABLE metrics (
status_code INTEGER,
requests BIGINT,
requests_per_minute DOUBLE,
consumers BIGINT,
bytes_received BIGINT,
bytes_sent BIGINT,
client_errors BIGINT,
Expand Down
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ enum Command {

/// JSON array or comma-separated list of metric names to include
///
/// Available metrics: requests, requests_per_minute, bytes_received, bytes_sent, client_errors, server_errors, error_rate,
/// response_time_p50, response_time_p75, response_time_p90, response_time_p95, response_time_p99.
/// Available metrics: requests, requests_per_minute, consumers, bytes_received, bytes_sent, client_errors, server_errors,
/// error_rate, response_time_p50, response_time_p75, response_time_p90, response_time_p95, response_time_p99.
#[arg(long)]
metrics: String,

Expand Down
10 changes: 7 additions & 3 deletions src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub(crate) fn ensure_metrics_table(conn: &duckdb::Connection) -> Result<()> {
status_code INTEGER,
requests BIGINT,
requests_per_minute DOUBLE,
consumers BIGINT,
bytes_received BIGINT,
bytes_sent BIGINT,
client_errors BIGINT,
Expand All @@ -33,7 +34,8 @@ pub(crate) fn ensure_metrics_table(conn: &duckdb::Connection) -> Result<()> {
response_time_p99 INTEGER
);
ALTER TABLE metrics ADD COLUMN IF NOT EXISTS response_time_p90 INTEGER;
ALTER TABLE metrics ADD COLUMN IF NOT EXISTS response_time_p99 INTEGER;",
ALTER TABLE metrics ADD COLUMN IF NOT EXISTS response_time_p99 INTEGER;
ALTER TABLE metrics ADD COLUMN IF NOT EXISTS consumers BIGINT;",
)?;
Ok(())
}
Expand Down Expand Up @@ -178,6 +180,7 @@ mod tests {
),
Field::new("method", DataType::Utf8, true),
Field::new("requests", DataType::Int64, false),
Field::new("consumers", DataType::Int64, false),
Field::new("error_rate", DataType::Float64, false),
]));
let batch = RecordBatch::try_new(
Expand All @@ -197,6 +200,7 @@ mod tests {
),
Arc::new(StringArray::from(vec![Some("GET"); ROW_COUNT])),
Arc::new(Int64Array::from(vec![100; ROW_COUNT])),
Arc::new(Int64Array::from(vec![3; ROW_COUNT])),
Arc::new(Float64Array::from(vec![0.05; ROW_COUNT])),
],
)
Expand Down Expand Up @@ -262,7 +266,7 @@ mod tests {
1,
"2025-01-01",
None,
r#"["requests","error_rate"]"#,
r#"["requests","consumers","error_rate"]"#,
Some("hour"),
Some(r#"["method"]"#),
None,
Expand All @@ -280,7 +284,7 @@ mod tests {
let (count, periods, matching): (i64, i64, i64) = conn
.query_row(
"SELECT count(*), count(DISTINCT period_start), count(*) FILTER (
WHERE app_id = 1 AND method = 'GET' AND requests = 100 AND error_rate = 0.05
WHERE app_id = 1 AND method = 'GET' AND requests = 100 AND consumers = 3 AND error_rate = 0.05
AND epoch_ms(period_end) - epoch_ms(period_start) = 3600000
) FROM metrics",
[],
Expand Down
Loading