Skip to content

Commit a338422

Browse files
Merge pull request #25 from botanu-ai/developer
Developer
2 parents a07f811 + aec5b96 commit a338422

36 files changed

Lines changed: 2752 additions & 882 deletions

.github/workflows/ci.yml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ jobs:
1919
lint:
2020
runs-on: ubuntu-latest
2121
steps:
22-
- uses: actions/checkout@v4
23-
- uses: actions/setup-python@v5
22+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
23+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
2424
with:
2525
python-version: "3.12"
2626
- run: pip install ruff
@@ -33,8 +33,8 @@ jobs:
3333
typecheck:
3434
runs-on: ubuntu-latest
3535
steps:
36-
- uses: actions/checkout@v4
37-
- uses: actions/setup-python@v5
36+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
37+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
3838
with:
3939
python-version: "3.12"
4040
- run: pip install -e ".[dev]"
@@ -50,11 +50,11 @@ jobs:
5050
matrix:
5151
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
5252
steps:
53-
- uses: actions/checkout@v4
53+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
5454
with:
5555
fetch-depth: 0 # hatch-vcs needs full history
5656

57-
- uses: actions/setup-python@v5
57+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
5858
with:
5959
python-version: ${{ matrix.python-version }}
6060

@@ -66,7 +66,7 @@ jobs:
6666

6767
- name: Upload coverage
6868
if: matrix.python-version == '3.12'
69-
uses: codecov/codecov-action@v4
69+
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
7070
with:
7171
file: coverage.xml
7272
fail_ci_if_error: false
@@ -77,15 +77,15 @@ jobs:
7777
build:
7878
runs-on: ubuntu-latest
7979
steps:
80-
- uses: actions/checkout@v4
80+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
8181
with:
8282
fetch-depth: 0
83-
- uses: actions/setup-python@v5
83+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
8484
with:
8585
python-version: "3.12"
8686
- run: pip install build
8787
- run: python -m build
88-
- uses: actions/upload-artifact@v4
88+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
8989
with:
9090
name: dist
9191
path: dist/
@@ -97,10 +97,10 @@ jobs:
9797
runs-on: ubuntu-latest
9898
if: github.event_name == 'pull_request'
9999
steps:
100-
- uses: actions/checkout@v4
100+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
101101
with:
102102
fetch-depth: 0
103103
- name: DCO check
104-
uses: christophebedard/dco-check@0.5.0
104+
uses: christophebedard/dco-check@7b0205d25ead0f898e0b706b58227dd5fa7e3f55 # 0.5.0
105105
env:
106106
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/codeql.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,17 @@ jobs:
2424
matrix:
2525
language: [python]
2626
steps:
27-
- uses: actions/checkout@v4
27+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
2828

2929
- name: Initialize CodeQL
30-
uses: github/codeql-action/init@v3
30+
uses: github/codeql-action/init@ebcb5b36ded6beda4ceefea6a8bc4cc885255bb3 # v3
3131
with:
3232
languages: ${{ matrix.language }}
3333

3434
- name: Autobuild
35-
uses: github/codeql-action/autobuild@v3
35+
uses: github/codeql-action/autobuild@ebcb5b36ded6beda4ceefea6a8bc4cc885255bb3 # v3
3636

3737
- name: Perform CodeQL Analysis
38-
uses: github/codeql-action/analyze@v3
38+
uses: github/codeql-action/analyze@ebcb5b36ded6beda4ceefea6a8bc4cc885255bb3 # v3
3939
with:
4040
category: "/language:${{ matrix.language }}"

.github/workflows/release.yml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ jobs:
2828
build:
2929
runs-on: ubuntu-latest
3030
steps:
31-
- uses: actions/checkout@v4
31+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
3232
with:
3333
fetch-depth: 0 # hatch-vcs needs full history
3434

35-
- uses: actions/setup-python@v5
35+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
3636
with:
3737
python-version: "3.12"
3838

