Run-level cost attribution for AI workflows, built on OpenTelemetry.
Botanu adds runs on top of distributed tracing. A run represents one business transaction that may span multiple LLM calls, database queries, and microservices. By correlating every operation to a stable run_id, you get per-transaction cost attribution without sampling artifacts.
User Request
|
v
Entry Service Intermediate Service LLM / DB
@botanu_use_case --> enable() propagates --> auto-instrumented
creates run_id run_id via W3C Baggage spans tagged with run_id
- Entry point creates a
run_idwith@botanu_use_case - Every service calls
enable()to propagate therun_idvia W3C Baggage - All spans across all services share the same
run_id - Traces export to your OTel Collector via OTLP (configured by environment variable)
pip install botanuOne install. Includes OTel SDK, OTLP exporter, and auto-instrumentation for 50+ libraries.
Entry service (where the workflow begins):
from botanu import enable, botanu_use_case
enable() # reads config from env vars
@botanu_use_case(name="Customer Support")
async def handle_ticket(ticket_id: str):
data = await db.query(ticket_id)
result = await llm.complete(data)
return resultEvery other service (intermediate, downstream):
from botanu import enable
enable() # propagates run_id from incoming requestThat's it. No collector endpoint in code. No manual span creation.
All configuration is via environment variables. Zero hardcoded values in code.
| Variable | Description | Default |
|---|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT |
Collector endpoint | http://localhost:4318 |
OTEL_SERVICE_NAME |
Service name | unknown_service |
BOTANU_ENVIRONMENT |
Deployment environment | production |
# docker-compose.yml / Kubernetes deployment
environment:
- OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
- OTEL_SERVICE_NAME=my-serviceSee Configuration Reference for all options.
Everything is included and auto-detected. If the library is in your dependencies, it gets instrumented:
| Category | Libraries |
|---|---|
| LLM Providers | OpenAI, Anthropic, Vertex AI, Google GenAI, LangChain, Ollama, CrewAI |
| Web Frameworks | FastAPI, Flask, Django, Starlette, Falcon, Pyramid, Tornado |
| HTTP Clients | requests, httpx, urllib3, aiohttp |
| Databases | PostgreSQL (psycopg2/3, asyncpg), MySQL, SQLite, MongoDB, Redis, SQLAlchemy, Elasticsearch, Cassandra |
| Messaging | Celery, Kafka, RabbitMQ (pika) |
| AWS | botocore, boto3 (SQS) |
| gRPC | Client + Server |
| Runtime | logging, threading, asyncio |
No manual instrumentation required. Libraries not installed are silently skipped.
For large deployments (2000+ services), only entry points need code changes:
| Service Type | Code Change | Configuration |
|---|---|---|
| Entry point | @botanu_use_case decorator |
OTEL_EXPORTER_OTLP_ENDPOINT env var |
| Intermediate | enable() call only |
OTEL_EXPORTER_OTLP_ENDPOINT env var |
See Kubernetes Deployment Guide for details.
+---------+ +---------+ +---------+
| Service | --> | Service | --> | Service |
| enable()| --> | enable()| --> | enable()|
+---------+ +---------+ +---------+
| | |
v v v
+-------------------------------------+
| OTel Collector (OTLP) |
+-------------------------------------+
| | |
v v v
Jaeger/Tempo Prometheus Your Backend
The SDK is a thin layer on OpenTelemetry:
- SDK: Generates
run_id, propagates context, auto-instruments - Collector: PII redaction, cardinality limits, routing, vendor enrichment
- Getting Started - Installation, quickstart, configuration
- Concepts - Runs, context propagation, cost attribution
- Integration - Auto-instrumentation, Kubernetes, collector setup
- API Reference -
enable(),@botanu_use_case,emit_outcome()
- Python 3.9+
- OpenTelemetry Collector (recommended for production)
We welcome contributions. See CONTRIBUTING.md.
This project follows the Developer Certificate of Origin (DCO). Sign off your commits:
git commit -s -m "Your commit message"This project is an LF AI & Data Foundation project.