README
¶
copilot-usage-logger
A standalone HTTPS MITM proxy that intercepts traffic to api.githubcopilot.com
and logs token usage, model calls, and premium request weights — per task and globally.
No mitmproxy or Python required. Written in Go using only the standard library.
Run copilot-usage-logger --summary from any terminal at any time to see accumulated usage:
════════════════════════════════════════════════════════════
COPILOT USAGE SUMMARY — current month: 2026-04
════════════════════════════════════════════════════════════
Current month (2026-04)
────────────────────────────────────────────────────────────
Total API calls: 4
Total tokens: 41455
Cached tokens: 20167
Reasoning tokens: 0
Premium requests (weighted): 2.00
Models:
claude-sonnet-4.6: 2 calls (1x)
gpt-5-mini: 2 calls (0x)
All-time
────────────────────────────────────────────────────────────
Total API calls: 4
Total tokens: 41455
Cached tokens: 20167
Reasoning tokens: 0
Premium requests (weighted): 2.00
Models (all-time):
claude-sonnet-4.6: 2 calls (1x)
gpt-5-mini: 2 calls (0x)
────────────────────────────────────────────────────────────
TASKS
────────────────────────────────────────────────────────────
check-idfdf
────────────────────────────────────────────────────────────
Total API calls: 4
Total tokens: 41455
Cached tokens: 20167
Reasoning tokens: 0
Premium requests (weighted): 2.00
Models:
claude-sonnet-4.6: 2 calls (1x)
gpt-5-mini: 2 calls (0x)
════════════════════════════════════════════════════════════
Stats persist across runs in a JSON store in the config directory.
Use -task <name> when starting the proxy to group calls by feature or session.
How it works
- Listens as an HTTP/HTTPS proxy on a local port.
- On first run, generates a self-signed CA (
ca.crt/ca.key) in the config directory. - When a CONNECT tunnel is opened to
api.githubcopilot.com, it performs a MITM: signs a leaf certificate on the fly and decrypts the TLS stream. - POST responses are parsed for SSE
data:lines containingusagefields. - Token counts, model names, and premium weights are written to log files and stdout.
Quick start
Follow these steps in order. Each step must be completed before the next.
Step 1 — Install the binary
Option A: go install (requires Go 1.21+)
go install github.com/hackmajoris/copilot-usage-logger@latest
The binary lands in $(go env GOPATH)/bin/copilot-usage-logger. Make sure that directory
is on your PATH:
export PATH="$(go env GOPATH)/bin:$PATH"
Option B: Download a pre-built binary
Go to the Releases page and download the archive for your OS and architecture:
| OS | Architecture | File |
|---|---|---|
| macOS | Apple Silicon (M1/M2/M3) | copilot-usage-logger_darwin_arm64.tar.gz |
| macOS | Intel | copilot-usage-logger_darwin_amd64.tar.gz |
| Linux | x86-64 | copilot-usage-logger_linux_amd64.tar.gz |
| Linux | ARM64 | copilot-usage-logger_linux_arm64.tar.gz |
| Windows | x86-64 | copilot-usage-logger_windows_amd64.zip |
| Windows | ARM64 | copilot-usage-logger_windows_arm64.zip |
Extract into your working directory:
# macOS / Linux
tar -xzf copilot-usage-logger_darwin_arm64.tar.gz -C ~/copilot-usage-logger
# Windows (PowerShell)
Expand-Archive copilot-usage-logger_windows_amd64.zip -DestinationPath $HOME\copilot-usage-logger
Verify the download with checksums.txt (included in the release):
sha256sum --check checksums.txt
Option C: Build from source (requires Go 1.21+)
git clone https://github.com/hackmajoris/copilot-usage-logger.git
cd copilot-usage-logger
go build -o copilot-usage-logger copilot-logger.go
Step 2 — Generate and trust the CA certificate
Run the --trust-cert command. It generates ca.crt / ca.key in the
config directory if they don't exist, then installs the certificate
as a trusted root CA in your OS keychain.
copilot-usage-logger --trust-cert
You will be prompted for your password (macOS / Linux) or need to run as Administrator (Windows). The command handles all platforms automatically:
| OS | Method |
|---|---|
| macOS | sudo security add-trusted-cert (password prompt) |
| Linux | sudo update-ca-certificates |
| Windows | certutil -addstore (run terminal as Administrator) |
If you regenerate the certificate (e.g. after deleting ca.crt), re-run
--trust-cert — it removes the old entry before installing the new one.
Keep
ca.keyprivate. Anyone with this file can sign certificates trusted by your machine. Never commit it to version control.
Step 3 — Start the proxy
Open a dedicated terminal window (or a tmux/screen session) and start the proxy. Leave this terminal running for as long as you want to capture usage.
copilot-usage-logger
To label the session so you can group stats later:
copilot-usage-logger -task my-feature
The proxy is now listening on http://127.0.0.1:8080.
Step 4 — Set proxy variables in your working terminal
Open a second terminal (the one you will use to run your editor, CLI tools, or agents) and run:
macOS / Linux
eval "$(copilot-usage-logger --print-proxy)"
PowerShell
copilot-usage-logger --print-proxy | Invoke-Expression
This outputs and applies $env: assignments:
$env:HTTP_PROXY = "http://localhost:8080"
$env:HTTPS_PROXY = "http://localhost:8080"
$env:http_proxy = "http://localhost:8080"
$env:https_proxy = "http://localhost:8080"
This sets HTTP_PROXY, HTTPS_PROXY, http_proxy, and https_proxy in the
current session. If you started the proxy on a custom port pass the same flag:
eval "$(copilot-usage-logger -addr :9090 --print-proxy)"
The variables only apply to the current shell session — re-run the command each time you open a new terminal.
Persistent proxy (set once, works across sessions)
Run --setup-shell once to have the snippet added to your profile automatically:
copilot-usage-logger --setup-shell
This appends a conditional block to ~/.zshrc (zsh), ~/.bashrc (bash), or on Windows to both PowerShell profile paths:
Documents\PowerShell\Microsoft.PowerShell_profile.ps1(PowerShell 7+)Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1(Windows PowerShell 5)
Writing to both ensures the snippet is loaded regardless of which version you open. The proxy variables are set automatically when the proxy is running and silently skipped when it is not — so tools work normally either way.
The snippet it adds looks like this:
macOS / Linux
# copilot-usage-logger proxy
if nc -z -w1 localhost 8080 2>/dev/null; then
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080
export http_proxy=http://localhost:8080
export https_proxy=http://localhost:8080
fi
PowerShell
# copilot-usage-logger proxy
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force
if (Test-NetConnection localhost -Port 8080 -InformationLevel Quiet -WarningAction SilentlyContinue) {
$env:HTTP_PROXY = "http://localhost:8080"
$env:HTTPS_PROXY = "http://localhost:8080"
$env:http_proxy = "http://localhost:8080"
$env:https_proxy = "http://localhost:8080"
}
The command is idempotent — running it again will not add the snippet a second time. Restart your shell (or source ~/.zshrc / . $PROFILE) after running it.
Step 5 — Open GitHub Copilot or OpenCode
With the proxy running and the environment variables set, start your AI tool in the same terminal where you exported the proxy settings:
VS Code with GitHub Copilot
Add to VS Code settings.json (Cmd+Shift+P → "Open User Settings (JSON)"):
{
"http.proxy": "http://127.0.0.1:8080",
"http.proxyStrictSSL": true,
"github.copilot.advanced": {
"debug.useNodeFetcher": true,
"debug.chatOverrideProxyUrl": "http://127.0.0.1:8080"
}
}
Then launch VS Code from the terminal where you exported the proxy variables:
code .
OpenCode (CLI)
OpenCode picks up HTTP_PROXY / HTTPS_PROXY automatically. Just launch it from
the same terminal:
opencode
Any other CLI tool
Any tool that respects the standard HTTP_PROXY / HTTPS_PROXY environment variables
will be captured automatically once those are set.
You should now see log lines appearing in the proxy terminal as Copilot requests are
intercepted. Check the summary log or run copilot-usage-logger --summary from any directory
to view aggregated stats.
Config directory
All persistent files are stored in a single platform-specific directory — no need to
cd anywhere before running copilot-usage-logger --summary or any other command.
| Platform | Default location |
|---|---|
| Linux / macOS | $XDG_CONFIG_HOME/copilot-usage-logger (falls back to ~/.config/copilot-usage-logger) |
| Windows | %APPDATA%\copilot-usage-logger |
Override the base directory by setting $XDG_CONFIG_HOME (Linux/macOS) or %APPDATA%
(Windows), or override individual file paths with the corresponding flags (see
All flags).
Commands
| Command | Description |
|---|---|
copilot-usage-logger |
Start the MITM proxy (default mode) |
copilot-usage-logger --trust-cert |
Generate CA cert (if needed) and install it as a trusted root CA |
copilot-usage-logger --print-proxy |
Print shell commands to set HTTP_PROXY/HTTPS_PROXY (use with eval) |
copilot-usage-logger --setup-shell |
Append a conditional proxy snippet to your shell profile (one-time setup) |
copilot-usage-logger --summary |
Print current-month usage summary and exit |
copilot-usage-logger --prevmonth |
Print previous-month usage summary and exit |
copilot-usage-logger --version |
Print the application version and exit |
copilot-usage-logger --help |
Print help and exit |
Positional subcommands are also accepted for summary, prevmonth, and version
(e.g. copilot-usage-logger summary).
All flags
copilot-usage-logger \
-addr :8080 \
-task my-feature \
-log ~/.config/copilot-usage-logger/copilot_usage.log \
-summary-file ~/.config/copilot-usage-logger/copilot_summary.log \
-data ~/.config/copilot-usage-logger/copilot_data.json \
-cacert ~/.config/copilot-usage-logger/ca.crt \
-cakey ~/.config/copilot-usage-logger/ca.key
| Flag | Default | Description |
|---|---|---|
-addr |
:8080 |
TCP address the MITM proxy listens on (e.g. :8080 or 127.0.0.1:9090) |
-task |
default |
Label used to group token-usage stats in the summary log |
-log |
<config dir>/copilot_usage.log |
Path to the append-only NDJSON file that records every intercepted request |
-summary-file |
<config dir>/copilot_summary.log |
Path to the summary file rewritten on each request |
-data |
<config dir>/copilot_data.json |
Path to the persistent JSON store that accumulates stats across all runs |
-cacert |
<config dir>/ca.crt |
Path to the self-signed CA certificate (created automatically on first run) |
-cakey |
<config dir>/ca.key |
Path to the CA private key (created automatically on first run — keep secret) |
--trust-cert |
— | Generate CA cert (if needed) and install it as a trusted root CA |
--print-proxy |
— | Print shell commands to set HTTP_PROXY/HTTPS_PROXY and exit |
--setup-shell |
— | Append a conditional proxy snippet to your shell profile and exit |
--summary |
— | Print current-month usage summary and exit |
--prevmonth |
— | Print previous-month usage summary and exit |
--version |
— | Print the application version and exit |
<config dir> refers to the platform-specific config directory.
Docker container usage
If you run an agent or tool inside a Docker container and want it to go through the proxy, you need to:
- Copy
ca.crtfrom the config directory into your Docker build context. - Trust it in the image.
- Point the container at the host proxy using
host.docker.internal(Docker Desktop on Mac/Windows) or172.17.0.1(native Linux Docker).
Dockerfile snippet
USER root
COPY ca.crt /usr/local/share/ca-certificates/copilot-usage-logger.crt
RUN apk add --no-cache ca-certificates && update-ca-certificates
The cert must have a .crt extension for update-ca-certificates to pick it up.
Running the container
docker run \
-e SSL_CERT_FILE=/usr/local/share/ca-certificates/copilot-usage-logger.crt \
-e HTTP_PROXY=http://host.docker.internal:8080 \
-e HTTPS_PROXY=http://host.docker.internal:8080 \
-e NO_PROXY=localhost,127.0.0.1 \
your-image
host.docker.internal vs 172.17.0.1
| Environment | Host address to use |
|---|---|
| Docker Desktop (Mac / Windows) | host.docker.internal |
| Native Linux Docker | 172.17.0.1 (default bridge gateway) |
On Docker Desktop for Mac, containers run inside a Linux VM and cannot reach the host
at 172.17.0.1. Use host.docker.internal instead — it always resolves to the
correct host IP.
Verify the proxy is reachable before troubleshooting TLS:
docker run --rm alpine sh -c "apk add --no-cache netcat-openbsd && nc -zv host.docker.internal 8080"
Output files
copilot_usage.log
Append-only log of every intercepted POST request and its parsed response.
[2026-04-05 14:01:02] [my-feature] ► POST https://api.githubcopilot.com/chat/completions
[2026-04-05 14:01:03] [my-feature] ◄ RESPONSE
Model : gpt-4o
Total tokens : 1842
Cached tokens : 512
Reasoning tokens: 0
Premium weight : 0x
copilot_summary.log
Overwritten after every response with the latest aggregated stats. The MTD (month-to-date) section appears first, followed by all-time totals.
============================================================
COPILOT USAGE SUMMARY — current month: 2026-04
============================================================
Current month (2026-04):
────────────────────────────────────────────────────────────
Total API calls : 3
Total tokens : 5210
Cached tokens : 1024
Reasoning tokens : 400
Premium requests : 3.00 (weighted total across all models)
Models used:
- gpt-4o: 2 calls
- claude-sonnet-4-6: 1 calls
All-time:
Total API calls : 47
Total tokens : 91820
...
============================================================
Premium request weighting
GitHub Copilot bills some models as premium requests with a per-model multiplier. The logger tracks the weighted total for each call and accumulates it in the summary.
Multipliers are sourced from the official GitHub Copilot documentation.
| Model | Multiplier (paid plans) | Multiplier (Copilot Free) |
|---|---|---|
| Claude Haiku 4.5 | 0.33 | 1 |
| Claude Opus 4.5 | 3 | Not applicable |
| Claude Opus 4.6 | 3 | Not applicable |
| Claude Opus 4.6 (fast mode, preview) | 30 | Not applicable |
| Claude Sonnet 4 | 1 | Not applicable |
| Claude Sonnet 4.5 | 1 | Not applicable |
| Claude Sonnet 4.6 | 1 | Not applicable |
| Gemini 2.5 Pro | 1 | Not applicable |
| Gemini 3 Flash | 0.33 | Not applicable |
| Gemini 3 Pro | 1 | Not applicable |
| Gemini 3.1 Pro | 1 | Not applicable |
| GPT-4.1 | 0 (included) | 1 |
| GPT-4o | 0 (included) | 1 |
| GPT-5 mini | 0 (included) | 1 |
| GPT-5.1 | 1 | Not applicable |
| GPT-5.1-Codex | 1 | Not applicable |
| GPT-5.1-Codex-Mini | 0.33 | Not applicable |
| GPT-5.1-Codex-Max | 1 | Not applicable |
| GPT-5.2 | 1 | Not applicable |
| GPT-5.2-Codex | 1 | Not applicable |
| GPT-5.3-Codex | 1 | Not applicable |
| GPT-5.4 | 1 | Not applicable |
| GPT-5.4 mini | 0.33 | Not applicable |
| Grok Code Fast 1 | 0.25 | 1 |
| Raptor mini | 0 (included) | 1 |
| Goldeneye | Not applicable | 1 |
Models with multiplier 0 are included in the base plan at no premium cost. Models listed as Not applicable for free plan are not available on the Copilot Free tier. Unknown models default to a multiplier of 1.
The summary log shows the weighted total (sum of per-call multipliers), not a raw request count.
Files generated
| File | Description |
|---|---|
ca.crt |
Self-signed CA certificate — install as trusted root (Step 3) |
ca.key |
CA private key — keep private, never commit |
copiwilot_usage.log |
Append-only per-call log (raw, never overwritten) |
copilot_summary.log |
Human-readable summary, regenerated after every request |
copilot_data.json |
Persistent JSON store — accumulates stats across all runs and tasks |
Add ca.key to your .gitignore:
echo "ca.key" >> .gitignore
Persistent data store
All stats are accumulated in copilot_data.json across runs. The file is structured as:
{
"global": {
"total_calls": 12,
"total_tokens": 48320,
"cached_tokens": 8192,
"reasoning_tokens": 1024,
"premium_requests": 7.66,
"models": { "claude-sonnet-4-6": 9, "gpt-4o": 3 },
"first_seen": "2026-04-05 09:00:00",
"last_seen": "2026-04-05 17:30:00"
},
"tasks": {
"my-feature": { "total_calls": 8, "..." : "..." },
"sprint-42": { "total_calls": 4, "..." : "..." }
},
"monthly": {
"2026-03": { "total_calls": 5, "..." : "..." },
"2026-04": { "total_calls": 7, "..." : "..." }
}
}
The monthly map retains the current month and the previous month only — older
entries are pruned automatically on each flush. This gives you a rolling
month-over-month comparison without unbounded growth of the data file.
Same task name on restart
When you start the proxy with a -task name that already has data, you are prompted:
Task "my-feature" already exists in copilot_data.json:
calls=8 tokens=32100 premium=5.33 last seen=2026-04-05 14:22:01
[A]ggregate into existing task / [R]eset and start fresh / [C]ancel:
- A — new calls are added to the existing totals (default workflow).
- R — the task record is wiped and starts from zero.
- C — the proxy exits without starting.
Requirements
- Go 1.21 or later (only needed for
go installor building from source) - The generated
ca.crttrusted as a root CA on your machine (one-time, Step 3 — run--trust-cert)
Documentation
¶
Overview ¶
copilot-usage-logger — standalone HTTPS MITM proxy that intercepts api.githubcopilot.com traffic and logs token usage.
Usage:
go run copilot-logger.go [-addr :8080] [-task my-feature] [-log copilot_usage.log] [-summary copilot_summary.log]
Then configure your HTTP_PROXY / HTTPS_PROXY (or VS Code / GitHub Copilot extension proxy settings) to point at http://localhost:8080.
On first run the proxy generates a self-signed CA certificate (ca.crt / ca.key). Install ca.crt as a trusted root CA in your OS / browser so that TLS connections to api.githubcopilot.com succeed.