@@ -48,7 +48,7 @@ jobs:
4848
- name: List build artifacts
4949
run: ls -la dist/
5050

51-
- uses: actions/upload-artifact@v4
51+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
5252
with:
5353
name: dist
5454
path: dist/
@@ -71,13 +71,13 @@ jobs:
7171
permissions:
7272
id-token: write # required for OIDC trusted publishing
7373
steps:
74-
- uses: actions/download-artifact@v4
74+
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
7575
with:
7676
name: dist
7777
path: dist/
7878

7979
- name: Publish to TestPyPI
80-
uses: pypa/gh-action-pypi-publish@release/v1
80+
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1
8181
with:
8282
repository-url: https://test.pypi.org/legacy/
8383
skip-existing: true
@@ -99,13 +99,13 @@ jobs:
9999
permissions:
100100
id-token: write # required for OIDC trusted publishing
101101
steps:
102-
- uses: actions/download-artifact@v4
102+
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
103103
with:
104104
name: dist
105105
path: dist/
106106

107107
- name: Publish to PyPI
108-
uses: pypa/gh-action-pypi-publish@release/v1
108+
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1
109109

110110
# -------------------------------------------------------------------
111111
# Create GitHub Release with auto-generated notes
@@ -117,11 +117,11 @@ jobs:
117117
permissions:
118118
contents: write
119119
steps:
120-
- uses: actions/checkout@v4
120+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
121121
with:
122122
fetch-depth: 0
123123

124-
- uses: actions/download-artifact@v4
124+
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
125125
with:
126126
name: dist
127127
path: dist/

.github/workflows/repolinter.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ jobs:
1616
lint:
1717
runs-on: ubuntu-latest
1818
steps:
19-
- uses: actions/checkout@v4
19+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
2020

2121
- name: Run Repolinter
22-
uses: todogroup/repolinter-action@v1
22+
uses: todogroup/repolinter-action@4d478dcd860571382da7d512d6dc6dd5f554fbb2 # v1
2323
with:
2424
config_file: .github/repolinter.json

.github/workflows/scorecard.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,18 @@ jobs:
1818
security-events: write # upload SARIF
1919
id-token: write # publish results
2020
steps:
21-
- uses: actions/checkout@v4
21+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
2222
with:
2323
persist-credentials: false
2424

2525
- name: Run OpenSSF Scorecard
26-
uses: ossf/scorecard-action@v2
26+
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
2727
with:
2828
results_file: results.sarif
2929
results_format: sarif
3030
publish_results: true
3131

3232
- name: Upload SARIF to GitHub Security tab
33-
uses: github/codeql-action/upload-sarif@v3
33+
uses: github/codeql-action/upload-sarif@ebcb5b36ded6beda4ceefea6a8bc4cc885255bb3 # v3
3434
with:
3535
sarif_file: results.sarif

CHANGELOG.md

Lines changed: 56 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -7,69 +7,61 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
## [0.1.0] - 2026-02-05
11-
1210
### Added
1311

