Skip to content

Commit 3bee454

Browse files
Merge pull request #17 from botanu-ai/developer-deborah
refactor: remove metrics module and sampling configuration
2 parents 11cbb46 + 7d65915 commit 3bee454

File tree

11 files changed

+133
-92
lines changed

11 files changed

+133
-92
lines changed

.github/workflows/publish.yml

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# SPDX-FileCopyrightText: 2026 The Botanu Authors
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
name: Publish to PyPI
5+
6+
on:
7+
release:
8+
types: [published]
9+
workflow_dispatch:
10+
inputs:
11+
target:
12+
description: 'Target repository'
13+
required: true
14+
default: 'testpypi'
15+
type: choice
16+
options:
17+
- testpypi
18+
- pypi
19+
20+
permissions:
21+
contents: read
22+
23+
jobs:
24+
build:
25+
runs-on: ubuntu-latest
26+
steps:
27+
- uses: actions/checkout@v4
28+
with:
29+
fetch-depth: 0
30+
31+
- uses: actions/setup-python@v5
32+
with:
33+
python-version: "3.12"
34+
35+
- name: Install build dependencies
36+
run: pip install build
37+
38+
- name: Build package
39+
run: python -m build
40+
41+
- name: Upload artifacts
42+
uses: actions/upload-artifact@v4
43+
with:
44+
name: dist
45+
path: dist/
46+
47+
publish-testpypi:
48+
needs: build
49+
runs-on: ubuntu-latest
50+
if: github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'testpypi'
51+
environment: testpypi
52+
permissions:
53+
id-token: write
54+
steps:
55+
- name: Download artifacts
56+
uses: actions/download-artifact@v4
57+
with:
58+
name: dist
59+
path: dist/
60+
61+
- name: Publish to TestPyPI
62+
uses: pypa/gh-action-pypi-publish@release/v1
63+
with:
64+
repository-url: https://test.pypi.org/legacy/
65+
66+
publish-pypi:
67+
needs: build
68+
runs-on: ubuntu-latest
69+
if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'pypi')
70+
environment: pypi
71+
permissions:
72+
id-token: write
73+
steps:
74+
- name: Download artifacts
75+
uses: actions/download-artifact@v4
76+
with:
77+
name: dist
78+
path: dist/
79+
80+
- name: Publish to PyPI
81+
uses: pypa/gh-action-pypi-publish@release/v1

