LLM Open Telemetry Cost Monitor
A small local collector for token usage emitted by GitHub Copilot through OpenTelemetry. It accepts OTLP/HTTP trace protobuf and JSON, stores token usage metadata in SQLite, and estimates cost with genai-pricing.
The monitor stores trace ID, span ID, timestamp, model, input tokens, cache-read input tokens, cache-creation input tokens, and output tokens. It does not capture prompts or responses.
Requirements
- Python 3.10 or newer
- VS Code and a Copilot Chat version that supports OpenTelemetry export
- Network access for the first pricing lookup, unless
genai-pricingalready has a pricing cache
This project uses the repository-local virtual environment in venv/.
Install
Install the package into an activated virtual environment:
python -m pip install llm-ot-cost-monitor
To work from a repository checkout instead, install its dependencies:
./venv/bin/python -m pip install -r requirements.txt
The dependencies are pinned in requirements.txt.
Configure VS Code
Copilot's OpenTelemetry settings are application-scoped. Amend only ~/Library/Application Support/Code/User/settings.json; do not add them to a workspace .vscode/settings.json file:
{
"github.copilot.chat.otel.enabled": true,
"github.copilot.chat.otel.exporterType": "otlp-http",
"github.copilot.chat.otel.protocol": "http/protobuf",
"github.copilot.chat.otel.otlpEndpoint": "http://127.0.0.1:4318",
"github.copilot.chat.otel.captureContent": false
}
Reload VS Code after changing the settings, then run Copilot requests while the collector is running.
Do not enable content capture unless you explicitly want prompts, responses, or source code included in telemetry. This collector does not require content capture.
Start the collector
Start the local OTLP/HTTP receiver:
llm-monitor serve --db usage.db
The llm-monitor command is installed with the package. From a repository checkout,
you can instead run ./venv/bin/python monitor.py serve --db usage.db.
The receiver listens on 127.0.0.1:4318 and accepts trace exports at:
http://127.0.0.1:4318/v1/traces
To use another database, pass a different path:
llm-monitor serve --db data/usage.db
To change the listening address or port:
llm-monitor serve --host 127.0.0.1 --port 4318 --db usage.db
Keep the collector process running while using Copilot.
View usage and estimated cost
After running Copilot requests, stop or leave the collector running and execute:
llm-monitor summary --db usage.db
The output contains:
model: reported model identifierrequests: number of stored usage spansinput: input tokens reported bygen_ai.usage.input_tokenscache_read: input tokens reported bygen_ai.usage.cache_read.input_tokenscache_creation: input tokens reported bygen_ai.usage.cache_creation.input_tokensoutput: total output tokensestimated_cost_usd: estimated cost in US dollars
Example:
model | requests | input | cache_read | cache_creation | output | estimated_cost_usd
------------+----------+-------+------------+----------------+--------+--------------------
gpt-4o-mini | 2 | 1200 | 800 | 100 | 340 | 0.000248
Costs are calculated by genai-pricing using its pricing table, including provider-specific cache-read and cache-creation rates when available. Unknown models or unavailable prices are shown as n/a; the monitor does not guess rates.
genai-pricing treats input as the total prompt token count and subtracts the two cached-token counts before applying the regular input rate. This matches telemetry payloads where gen_ai.usage.input_tokens includes cached tokens. If an extension emits only non-cached tokens in that attribute, its estimate may undercount regular input because the semantic convention permits either payload interpretation.
Data and duplicate handling
The default database is usage.db in the repository root. SQLite creates it automatically when the collector starts.
Each record is keyed by trace ID and span ID. Repeated exports of the same span are ignored, preventing duplicate cost totals.
The database may contain sensitive operational metadata such as model names and usage volume. Keep it local and do not commit usage.db to source control.
Test
Run the unit tests with the local virtual environment:
env -u PYTHONHOME -u PYTHONPATH ./venv/bin/python -m unittest -v
The tests cover OTLP usage extraction, duplicate span handling, and the genai-pricing API call.
Limitations
- Exact usage depends on Copilot emitting the relevant
gen_ai.usage.*token attributes. - Missing token attributes cannot be reconstructed from trace metadata alone.
- Costs are estimates based on the pricing data available to
genai-pricingand may not match account-specific billing, discounts, or included usage. - The receiver is intentionally local and minimal; it does not provide authentication, a web dashboard, or remote storage.
Release files for llm-ot-cost-monitor 1.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| llm_ot_cost_monitor-1.0.1.tar.gz | 8.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| llm_ot_cost_monitor-1.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 17.7 kB
Release files / llm_ot_cost_monitor-1.0.1.tar.gz
| Download URL | llm_ot_cost_monitor-1.0.1.tar.gz |
|---|---|
| Size | 8.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e1b312794cba233c80a7c8155b9f7e9e54922a9d9dd66d627bb7a3fc58ab929a
|
|
BLAKE2b-256 checksum How to use checksums |
b4718062d2f780b9450a2aa36ac281605ab382624da06a0312c1c9895f74df14
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.12
|
Release files / llm_ot_cost_monitor-1.0.1-py3-none-any.whl
| Download URL | llm_ot_cost_monitor-1.0.1-py3-none-any.whl |
|---|---|
| Size | 8.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a537ff064e55876a0681d2f724278fa2cf5ea612900903042161b8ad3832cb53
|
|
BLAKE2b-256 checksum How to use checksums |
151c76bbc5d0b7914ae84dfc40a96268c0bd7908c0663dac3691c2e593b265cb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.12
|