Metadata-Version: 2.4
Name: openadapt-telemetry
Version: 0.3.0
Summary: Unified telemetry and error tracking for OpenAdapt packages
Project-URL: Homepage, https://github.com/OpenAdaptAI/openadapt-telemetry
Project-URL: Repository, https://github.com/OpenAdaptAI/openadapt-telemetry
Project-URL: Documentation, https://github.com/OpenAdaptAI/openadapt-telemetry#readme
Project-URL: Issues, https://github.com/OpenAdaptAI/openadapt-telemetry/issues
Project-URL: Changelog, https://github.com/OpenAdaptAI/openadapt-telemetry/releases
Author-email: Richard Abrich <richard@openadapt.ai>
Maintainer-email: OpenAdaptAI <info@openadapt.ai>
License-Expression: MIT
License-File: LICENSE
Keywords: error-tracking,glitchtip,observability,openadapt,privacy,sentry,telemetry
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.10
Requires-Dist: sentry-sdk>=2.0.0
Provides-Extra: all
Requires-Dist: pytest-cov>=4.0.0; extra == 'all'
Requires-Dist: pytest>=8.0.0; extra == 'all'
Requires-Dist: ruff>=0.1.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Description-Content-Type: text/markdown

# openadapt-telemetry

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/downloads/)

