Skip to content

Add GitHub API rate limit consumption analysis to logs, audit, and audit diff commands (#github-api-usage)#24748

Merged
pelikhan merged 3 commits intomainfrom
copilot/update-logs-audit-commands
Apr 5, 2026
Merged

Add GitHub API rate limit consumption analysis to logs, audit, and audit diff commands (#github-api-usage)#24748
pelikhan merged 3 commits intomainfrom
copilot/update-logs-audit-commands

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 5, 2026

Summary

Parses the github_rate_limits.jsonl artifact produced by workflow runs to provide a measure of how much GitHub API quota each agentic workflow consumes. This data is now surfaced in the logs, audit, and audit diff commands.

Changes

New file: pkg/cli/logs_github_rate_limit_usage.go

  • Defines GitHubRateLimitEntry (JSONL line structure), GitHubRateLimitResourceUsage (per-resource stats), and GitHubRateLimitUsage (aggregated summary)
  • analyzeGitHubRateLimits(runDir, verbose) – locates and parses github_rate_limits.jsonl from a run's artifact directory
  • Handles: missing file (returns nil), window resets (falls back to lastUsed), only API snapshot entries (zero TotalRequestsMade), entries without a resource field (bucketed as "core")

pkg/cli/logs_models.go

  • Adds GitHubRateLimitUsage *GitHubRateLimitUsage to ProcessedRun, RunSummary, and DownloadResult

pkg/cli/audit.go

  • Calls analyzeGitHubRateLimits() after artifact download, stores result in ProcessedRun and RunSummary

pkg/cli/audit_report.go

  • Adds GitHubRateLimitUsage *GitHubRateLimitUsage to AuditData; populated from processedRun.GitHubRateLimitUsage

pkg/cli/audit_report_render.go

  • New "🐙 GitHub API Usage" section in renderConsole() (after Token Usage) – shows a summary line (total calls, core consumed/remaining/limit) and a per-resource breakdown table

pkg/cli/logs_orchestrator.go

  • Calls analyzeGitHubRateLimits() in the download worker; propagates through cached-run path and both ProcessedRun and RunSummary construction

pkg/cli/logs_report.go

  • Adds GitHubAPICalls int to RunData (column: "GitHub API Calls")
  • Adds TotalGitHubAPICalls int to LogsSummary (column: "Total GitHub API Calls")
  • Both are omitempty – column is hidden for runs/summaries where no rate-limit data was found

pkg/cli/audit_diff.go

  • Adds GitHubRateLimitDiff struct with per-run API call counts, core quota consumed/remaining/limit, and percentage-change strings
  • Adds GitHubRateLimitDetails *GitHubRateLimitDiff to RunMetricsDiff alongside the existing TokenUsageDetails
  • Adds computeGitHubRateLimitDiff() function; updates computeRunMetricsDiff() to call it
  • Updates loadRunSummaryForDiff() to call analyzeGitHubRateLimits() when building partial summaries for non-cached runs

pkg/cli/audit_diff_render.go

  • Adds renderGitHubRateLimitDiffMarkdownSection() – renders a #### GitHub API Usage markdown table
  • Adds renderGitHubRateLimitDiffPrettySection() – renders a 🐙 GitHub API Usage console table
  • Both are called from the existing markdown and pretty render paths after the token usage details section

New file: pkg/cli/logs_github_rate_limit_usage_test.go

9 unit tests covering:

  • Basic parsing with multiple resources and correct aggregation
  • Empty file returns nil without error
  • Missing resource field defaults to "core"
  • Window reset detection and fallback to lastUsed
  • Only API snapshot entries (zero requests counted)
  • File discovery (root, nested subdirectory, absent)
  • ResourceRows() sort order

pkg/cli/audit_diff_test.go

5 new unit tests covering:

  • computeGitHubRateLimitDiff with both nil, with data, and run1 nil
  • computeRunMetricsDiff with rate limit data and rate limit data alone triggering non-nil result

Example output

gh aw audit – new section:

────────────────────────────────────────────────────────────
🐙 GitHub API Usage
────────────────────────────────────────────────────────────

  Total GitHub API calls: 47  |  Core quota consumed: 47 / 5,000  (remaining: 4,953)

  Resource   API Calls   Quota Consumed   Remaining   Limit
  ─────────────────────────────────────────────────────────
  core       45          45               4,953        5,000
  search     2           2                28           30

gh aw logs – new column in run table:

  Run ID   Workflow    Status   Tokens   GitHub API Calls   ...
  ──────────────────────────────────────────────────────────
  123456   my-workflow success  12,340   47

gh aw audit diff – new section in run metrics diff:

────────────────────────────────────────────────────────────
🐙 GitHub API Usage
────────────────────────────────────────────────────────────

  Metric               Run #100   Run #200   Change
  ────────────────────────────────────────────────
  Total API calls      40         60         +50%
  Core quota consumed  40         60         +50%
  Core remaining       4960       4940       —
  Core limit           5000       5000       —

Copilot AI and others added 2 commits April 5, 2026 15:27
Copilot AI requested a review from pelikhan April 5, 2026 15:29
@pelikhan pelikhan marked this pull request as ready for review April 5, 2026 15:30
Copilot AI review requested due to automatic review settings April 5, 2026 15:30
@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Apr 5, 2026

@copilot add support in audit diff

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds GitHub API rate-limit usage analysis by parsing the github_rate_limits.jsonl artifact and surfacing aggregated API call/quota consumption metrics in both gh aw logs and gh aw audit outputs.

Changes:

  • Introduces parsing/aggregation logic for github_rate_limits.jsonl and unit tests for key scenarios.
  • Propagates GitHubRateLimitUsage through logs/audit processing models and download pipelines (including cached-run paths).
  • Renders the new audit console section and adds a new logs table column + summary total for GitHub API calls.
Show a summary per file
File Description
pkg/cli/logs_github_rate_limit_usage.go Implements file discovery + JSONL parsing and aggregates per-resource and core GitHub API usage metrics.
pkg/cli/logs_github_rate_limit_usage_test.go Adds unit tests covering parsing, file discovery, window reset handling, and row sorting.
pkg/cli/logs_models.go Plumbs GitHubRateLimitUsage through ProcessedRun, RunSummary, and DownloadResult.
pkg/cli/logs_orchestrator.go Runs usage analysis after artifact download and propagates into processed/cached run summaries.
pkg/cli/logs_report.go Adds per-run and total “GitHub API Calls” fields/columns to the logs report output.
pkg/cli/audit.go Runs usage analysis during audit processing and stores it on processed run + summary.
pkg/cli/audit_report.go Adds GitHubRateLimitUsage to AuditData and populates it from ProcessedRun.
pkg/cli/audit_report_render.go Renders a new “GitHub API Usage” console section with summary + per-resource breakdown.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 8/8 changed files
  • Comments generated: 5

Comment on lines +214 to +223
var consumed int
if state.requestsMade > 0 {
diff := state.lastUsed - state.firstUsed
if diff >= 0 {
consumed = diff
} else {
// Window reset mid-run; use lastUsed as a lower-bound estimate
consumed = state.lastUsed
}
}
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

QuotaConsumed is undercounted: with one response_headers entry, diff := lastUsed - firstUsed yields 0 even though at least 1 request was made. Since x-ratelimit-used reflects the post-request value, the per-window delta should include the first observed request (e.g., max(0, lastUsed-firstUsed)+1 when requestsMade>0), and tests should cover the single-request case.

Copilot uses AI. Check for mistakes.

// Sort resources for deterministic output
sort.Slice(usage.Resources, func(i, j int) bool {
return usage.Resources[i].RequestsMade > usage.Resources[j].RequestsMade
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

The sort comparator only considers RequestsMade. When counts are equal (common for snapshot-only files where all RequestsMade are 0), the resulting order is nondeterministic due to Go map iteration + sort.Slice being unstable, despite the comment about deterministic output. Add a secondary tie-breaker (e.g., Resource name) here, and mirror it in ResourceRows() for consistent console/JSON ordering.

Suggested change
return usage.Resources[i].RequestsMade > usage.Resources[j].RequestsMade
if usage.Resources[i].RequestsMade != usage.Resources[j].RequestsMade {
return usage.Resources[i].RequestsMade > usage.Resources[j].RequestsMade
}
return usage.Resources[i].Resource < usage.Resources[j].Resource

Copilot uses AI. Check for mistakes.
Comment on lines 69 to 73
TotalSafeItems int `json:"total_safe_items" console:"header:Total Safe Items"`
TotalEpisodes int `json:"total_episodes" console:"header:Total Episodes"`
HighConfidenceEpisodes int `json:"high_confidence_episodes" console:"header:High Confidence Episodes"`
TotalGitHubAPICalls int `json:"total_github_api_calls,omitempty" console:"header:Total GitHub API Calls,format:number,omitempty"`
}
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

With omitempty, this field is omitted (and the console column hidden) whenever the total is 0. That makes it indistinguishable from “no rate-limit artifact found”, and it contradicts the PR description for the snapshot-only case (rate-limit data found but TotalRequestsMade == 0). Consider using a pointer/nullable type (or a separate “data present” flag) so you can render 0 when data exists while still omitting when absent.

Copilot uses AI. Check for mistakes.
Comment on lines 116 to 120
AgenticAssessments []AgenticAssessment `json:"agentic_assessments,omitempty" console:"-"`
AwContext *AwContext `json:"context,omitempty" console:"-"` // aw_context data from aw_info.json
TokenUsageSummary *TokenUsageSummary `json:"token_usage_summary,omitempty" console:"-"` // Token usage from firewall proxy
AwContext *AwContext `json:"context,omitempty" console:"-"` // aw_context data from aw_info.json
TokenUsageSummary *TokenUsageSummary `json:"token_usage_summary,omitempty" console:"-"` // Token usage from firewall proxy
GitHubAPICalls int `json:"github_api_calls,omitempty" console:"header:GitHub API Calls,format:number,omitempty"` // GitHub API calls made during the run
}
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

Same issue as the summary: omitempty on an int will hide the per-run column when the value is 0, even if GitHubRateLimitUsage was present but indicated zero calls (snapshot-only). If the intent is “hide only when artifact missing”, consider making this a *int and setting it only when usage is non-nil, or rendering a sentinel/default value (e.g., N/A) for missing data.

Copilot uses AI. Check for mistakes.
Comment on lines +1119 to +1123
// Per-resource breakdown table (only when there are multiple resources or non-core resources)
rows := usage.ResourceRows()
if len(rows) == 0 {
return
}
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

The comment says the per-resource breakdown table is shown “only when there are multiple resources or non-core resources”, but the code renders it whenever len(rows) > 0 (including a single core row). Either adjust the condition to match the comment, or update the comment to reflect the current behavior.

Copilot uses AI. Check for mistakes.
@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Apr 5, 2026

@copilot review comments

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 5, 2026

@copilot add support in audit diff

Done in commit 450c686. Added GitHubRateLimitDiff to the audit diff output with:

  • computeGitHubRateLimitDiff() – diffs GitHubRateLimitUsage between two runs (total API calls, core consumed/remaining/limit with % change)
  • RunMetricsDiff.GitHubRateLimitDetails – nested field alongside existing TokenUsageDetails
  • Updated loadRunSummaryForDiff() to call analyzeGitHubRateLimits() when building partial summaries (non-cached runs)
  • Renders in both pretty (table with 🐙 GitHub API Usage header) and markdown formats (#### GitHub API Usage table)

Copilot AI changed the title Add GitHub API rate limit consumption analysis to logs and audit commands (#github-api-usage) Add GitHub API rate limit consumption analysis to logs, audit, and audit diff commands (#github-api-usage) Apr 5, 2026
@pelikhan pelikhan merged commit 9a78bc2 into main Apr 5, 2026
1 check failed
@pelikhan pelikhan deleted the copilot/update-logs-audit-commands branch April 5, 2026 15:48
Copilot stopped work on behalf of pelikhan due to an error April 5, 2026 15:49
github-actions bot added a commit that referenced this pull request Apr 5, 2026
- Add git, copilot_spaces, github_support_docs_search toolsets to github-tools.md (from PR #24729, v2.2 toolsets mapping)
- Add GitHub API rate limit consumption to audit report sections, cross-run logs report, and audit diff output (from PR #24748)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

3 participants