Skip to main content

Parse LLM API response logs (Anthropic, OpenAI, Google) and generate token / cost reports. Supports a --alert-at budget alarm that exits non-zero when total cost exceeds a threshold. No framework adoption required.

Project description

llm-usage-report

CI PyPI Python License: MIT

Parse LLM API response logs (Anthropic, OpenAI, Google) and generate a readable usage + cost report. Works on raw JSONL you already have sitting in log files — no framework adoption, no SDK wrapping, no proxy.

Install

pip install llm-usage-report

What it does

Point it at one or more JSONL files (or stdin), it reads the usage / usageMetadata fields from each line, normalizes them, and prints a table like:

model              requests  input   output  cache_read  cache_new  cost (USD)
-----------------  --------  ------  ------  ----------  ---------  ----------
claude-opus-4-5           8  120000   35000       20000      50000      $4.57
claude-sonnet-4-5        42   88000   32000           0          0      $0.75
gpt-4o                   15   45000   12000           0          0      $0.23
gemini-2.5-pro            6    8000    3000           0          0      $0.05
-----------------  --------  ------  ------  ----------  ---------  ----------
TOTAL                    71  261000   82000       20000      50000      $5.60

Supported providers

Provider Shape it understands
Anthropic {"type":"message","model":"claude-...","usage":{"input_tokens":..., "output_tokens":..., "cache_read_input_tokens":..., "cache_creation_input_tokens":...}}
OpenAI {"object":"chat.completion","model":"gpt-...","usage":{"prompt_tokens":..., "completion_tokens":...}} and the newer response object
Google Gemini {"modelVersion":"gemini-...","usageMetadata":{"promptTokenCount":..., "candidatesTokenCount":..., "cachedContentTokenCount":...}}

Each line in your JSONL is expected to be a full API response. The parser is lenient: unparseable lines are skipped silently so you can point it at noisy log files.

CLI

# Point at a file
llm-usage-report path/to/api-responses.jsonl

# Or a directory (scans recursively for *.jsonl)
llm-usage-report ./logs/

# Or pipe from stdin
tail -f logs/api.jsonl | llm-usage-report -

# Group by day, provider, project, or user
llm-usage-report logs/ --group-by day
llm-usage-report logs/ --group-by provider

# Machine-readable output
llm-usage-report logs/ --format json > report.json
llm-usage-report logs/ --format csv > report.csv

Tagging requests with project / user

Include optional project and user fields at the top level of each log line:

{"type":"message","model":"claude-sonnet-4-5","usage":{"input_tokens":100,"output_tokens":50},"project":"search","user":"alice"}

Then group by them:

llm-usage-report logs/ --group-by project
llm-usage-report logs/ --group-by user

Pricing

Prices are embedded as a dated snapshot (see src/llm_usage_report/pricing.py). They will drift — provider prices change. Two ways to override:

# Via CLI flag
llm-usage-report logs/ --pricing ./my-pricing.json

# Or via environment variable
export LLM_USAGE_REPORT_PRICING=./my-pricing.json
llm-usage-report logs/

The override file has the same shape as the built-in table:

{
  "claude-sonnet-4-5": {"input": 3.00, "output": 15.00, "cache_read": 0.30, "cache_creation": 3.75},
  "gpt-5": {"input": 15.00, "output": 60.00}
}

Rates are USD per 1 million tokens. Unknown models contribute zero cost (token totals still aggregate correctly).

Library API

from llm_usage_report import parse_stream, aggregate, GroupKey
from llm_usage_report.formatters import format_table

with open("logs/api.jsonl") as f:
    records = list(parse_stream(f))

summaries = aggregate(records, group_by=GroupKey.MODEL)
print(format_table(summaries, group_label="model"))

Philosophy

This package does one thing: it reads logs you already have and tells you what they cost. It does not:

  • proxy your API calls (use LiteLLM if you want that)
  • require adopting an SDK (use Braintrust / Helicone / LangSmith if you want full observability)
  • pretend to know the future (pricing is a snapshot; override it when you need to)

If you outgrow this, good — that's what full LLM observability platforms are for. This is for the team that's logging to a file today and needs an answer before end of sprint.

License

MIT.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

llm_usage_report-0.1.1.tar.gz (12.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

llm_usage_report-0.1.1-py3-none-any.whl (13.1 kB view details)

Uploaded Python 3

File details

Details for the file llm_usage_report-0.1.1.tar.gz.

File metadata

  • Download URL: llm_usage_report-0.1.1.tar.gz
  • Upload date:
  • Size: 12.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for llm_usage_report-0.1.1.tar.gz
Algorithm Hash digest
SHA256 37a7647f89456be5cc0593bc88d914520618184a1383979ca745d9c05fe15de4
MD5 c3c43725e1b5bd698656ceac87c0f59d
BLAKE2b-256 7c9f049f82564602abb71e5cbd725f3d993c2e79a76b1db99341961e9a267675

See more details on using hashes here.

Provenance

The following attestation bundles were made for llm_usage_report-0.1.1.tar.gz:

Publisher: publish.yml on MukundaKatta/llm-usage-report

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file llm_usage_report-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for llm_usage_report-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6e30ac908e06fbbf041053dcb0bb6f77670710742e1fcf23fe6fabdecd44062c
MD5 009efd11b21c14d218557039a18bfcb4
BLAKE2b-256 5ea19f057baa0180a55f6359fe8abdc07ee75810a635dc569aa3e041e86ff8e3

See more details on using hashes here.

Provenance

The following attestation bundles were made for llm_usage_report-0.1.1-py3-none-any.whl:

Publisher: publish.yml on MukundaKatta/llm-usage-report

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page