<!-- PyPI badges (uncomment once package is published)
[![PyPI version](https://img.shields.io/pypi/v/openadapt-telemetry.svg)](https://pypi.org/project/openadapt-telemetry/)
[![Downloads](https://img.shields.io/pypi/dm/openadapt-telemetry.svg)](https://pypi.org/project/openadapt-telemetry/)
-->

Unified telemetry and error tracking for OpenAdapt packages.

## Features

- **Unified Error Tracking**: Consistent error reporting across all OpenAdapt packages
- **Usage Counters (PostHog)**: Lightweight product usage events for adoption metrics
- **Privacy-First Design**: Automatic PII scrubbing and path sanitization
- **Configurable Opt-Out**: Respects `DO_NOT_TRACK` and custom environment variables
- **Internal Usage Tagging**: Explicit flags + CI detection with optional git heuristic
- **GlitchTip/Sentry Compatible**: Uses the Sentry SDK for maximum compatibility

## Installation

```bash
pip install openadapt-telemetry
```

Or with development dependencies:

```bash
pip install openadapt-telemetry[dev]
```

## Quick Start

### Initialize Telemetry

```python
from openadapt_telemetry import get_telemetry

# Initialize once at package startup
get_telemetry().initialize(
    dsn="https://xxx@app.glitchtip.com/XXXX",
    package_name="openadapt-mypackage",
    package_version="0.1.0",
)
```

### Capture Exceptions

```python
from openadapt_telemetry import get_telemetry

try:
    risky_operation()
except Exception as e:
    get_telemetry().capture_exception(e)
    raise
```

### Capture Usage Events (PostHog)

```python
from openadapt_telemetry import capture_usage_event

capture_usage_event(
    "agent_run",
    properties={"entrypoint": "oa evals run", "mode": "live"},
    package_name="openadapt-evals",
)
```

### Using Decorators

```python
from openadapt_telemetry import track_errors, track_performance, track_feature

@track_errors()
def process_data(data):
    """Exceptions are automatically captured."""
    return transform(data)

@track_performance("indexing.build_faiss")
def build_index(vectors):
    """Execution time is automatically tracked."""
    return create_index(vectors)

@track_feature("retrieval.add_demo")
def add_demo(demo_id, task):
    """Feature usage is tracked for analytics."""
    save_demo(demo_id, task)
```

### Span Context Manager

```python
from openadapt_telemetry import TelemetrySpan

with TelemetrySpan("indexing", "build_faiss_index") as span:
    span.set_tag("num_vectors", 1000)
    # ... indexing operations ...
```

## Configuration

### Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `DO_NOT_TRACK` | - | Universal opt-out (1 = disabled) |
| `OPENADAPT_TELEMETRY_ENABLED` | `true` | Enable/disable telemetry |
| `OPENADAPT_INTERNAL` | `false` | Tag as internal usage |
| `OPENADAPT_DEV` | `false` | Development mode |
| `OPENADAPT_INTERNAL_FROM_GIT` | `false` | Optional: tag as internal when running from a git checkout |
| `OPENADAPT_TELEMETRY_DSN` | - | GlitchTip/Sentry DSN |
| `OPENADAPT_POSTHOG_PROJECT_API_KEY` | embedded default | PostHog ingestion project token (`phc_...`) |
| `OPENADAPT_POSTHOG_HOST` | `https://us.i.posthog.com` | PostHog ingestion host |
| `OPENADAPT_TELEMETRY_DISTINCT_ID` | generated UUID | Stable anonymous identifier override |
| `OPENADAPT_TELEMETRY_TIMEOUT_SECONDS` | `1.0` | PostHog network timeout |
| `OPENADAPT_TELEMETRY_IN_CI` | `false` | Enable usage events in CI pipelines |
| `OPENADAPT_TELEMETRY_ENVIRONMENT` | `production` | Environment name |
| `OPENADAPT_TELEMETRY_SAMPLE_RATE` | `1.0` | Error sampling rate (0.0-1.0) |
| `OPENADAPT_TELEMETRY_TRACES_SAMPLE_RATE` | `0.01` | Performance sampling rate |
| `OPENADAPT_TELEMETRY_ANON_SALT` | generated | Optional anonymization salt override (advanced use only) |

### Configuration File

Create `~/.config/openadapt/telemetry.json`:

```json
{
  "enabled": true,
  "internal": false,
  "dsn": "https://xxx@app.glitchtip.com/XXXX",
  "environment": "production",
  "sample_rate": 1.0,
  "traces_sample_rate": 0.01
}
```

### Priority Order

1. Environment variables (highest priority)
2. Configuration file
3. Package defaults (lowest priority)

## Opt-Out

To disable telemetry, set either:

```bash
# Universal standard
export DO_NOT_TRACK=1

# Or package-specific
export OPENADAPT_TELEMETRY_ENABLED=false
```

## Privacy

### What We Collect

| Category | Data | Purpose |
|----------|------|---------|
| Errors | Exception type, stack trace | Bug fixing |
| Performance | Function timing | Optimization |
| Feature Usage | Feature names, counts | Prioritization |
| Environment | OS, Python version | Compatibility |

### What We Never Collect

- Screenshots or images
- Text content or file contents
- Personal information (names, emails, IPs)
- API keys or passwords
- Full file paths with usernames

### Automatic Scrubbing

- File paths have usernames replaced with `<user>`
- Sensitive fields (password, token, api_key, etc.) are redacted
- Email addresses and phone numbers are scrubbed from messages
- Top-level event messages/logentry strings are scrubbed
- Tag keys are validated, sensitive/invalid keys are dropped, and values are scrubbed before upload
- User IDs are HMAC-anonymized before upload (`anon:v2:<hash>`)
- `send_default_pii` is enforced to `false` by the client

## Internal Usage Tagging

Internal/developer usage is automatically detected via:

1. `OPENADAPT_INTERNAL=true` environment variable
2. `OPENADAPT_DEV=true` environment variable
3. CI environment detected (GitHub Actions, GitLab CI, etc.)
4. Optional git repository heuristic when `OPENADAPT_INTERNAL_FROM_GIT=true`

Filter in GlitchTip:
```
tag:internal IS false  # External users only
tag:internal IS true   # Internal users only
```

## Development

```bash
# Clone and install
git clone https://github.com/OpenAdaptAI/openadapt-telemetry
cd openadapt-telemetry
pip install -e ".[dev]"

# Run tests
pytest tests/ -v

# Run with coverage
pytest tests/ --cov=openadapt_telemetry
```

## License

MIT License - see [LICENSE](LICENSE) for details.

## Links

- [Documentation](https://github.com/OpenAdaptAI/openadapt-telemetry#readme)
- [Issues](https://github.com/OpenAdaptAI/openadapt-telemetry/issues)
- [GlitchTip](https://glitchtip.com)
- [Sentry SDK](https://docs.sentry.io/platforms/python/)
