A previous release had provenance metadata, but this release does not. View details.
Token Usage Metrics
A production-ready, async-first Python package for tracking LLM and embedding token usage with multi-backend support (Redis, PostgreSQL/Supabase, MongoDB). It provides lifetime retention, project-based deletion, rich aggregations, and non-blocking async operations for high-throughput environments.
Features
- Multi-Backend Support: Redis, PostgreSQL, Supabase, and MongoDB backends with a unified API.
- Rich Aggregations: Daily summaries, project/type grouping, and time-series for dashboards.
- Async-First: Non-blocking operations with background flushing and circuit breakers.
- Lifetime Retention: No enforced TTL; explicit project-based deletion with date ranges.
- Flexible Queries: Raw event fetching with filters and cursor-based pagination.
- Production-Ready: Structured logging, retry logic, graceful fallbacks, and health checks.
Documentation
1. Quick Start and Setup
Installation
Install with Redis support (recommended for getting started):
uv add token-usage-metrics[redis]
Other installation options:
# All backends
uv add token-usage-metrics[all]
# PostgreSQL only
uv add token-usage-metrics[postgres]
# MongoDB only
uv add token-usage-metrics[mongo]
# Supabase only
uv add token-usage-metrics[supabase]
Basic Example with Redis
- Start Redis (using Docker):
docker run -d -p 6379:6379 redis:7-alpine
- Create a simple script:
import asyncio
from token_usage_metrics import TokenUsageClient, Settings
async def main():
# Initialize client with Redis
settings = Settings(backend="redis", redis_url="redis://localhost:6379/0")
client = await TokenUsageClient.from_settings(settings)
# Log token usage
await client.log("my_app", "chat", input_tokens=100, output_tokens=50)
# Query events
events, _ = await client.query(project="my_app")
print(f"Found {len(events)} events")
await client.aclose()
asyncio.run(main())
- Run it:
python your_script.py
# Output: Found 1 events
2. Supported Databases
2.1 Redis
Docker:
docker run -d -p 6379:6379 redis:7-alpine
Schema: Hash-per-event + day-partitioned ZSETs + daily aggregate hashes. Optimized for fast writes and efficient date-range queries.
Performance: ~10k writes/sec (pipelined batches), ~5k reads/sec (optimized ZSETs)
2.2 PostgreSQL
Docker:
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=pass -e POSTGRES_DB=token_usage postgres:16-alpine
Schema: usage_events table + daily_aggregates table with indexes on (project, timestamp) and (type, timestamp).
Performance: ~2k writes/sec (bulk inserts), ~10k reads/sec (indexed queries)
Configuration:
from token_usage_metrics import Settings
settings = Settings(
backend="postgres",
postgres_dsn="postgresql://user:pass@localhost:5432/token_usage"
)
2.3 MongoDB
Docker:
docker run -d -p 27017:27017 mongo:7
Schema: usage_events collection + daily_aggregates collection with compound indexes.
Performance: ~5k writes/sec (batched inserts), ~8k reads/sec (indexed scans)
Configuration:
from token_usage_metrics import Settings
settings = Settings(
backend="mongodb",
mongodb_url="mongodb://localhost:27017",
mongodb_database="token_usage"
)
2.4 Supabase
Supabase exposes the same Postgres-compatible usage_events and daily_aggregates schema.
Configuration:
export TUM_BACKEND=supabase
export TUM_SUPABASE_DSN="postgresql://postgres:service_role_key@db.supabase.co:5432/postgres"
3. Configuration
Configure via environment variables (prefix: TUM_) or the Settings object:
from token_usage_metrics import Settings
settings = Settings(
backend="redis", # redis | postgres | supabase | mongodb
redis_url="redis://localhost:6379/0",
redis_pool_size=10,
postgres_dsn="postgresql://user:pass@localhost:5432/token_usage",
supabase_dsn="postgresql://postgres:service_role_key@db.supabase.co:5432/postgres",
mongodb_url="mongodb://localhost:27017",
mongodb_database="token_usage",
buffer_size=1000,
flush_interval=1.0, # seconds
flush_batch_size=200,
max_retries=3,
circuit_breaker_threshold=5,
)
Or via .env:
TUM_BACKEND=redis
TUM_REDIS_URL=redis://localhost:6379/0
TUM_BUFFER_SIZE=1000
TUM_FLUSH_INTERVAL=1.0
4. API Reference
Methods and Models
TokenUsageClient
Main client for interacting with the token usage tracking system.
Initialization:
client = await TokenUsageClient.from_settings(settings)
Logging Events
# Single event (async, non-blocking)
await client.log(
project: str,
request_type: str,
input_tokens: int,
output_tokens: int,
metadata: dict | None = None
)
# Multiple events
await client.log_many(events: list[UsageEvent])
# Force flush pending events
flushed_count = await client.flush(timeout: float = 5.0)
Arguments:
project(str): Project identifierrequest_type(str): Type of request (e.g., "chat", "embedding")input_tokens(int): Number of input tokensoutput_tokens(int): Number of output tokensmetadata(dict, optional): Additional context metadata
Fetching Raw Events
from token_usage_metrics import UsageFilter
events, next_cursor = await client.fetch_raw(
filters: UsageFilter
)
UsageFilter Arguments:
project_name(str, optional): Filter by projectrequest_type(str, optional): Filter by request typetime_from(datetime, optional): Start timetime_to(datetime, optional): End timelimit(int): Maximum number of events (default: 100)cursor(str, optional): Pagination cursor
Aggregations & Summaries
from token_usage_metrics import AggregateSpec, AggregateMetric
spec = AggregateSpec(
metrics={
AggregateMetric.SUM_TOTAL,
AggregateMetric.COUNT_REQUESTS,
AggregateMetric.AVG_TOTAL_PER_REQUEST
}
)
daily_buckets = await client.summary_by_day(spec, filters)
AggregateMetric Options:
SUM_TOTAL: Sum of all tokensCOUNT_REQUESTS: Number of requestsAVG_TOTAL_PER_REQUEST: Average tokens per requestSUM_INPUT_TOKENS: Sum of input tokensSUM_OUTPUT_TOKENS: Sum of output tokens
Deleting Project Data
from token_usage_metrics import DeleteOptions
options = DeleteOptions(
project_name="my_app",
time_from=datetime(...),
time_to=datetime(...),
include_aggregates=True,
simulate=True
)
result = await client.delete_project(options)
DeleteOptions Arguments:
project_name(str): Project to deletetime_from(datetime): Start of deletion rangetime_to(datetime): End of deletion rangeinclude_aggregates(bool): Also delete aggregatessimulate(bool): Dry run without actual deletion
5. Architecture
┌─────────────────────────────────────────────────────────────┐
│ TokenUsageClient │
│ (Async API: log, fetch_raw, summary_*, delete_project) │
└────────────────┬────────────────────────────────────────────┘
│
┌────────┴────────┐
│ AsyncEventQueue │ (Background flusher, circuit breaker)
└────────┬─────────┘
│
┌───────────┴───────────┐
│ Backend Interface │
└───────────┬───────────┘
│
┌────────────┼────────────┼────────────┐
│ │ │ │
┌───▼────┐ ┌───▼─────┐ ┌───▼────┐ ┌──▼──────┐
│ Redis │ │Postgres │ │Supabase │ │ MongoDB │
└────────┘ └─────────┘ └─────────┘ └─────────┘
- Async Queue: Buffers events in memory, flushes batches periodically.
- Circuit Breaker: Auto-recovery when backend is unhealthy.
- Retry Logic: Exponential backoff with jitter for transient errors.
- Lifetime Retention: No enforced TTL (configurable per-backend if needed).
6. Testing
Run tests with pytest:
# Run all tests
uv run pytest
# Run with coverage
uv run pytest --cov=token_usage_metrics
# Run a specific test
uv run pytest tests/test_redis_backend.py -v
7. Development
# Install dev dependencies
uv add --dev ruff mypy pytest pytest-asyncio fakeredis
# Lint and format
uv run ruff check .
uv run ruff format .
# Type checking
uv run mypy token_usage_metrics
8. Performance
- Redis: ~10k writes/sec (pipelined batches), ~5k reads/sec (optimized ZSETs)
- Postgres: ~2k writes/sec (bulk inserts), ~10k reads/sec (indexed queries)
- MongoDB: ~5k writes/sec (batched inserts), ~8k reads/sec (indexed scans)
Benchmarks on single-instance deployments. Scale horizontally for higher throughput.
9. Contribution Guidelines
We welcome contributions! Please follow these guidelines to ensure a smooth process:
Getting Started
- Fork the Repository: Click the fork button on GitHub.
- Clone Your Fork:
git clone https://github.com/your-username/token-usage-metrics.git cd token-usage-metrics
- Create a Branch:
git checkout -b feature/your-feature-name
Development Setup
- Install Dependencies:
uv sync uv add --dev ruff mypy pytest pytest-asyncio fakeredis
- Run Tests:
uv run pytest
Code Standards
- Format Code: Use ruff for formatting
uv run ruff format .
- Lint Code: Check for issues
uv run ruff check .
- Type Checking: Ensure type safety
uv run mypy token_usage_metrics
Submitting Changes
- Commit Your Changes:
git add . git commit -m "feat: add your feature description"
- Push to Your Fork:
git push origin feature/your-feature-name
- Open a Pull Request: Go to GitHub and create a PR with a clear description of your changes.
PR Guidelines
- Ensure all tests pass:
uv run pytest - Include test coverage for new features
- Update documentation if needed
- Follow the commit message format:
feat:,fix:,docs:,test:, etc.
Reporting Issues
Please use GitHub Issues to report bugs or suggest features. Include:
- Clear description of the issue
- Steps to reproduce (for bugs)
- Expected vs. actual behavior
- Environment details (Python version, backend used, etc.)
Thank you for contributing! 🎉
Built with ❤️ by lazzyms
Metadata
Release files for token-usage-metrics 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Loss of provenance
These files do not have provenance metadata, despite files in a prior release including this data.
We recommend further investigation before installing these files. View details.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| token_usage_metrics-0.1.2.tar.gz | 112.8 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| token_usage_metrics-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 172.3 kB
Release files / token_usage_metrics-0.1.2.tar.gz
Loss of provenance
This file belongs to a release without provenance metadata, despite a prior release including this data.
We recommend further investigation before installing this file. View details.
| Download URL | token_usage_metrics-0.1.2.tar.gz |
|---|---|
| Size | 112.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2c1b173152515271a80499dc36b1b97cee2b39d12ff0dd8f7c7fc53ee3713eff
|
|
BLAKE2b-256 checksum How to use checksums |
ce19e0e1de57c2804b70d3b14b02f25bb13ecce0ffccef61ad87809808c28f7a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.7.11
|
Release files / token_usage_metrics-0.1.2-py3-none-any.whl
Loss of provenance
This file belongs to a release without provenance metadata, despite a prior release including this data.
We recommend further investigation before installing this file. View details.
| Download URL | token_usage_metrics-0.1.2-py3-none-any.whl |
|---|---|
| Size | 59.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6170c83b0e2744c8a2ee32108e062ae2841b10a32bd61ad29567366c8b4e0840
|
|
BLAKE2b-256 checksum How to use checksums |
25a685589562273492a96c22ee14d320d919caf1d03022d1424f71d45c184fdb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.7.11
|
Security for token-usage-metrics 0.1.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Loss of provenance
A previous release of these files had provenance metadata, but this release does not.
While this could reflect a routine change by the project maintainers, it may also indicate that the release files have been compromised.
Release comparison
- Removed 0.1.1 2 files With provenance
- Added 0.1.2 2 files Without provenance
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.