14-
- Initial open-source release under Apache-2.0 license
15-
- **Core SDK**
16-
- `enable()` / `disable()` bootstrap functions for SDK initialization
17-
- `@botanu_workflow` decorator with UUIDv7 run_id generation
18-
- `@botanu_outcome` decorator for sub-function outcome tracking
19-
- `emit_outcome()` helper for recording business outcomes
20-
- `set_business_context()` for cost attribution dimensions
21-
- `RunContextEnricher` span processor for automatic run_id propagation
22-
23-
- **LLM Tracking** (aligned with OTel GenAI semantic conventions)
24-
- `track_llm_call()` context manager for LLM/model operations
25-
- `track_tool_call()` context manager for tool/function calls
26-
- Token usage tracking (input, output, cached)
27-
- Provider normalization for 15+ LLM providers
28-
- Support for all GenAI operations (chat, embeddings, etc.)
29-
30-
- **Data Tracking**
31-
- `track_db_operation()` for database operations
32-
- `track_storage_operation()` for object storage (S3, GCS, Azure Blob)
33-
- `track_messaging_operation()` for message queues (SQS, Kafka, Pub/Sub)
34-
- System normalization for 30+ database/storage systems
35-
36-
- **Context Propagation**
37-
- W3C Baggage propagation for cross-service run_id correlation
38-
- Lean mode (default) and full mode propagation options
39-
- `RunContext` model with retry tracking and deadline support
40-
41-
- **Resource Detection**
42-
- Kubernetes (pod, namespace, container)
43-
- AWS (EC2, ECS, Lambda, Fargate)
44-
- GCP (GCE, Cloud Run, Cloud Functions)
45-
- Azure (VM, Container Apps, Functions)
46-
47-
- **Auto-Instrumentation Support**
48-
- HTTP clients: requests, httpx, urllib3, aiohttp
49-
- Web frameworks: FastAPI, Flask, Django, Starlette
50-
- Databases: SQLAlchemy, psycopg2, asyncpg, pymongo, Redis
51-
- Messaging: Celery, Kafka
52-
- GenAI: OpenAI, Anthropic, Vertex AI, Google GenAI, LangChain
53-
54-
- **Optional Extras**
55-
- `[sdk]` - OTel SDK + OTLP exporter
56-
- `[instruments]` - Common library instrumentation
57-
- `[genai]` - GenAI provider instrumentation
58-
- `[carriers]` - Cross-service propagation helpers
59-
- `[all]` - Everything included
60-
- `[dev]` - Development and testing tools
61-
62-
- **Documentation**
63-
- Comprehensive docs in `/docs` following LF format
64-
- Getting started guides
65-
- API reference
66-
- Best practices and anti-patterns
67-
68-
### Dependencies
69-
70-
- Core: `opentelemetry-api >= 1.20.0`
71-
- SDK extra: `opentelemetry-sdk`, `opentelemetry-exporter-otlp-proto-http`
72-
- Python: `>= 3.9`
73-
74-
[Unreleased]: https://github.com/botanu-ai/botanu-sdk-python/compare/v0.1.0...HEAD
75-
[0.1.0]: https://github.com/botanu-ai/botanu-sdk-python/releases/tag/v0.1.0
12+
- **Security**
13+
- OTLP bearer token is attached only when the endpoint host is botanu-owned
14+
(`*.botanu.ai`) or a local dev host, preventing tenant API-key leakage
15+
via a customer-supplied `OTEL_EXPORTER_OTLP_ENDPOINT`.
16+
- Authorization / `x-api-key` / `botanu-api-key` headers and `user:pass@`
17+
URL credentials are redacted in logs.
18+
- **Brownfield OTel coexistence**
19+
- `SampledSpanProcessor` preserves the host app's existing TracerProvider
20+
sampling ratio when botanu is bootstrapped into a project that already
21+
has OTel wired up.
22+
- `register.py` entry point for explicit opt-in without decorator-side
23+
provider mutation.
24+
- Bootstrap detects a pre-configured provider and hands off instead of
25+
overriding it.
26+
- **Content capture for eval**
27+
- Workflow-level input/output capture gated by `content_capture_rate`
28+
config and a shared `content_sampler`. Writes
29+
`botanu.eval.input_content` / `botanu.eval.output_content`.
30+
- `set_input_content()` / `set_output_content()` on `LLMTracker` with the
31+
same gate, plus matching helpers on data-tracking helpers.
32+
- **Multi-step workflows**
33+
- `@botanu_workflow(..., step=...)` parameter (stored in `RunContext`,
34+
not yet emitted to span attributes — kept backward compatible until the
35+
collector servicegraph work lands).
36+
- **Resources**
37+
- `ResourceEnricher` span processor for deployment attributes.
38+
- **Release tooling**
39+
- `scripts/pre_publish_check.py` red/green gate: builds sdist + wheel,
40+
runs `twine check`, installs into a fresh venv, validates the public
41+
API surface, runs an end-to-end decorator + `emit_outcome` smoke test.
42+
43+
### Fixed
44+
45+
- `SampledSpanProcessor.on_start` now gates on the same ratio decision as
46+
`on_end`; forwarding `on_start` unconditionally while gating `on_end`
47+
leaked span bookkeeping inside wrapped exporters (QUAL-C1).
48+
49+
### Initial release contents
50+
51+
Carried forward from the pre-tag scaffolding (never published):
52+
53+
- `enable()` / `disable()` bootstrap, `@botanu_workflow`,
54+
`@botanu_outcome`, `emit_outcome()`, `set_business_context()`,
55+
`RunContextEnricher` — with UUIDv7 run_ids.
56+
- LLM tracking aligned with OTel GenAI semconv: `track_llm_call()`,
57+
`track_tool_call()`, token accounting, 15+ provider normalization.
58+
- Data tracking: `track_db_operation()`, `track_storage_operation()`,
59+
`track_messaging_operation()`; 30+ system normalizations.
60+
- W3C Baggage propagation with `RunContext` (retry tracking + deadline).
61+
- Cloud resource detectors via optional extras (`aws`, `gcp`, `azure`,
62+
`container`, `cloud`).
63+
- Auto-instrumentation bundled in the base install — HTTP clients, web
64+
frameworks, databases, messaging, and GenAI providers; instrumentation
65+
packages no-op when their target library is not installed.
66+
67+
[Unreleased]: https://github.com/botanu-ai/botanu-sdk-python/commits/main

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ This SDK is built on [OpenTelemetry](https://opentelemetry.io/) for event-level
88

99
## Getting Started
1010

11+
12+
1113
An **event** is one business transaction — resolving a support ticket, processing
1214
an order, generating a report. Each event may involve multiple **runs** (LLM calls,
1315
retries, sub-workflows) across multiple services. By correlating every run to a

docs/getting-started/installation.md

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
## Requirements
44

55
- Python 3.9 or later
6-
- OpenTelemetry Collector (recommended for production)
76

87
## Install
98

@@ -18,6 +17,16 @@ One install gives you everything:
1817

1918
Instrumentation packages are lightweight shims that silently no-op when the target library is not installed. Zero bloat.
2019

20+
## Configure
21+
22+
Set your API key as an environment variable. The SDK auto-configures the OTLP endpoint to `ingest.botanu.ai` — no other configuration needed.
23+
24+
```bash
25+
export BOTANU_API_KEY="btnu_live_..."
26+
```
27+
28+
That's it. No collector to run, no infrastructure to deploy. Botanu hosts everything.
29+
2130
## Verify
2231

2332
```python
@@ -47,6 +56,7 @@ FROM python:3.12-slim
4756
WORKDIR /app
4857
RUN pip install botanu
4958
COPY . .
59+
ENV BOTANU_API_KEY="btnu_live_..."
5060
CMD ["python", "app.py"]
5161
```
5262

@@ -58,22 +68,6 @@ For running tests and linting:
5868
pip install "botanu[dev]"
5969
```
6070

61-
## Collector Setup
62-
63-
The SDK sends traces to an OpenTelemetry Collector via OTLP HTTP (port 4318). Configure the endpoint via environment variable:
64-
65-
```bash
66-
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
67-
```
68-
69-
Quick start with Docker:
70-
71-
```bash
72-
docker run -p 4318:4318 otel/opentelemetry-collector:latest
73-
```
74-
75-
See [Collector Configuration](../integration/collector.md) for production setup.
76-
7771
## Next Steps
7872

7973
- [Quickstart](quickstart.md) - Your first instrumented application

0 commit comments

Comments
 (0)