GOVERNANCE.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Governance
2+
3+
This project follows the governance model of the [LF AI & Data Foundation](https://lfaidata.foundation/).
4+
5+
## Roles
6+
7+
### Maintainers
8+
9+
Maintainers are responsible for:
10+
- Reviewing and merging pull requests
11+
- Triaging issues
12+
- Releasing new versions
13+
- Ensuring project quality and direction
14+
15+
Current maintainers are listed in [MAINTAINERS.md](./MAINTAINERS.md).
16+
17+
### Contributors
18+
19+
Anyone can contribute by:
20+
- Opening issues
21+
- Submitting pull requests
22+
- Participating in discussions
23+
- Improving documentation
24+
25+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for contribution guidelines.
26+
27+
## Decision Making
28+
29+
- Technical decisions are made through pull request reviews
30+
- Significant changes require approval from at least one maintainer
31+
- Disputes are resolved by maintainer consensus
32+
33+
## Code of Conduct
34+
35+
All participants must follow the [Code of Conduct](./CODE_OF_CONDUCT.md).
36+
37+
## License
38+
39+
This project is licensed under Apache-2.0. See [LICENSE](./LICENSE).

docs/api/configuration.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ from botanu.sdk.config import BotanuConfig
2222
| `max_export_batch_size` | `int` | `512` | Max spans per batch |
2323
| `max_queue_size` | `int` | `2048` | Max spans in queue |
2424
| `schedule_delay_millis` | `int` | `5000` | Delay between batch exports |
25-
| `trace_sample_rate` | `float` | `1.0` | Sampling rate (1.0 = 100%) |
2625
| `propagation_mode` | `str` | `"lean"` | `"lean"` or `"full"` |
2726
| `auto_instrument_packages` | `list` | `[...]` | Packages to auto-instrument |
2827

@@ -137,9 +136,6 @@ export:
137136
queue_size: integer # Max spans in queue
138137
delay_ms: integer # Delay between exports
139138

140-
sampling:
141-
rate: float # Sampling rate (0.0-1.0)
142-
143139
propagation:
144140
mode: string # "lean" or "full"
145141

@@ -294,7 +290,6 @@ if not is_enabled():
294290
|----------|-------------|---------|
295291
| `BOTANU_ENVIRONMENT` | Fallback for environment | `"production"` |
296292
| `BOTANU_PROPAGATION_MODE` | `"lean"` or `"full"` | `"lean"` |
297-
| `BOTANU_TRACE_SAMPLE_RATE` | Sampling rate (0.0-1.0) | `"1.0"` |
298293
| `BOTANU_AUTO_DETECT_RESOURCES` | Auto-detect cloud resources | `"true"` |
299294
| `BOTANU_CONFIG_FILE` | Path to YAML config file | None |
300295

docs/getting-started/configuration.md

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,6 @@ class BotanuConfig:
8181
max_queue_size: int = 2048
8282
schedule_delay_millis: int = 5000
8383

84-
# Sampling (1.0 = 100%)
85-
trace_sample_rate: float = 1.0 # BOTANU_TRACE_SAMPLE_RATE
86-
8784
# Propagation mode
8885
propagation_mode: str = "lean" # BOTANU_PROPAGATION_MODE
8986

@@ -110,7 +107,6 @@ class BotanuConfig:
110107
|----------|-------------|---------|
111108
| `BOTANU_ENVIRONMENT` | Fallback for environment | `production` |
112109
| `BOTANU_PROPAGATION_MODE` | `lean` or `full` | `lean` |
113-
| `BOTANU_TRACE_SAMPLE_RATE` | Sampling rate (0.0-1.0) | `1.0` |
114110
| `BOTANU_AUTO_DETECT_RESOURCES` | Auto-detect cloud resources | `true` |
115111
| `BOTANU_CONFIG_FILE` | Path to YAML config | None |
116112

@@ -139,9 +135,6 @@ export:
139135
queue_size: 2048
140136
delay_ms: 5000
141137

142-
sampling:
143-
rate: 1.0
144-
145138
propagation:
146139
mode: lean
147140

@@ -259,16 +252,6 @@ enable(
259252
)
260253
```
261254

262-
## Sampling
263-
264-
For cost attribution, **always use 100% sampling** (the default):
265-
266-
```python
267-
trace_sample_rate: float = 1.0 # Never miss a transaction
268-
```
269-
270-
If you must sample, understand that cost calculations will be incomplete.
271-
272255
## Exporting Configuration
273256

274257
```python

docs/patterns/anti-patterns.md

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -238,26 +238,6 @@ track_llm_call(provider="azure_openai", ...)
238238

239239
### Sampling for Cost Attribution
240240

241-
**Don't** sample spans:
242-
243-
```python
244-
# BAD - Missing cost data
245-
enable(
246-
service_name="my-service",
247-
trace_sample_rate=0.1, # Only 10% of costs captured!
248-
)
249-
```
250-
251-
**Do** use 100% sampling:
252-
253-
```python
254-
# GOOD - Complete cost data
255-
enable(
256-
service_name="my-service",
257-
trace_sample_rate=1.0, # Default - don't change
258-
)
259-
```
260-
261241
### Hardcoding Configuration
262242

263243
**Don't** hardcode production values:

docs/patterns/best-practices.md

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -276,18 +276,6 @@ export OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4318
276276
export BOTANU_ENVIRONMENT=production
277277
```
278278

279-
### Never Sample for Cost Attribution
280-
281-
Always use 100% sampling for accurate cost data:
282-
283-
```python
284-
# GOOD
285-
trace_sample_rate: float = 1.0
286-
287-
# BAD - Missing cost data
288-
trace_sample_rate: float = 0.1 # Only 10% of costs captured
289-
```
290-
291279
### Use YAML for Complex Configuration
292280

293281
For multi-environment setups:

src/botanu/sdk/config.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,6 @@ class BotanuConfig:
6464
max_queue_size: int = 2048
6565
schedule_delay_millis: int = 5000
6666

67-
# Sampling (1.0 = 100% — never sample for cost attribution)
68-
trace_sample_rate: float = 1.0
69-
7067
# Propagation mode: "lean" (run_id + use_case only) or "full" (all context)
7168
propagation_mode: str = "lean"
7269

@@ -141,10 +138,6 @@ def __post_init__(self) -> None:
141138
if env_propagation_mode and env_propagation_mode in ("lean", "full"):
142139
self.propagation_mode = env_propagation_mode
143140

144-
env_sample_rate = os.getenv("BOTANU_TRACE_SAMPLE_RATE")
145-
if env_sample_rate:
146-
self.trace_sample_rate = float(env_sample_rate)
147-
148141
# ------------------------------------------------------------------
149142
# YAML loading
150143
# ------------------------------------------------------------------
@@ -236,7 +229,6 @@ def _from_dict(
236229
service = data.get("service", {})
237230
otlp = data.get("otlp", {})
238231
export = data.get("export", {})
239-
sampling = data.get("sampling", {})
240232
propagation = data.get("propagation", {})
241233
resource = data.get("resource", {})
242234
auto_packages = data.get("auto_instrument_packages")
@@ -252,7 +244,6 @@ def _from_dict(
252244
max_export_batch_size=export.get("batch_size", 512),
253245
max_queue_size=export.get("queue_size", 2048),
254246
schedule_delay_millis=export.get("delay_ms", 5000),
255-
trace_sample_rate=sampling.get("rate", 1.0),
256247
propagation_mode=propagation.get("mode", "lean"),
257248
auto_instrument_packages=(auto_packages if auto_packages else BotanuConfig().auto_instrument_packages),
258249
_config_file=config_file,
@@ -279,9 +270,6 @@ def to_dict(self) -> Dict[str, Any]:
279270
"queue_size": self.max_queue_size,
280271
"delay_ms": self.schedule_delay_millis,
281272
},
282-
"sampling": {
283-
"rate": self.trace_sample_rate,
284-
},
285273
"propagation": {
286274
"mode": self.propagation_mode,
287275
},

src/botanu/sdk/decorators.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424

2525
from botanu.models.run_context import RunContext, RunStatus
2626
from botanu.sdk.context import get_baggage, set_baggage
27-
from botanu.tracking.metrics import record_run_completed
2827

2928
T = TypeVar("T")
3029

@@ -120,7 +119,7 @@ async def async_wrapper(*args: Any, **kwargs: Any) -> T:
120119
result = await func(*args, **kwargs)
121120

122121
span_attrs = getattr(span, "attributes", None)
123-
existing_outcome = span_attrs.get("botanu.outcome.status") if span_attrs else None
122+
existing_outcome = span_attrs.get("botanu.outcome.status") if isinstance(span_attrs, dict) else None
124123

125124
if existing_outcome is None and auto_outcome_on_success:
126125
run_ctx.complete(RunStatus.SUCCESS)
@@ -176,7 +175,7 @@ def sync_wrapper(*args: Any, **kwargs: Any) -> T:
176175
result = func(*args, **kwargs)
177176

178177
span_attrs = getattr(span, "attributes", None)
179-
existing_outcome = span_attrs.get("botanu.outcome.status") if span_attrs else None
178+
existing_outcome = span_attrs.get("botanu.outcome.status") if isinstance(span_attrs, dict) else None
180179

181180
if existing_outcome is None and auto_outcome_on_success:
182181
run_ctx.complete(RunStatus.SUCCESS)
@@ -230,14 +229,6 @@ def _emit_run_completed(
230229
span.set_attribute("botanu.outcome.status", status.value)
231230
span.set_attribute("botanu.run.duration_ms", duration_ms)
232231

233-
record_run_completed(
234-
use_case=run_ctx.use_case,
235-
status=status.value,
236-
environment=run_ctx.environment,
237-
duration_ms=duration_ms,
238-
workflow=run_ctx.workflow,
239-
)
240-
241232

242233
# Alias
243234
use_case = botanu_use_case

src/botanu/tracking/__init__.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
- LLM/GenAI model calls
88
- Database, storage, and messaging operations
99
- Attempt ledger for durable cost tracking
10-
- Run completion metrics
1110
"""
1211

1312
from __future__ import annotations
@@ -44,7 +43,6 @@
4443
track_llm_call,
4544
track_tool_call,
4645
)
47-
from botanu.tracking.metrics import record_run_completed
4846

4947
__all__ = [
5048
# LLM tracking
@@ -76,6 +74,4 @@
7674
"record_tool_attempted",
7775
"LedgerEventType",
7876
"AttemptStatus",
79-
# Metrics
80-
"record_run_completed",
8177
]

src/botanu/tracking/ledger.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import time
2323
from dataclasses import dataclass, field
2424
from enum import Enum
25+
from functools import lru_cache
2526
from typing import Any, Dict, Optional
2627

2728
from opentelemetry import trace
@@ -384,12 +385,17 @@ def shutdown(self) -> None:
384385
_global_ledger: Optional[AttemptLedger] = None
385386

386387

388+
@lru_cache(maxsize=1)
389+
def _create_default_ledger() -> AttemptLedger:
390+
"""Create default ledger instance (thread-safe via lru_cache)."""
391+
return AttemptLedger()
392+
393+
387394
def get_ledger() -> AttemptLedger:
388-
"""Get the global attempt ledger instance."""
389-
global _global_ledger
390-
if _global_ledger is None:
391-
_global_ledger = AttemptLedger()
392-
return _global_ledger
395+
"""Get the global attempt ledger instance (thread-safe)."""
396+
if _global_ledger is not None:
397+
return _global_ledger
398+
return _create_default_ledger()
393399

394400

395401
def set_ledger(ledger: AttemptLedger) -> None:

0 commit comments

Comments
 (0)