Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 61 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,24 @@ on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
publish_target:
description: 'Publish target'
required: true
default: 'testpypi'
type: choice
options:
- testpypi
- pypi

permissions:
contents: read

jobs:
# -------------------------------------------------------------------
# Build the package
# -------------------------------------------------------------------
build:
runs-on: ubuntu-latest
steps:
Expand All @@ -24,23 +37,61 @@ jobs:
python-version: "3.12"

- name: Install build tools
run: pip install build
run: pip install build twine

- name: Build sdist and wheel
run: python -m build

- name: Check package with twine
run: twine check dist/*

- name: List build artifacts
run: ls -la dist/

- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/

# -------------------------------------------------------------------
# Publish to TestPyPI (manual trigger or pre-release tags)
# Uses Trusted Publishing (OIDC — no API tokens needed)
# Requires TestPyPI project to be configured for GitHub OIDC:
# https://test.pypi.org/manage/project/botanu/settings/publishing/
# -------------------------------------------------------------------
publish-testpypi:
needs: build
if: |
github.event_name == 'workflow_dispatch' && github.event.inputs.publish_target == 'testpypi'
|| (github.event_name == 'push' && contains(github.ref, '-alpha') || contains(github.ref, '-beta') || contains(github.ref, '-rc'))
runs-on: ubuntu-latest
environment:
name: testpypi
url: https://test.pypi.org/p/botanu
permissions:
id-token: write # required for OIDC trusted publishing
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/

- name: Publish to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
skip-existing: true

# -------------------------------------------------------------------
# Publish to PyPI via Trusted Publishing (OIDC — no API tokens)
# Requires PyPI project to be configured for GitHub OIDC:
# https://docs.pypi.org/trusted-publishers/
# https://pypi.org/manage/project/botanu/settings/publishing/
# -------------------------------------------------------------------
publish-pypi:
needs: build
if: |
github.event_name == 'workflow_dispatch' && github.event.inputs.publish_target == 'pypi'
|| (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '-'))
runs-on: ubuntu-latest
environment:
name: pypi
Expand All @@ -60,7 +111,8 @@ jobs:
# Create GitHub Release with auto-generated notes
# -------------------------------------------------------------------
github-release:
needs: publish-pypi
needs: [build, publish-pypi]
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
contents: write
Expand All @@ -77,4 +129,9 @@ jobs:
- name: Create GitHub Release
env:
GH_TOKEN: ${{ github.token }}
run: gh release create "${{ github.ref_name }}" dist/* --generate-notes
run: |
if [[ "${{ github.ref_name }}" == *"-"* ]]; then
gh release create "${{ github.ref_name }}" dist/* --generate-notes --prerelease
else
gh release create "${{ github.ref_name }}" dist/* --generate-notes
fi
76 changes: 64 additions & 12 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,69 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.1.0] - 2026-02-05

### Added

- Initial open-source release
- `enable()` / `disable()` bootstrap
- `@botanu_use_case` decorator with UUIDv7 run_id
- `emit_outcome()` and `set_business_context()` span helpers
- `RunContextEnricher` span processor
- LLM tracking with OTel GenAI semconv alignment
- Data tracking for database, storage, and messaging
- Resource detection for K8s, AWS, GCP, Azure, serverless
- Auto-instrumentation for 20+ libraries
- Optional extras: `[sdk]`, `[instruments]`, `[genai]`, `[carriers]`, `[all]`

[Unreleased]: https://github.com/botanu-ai/botanu-sdk-python/compare/v0.0.0...HEAD
- Initial open-source release under Apache-2.0 license
- **Core SDK**
- `enable()` / `disable()` bootstrap functions for SDK initialization
- `@botanu_use_case` decorator with UUIDv7 run_id generation
- `@botanu_outcome` decorator for sub-function outcome tracking
- `emit_outcome()` helper for recording business outcomes
- `set_business_context()` for cost attribution dimensions
- `RunContextEnricher` span processor for automatic run_id propagation

- **LLM Tracking** (aligned with OTel GenAI semantic conventions)
- `track_llm_call()` context manager for LLM/model operations
- `track_tool_call()` context manager for tool/function calls
- Token usage tracking (input, output, cached)
- Provider normalization for 15+ LLM providers
- Support for all GenAI operations (chat, embeddings, etc.)

- **Data Tracking**
- `track_db_operation()` for database operations
- `track_storage_operation()` for object storage (S3, GCS, Azure Blob)
- `track_messaging_operation()` for message queues (SQS, Kafka, Pub/Sub)
- System normalization for 30+ database/storage systems

- **Context Propagation**
- W3C Baggage propagation for cross-service run_id correlation
- Lean mode (default) and full mode propagation options
- `RunContext` model with retry tracking and deadline support

- **Resource Detection**
- Kubernetes (pod, namespace, container)
- AWS (EC2, ECS, Lambda, Fargate)
- GCP (GCE, Cloud Run, Cloud Functions)
- Azure (VM, Container Apps, Functions)

- **Auto-Instrumentation Support**
- HTTP clients: requests, httpx, urllib3, aiohttp
- Web frameworks: FastAPI, Flask, Django, Starlette
- Databases: SQLAlchemy, psycopg2, asyncpg, pymongo, Redis
- Messaging: Celery, Kafka
- GenAI: OpenAI, Anthropic, Vertex AI, Google GenAI, LangChain

- **Optional Extras**
- `[sdk]` - OTel SDK + OTLP exporter
- `[instruments]` - Common library instrumentation
- `[genai]` - GenAI provider instrumentation
- `[carriers]` - Cross-service propagation helpers
- `[all]` - Everything included
- `[dev]` - Development and testing tools

- **Documentation**
- Comprehensive docs in `/docs` following LF format
- Getting started guides
- API reference
- Best practices and anti-patterns

### Dependencies

- Core: `opentelemetry-api >= 1.20.0`
- SDK extra: `opentelemetry-sdk`, `opentelemetry-exporter-otlp-proto-http`
- Python: `>= 3.9`

[Unreleased]: https://github.com/botanu-ai/botanu-sdk-python/compare/v0.1.0...HEAD
[0.1.0]: https://github.com/botanu-ai/botanu-sdk-python/releases/tag/v0.1.0
124 changes: 117 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,155 @@

[![CI](https://github.com/botanu-ai/botanu-sdk-python/actions/workflows/ci.yml/badge.svg)](https://github.com/botanu-ai/botanu-sdk-python/actions/workflows/ci.yml)
[![PyPI version](https://badge.fury.io/py/botanu.svg)](https://pypi.org/project/botanu/)
[![Python versions](https://img.shields.io/pypi/pyversions/botanu.svg)](https://pypi.org/project/botanu/)
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/botanu-ai/botanu-sdk-python/badge)](https://scorecard.dev/viewer/?uri=github.com/botanu-ai/botanu-sdk-python)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)

OpenTelemetry-native **run-level cost attribution** for AI workflows.

## Overview

Botanu adds **runs** on top of distributed tracing. A run represents a single business execution that may span multiple traces, retries, and services. By correlating all spans to a stable `run_id`, you get accurate cost attribution without sampling artifacts.
Botanu adds **runs** on top of distributed tracing. A run represents a single business transaction that may span multiple LLM calls, database queries, and services. By correlating all operations to a stable `run_id`, you get accurate cost attribution without sampling artifacts.

**Key features:**
- 🎯 **Run-level attribution** — Link all costs to business outcomes
- 🔗 **Cross-service correlation** — W3C Baggage propagation
- 📊 **OTel-native** — Works with any OpenTelemetry-compatible backend
- ⚡ **Minimal overhead** — < 0.5ms per request
- 🤖 **GenAI support** — OpenAI, Anthropic, Vertex AI, and more

## Quick Start

```python
from botanu import enable, botanu_use_case, emit_outcome

# Initialize at startup
enable(service_name="my-app")

@botanu_use_case(name="Customer Support")
async def handle_ticket(ticket_id: str):
result = await process_ticket(ticket_id)
# All operations inside get the same run_id
context = await fetch_context(ticket_id)
response = await generate_response(context)

# Record the business outcome
emit_outcome("success", value_type="tickets_resolved", value_amount=1)
return result
return response
```

## Installation

```bash
pip install botanu # Core (opentelemetry-api only)
pip install botanu[sdk] # + OTel SDK + OTLP exporter
pip install botanu[all] # Everything including GenAI instrumentation
# Core SDK (opentelemetry-api only, ~50KB)
pip install botanu

# With OTel SDK + OTLP exporter (for standalone use)
pip install "botanu[sdk]"

# With GenAI provider instrumentation
pip install "botanu[genai]"

# Everything included
pip install "botanu[all]"
```

### Extras

| Extra | Description |
|-------|-------------|
| `sdk` | OpenTelemetry SDK + OTLP HTTP exporter |
| `instruments` | Auto-instrumentation for HTTP, databases, etc. |
| `genai` | GenAI provider instrumentation (OpenAI, Anthropic, etc.) |
| `carriers` | Cross-service propagation helpers (Celery, Kafka) |
| `all` | All of the above |
| `dev` | Development and testing tools |

## LLM Tracking

Track LLM calls with full cost attribution:

```python
from botanu.tracking.llm import track_llm_call

with track_llm_call(provider="openai", model="gpt-4") as tracker:
response = await openai.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "Hello"}]
)
tracker.set_tokens(
input_tokens=response.usage.prompt_tokens,
output_tokens=response.usage.completion_tokens,
)
```

## Data Tracking

Track database and storage operations:

```python
from botanu.tracking.data import track_db_operation, track_storage_operation

# Database
with track_db_operation(system="postgresql", operation="SELECT") as db:
result = await cursor.execute(query)
db.set_result(rows_returned=len(result))

# Storage
with track_storage_operation(system="s3", operation="PUT") as storage:
await s3.put_object(Bucket="bucket", Key="key", Body=data)
storage.set_result(bytes_written=len(data))
```

## Architecture

```
┌──────────────────────────────────────────────────────────────┐
│ Your Application │
│ │
│ @botanu_use_case track_llm_call() track_db_operation()│
│ │ │ │ │
│ └───────────────────┴────────────────────┘ │
│ │ │
│ Botanu SDK (thin) │
│ - Generate run_id (UUIDv7) │
│ - Set W3C Baggage │
│ - Record spans │
└─────────────────────────────┬─────────────────────────────────┘
│ OTLP
┌──────────────────────────────────────────────────────────────┐
│ OpenTelemetry Collector │
│ │
│ - PII redaction - Cost calculation │
│ - Vendor normalization - Cardinality management │
└──────────────────────────────────────────────────────────────┘
```

## Documentation

Full documentation is available at [docs.botanu.ai](https://docs.botanu.ai) and in the [`docs/`](./docs/) folder.
Full documentation is available at [docs.botanu.ai](https://docs.botanu.ai) and in the [`docs/`](./docs/) folder:

- [Getting Started](./docs/getting-started/)
- [Concepts](./docs/concepts/)
- [Tracking Guides](./docs/tracking/)
- [Integration](./docs/integration/)
- [API Reference](./docs/api/)

## Requirements

- Python 3.9+
- OpenTelemetry Collector (for production use)

## Contributing

See [CONTRIBUTING.md](./CONTRIBUTING.md). This project uses [DCO](./DCO) sign-off.

```bash
git commit -s -m "Your commit message"
```

## License

[Apache-2.0](./LICENSE) — see [NOTICE](./NOTICE) for attribution.

This project is an [LF AI & Data Foundation](https://lfaidata.foundation/) project.
Loading
Loading